Compare commits

..

73 Commits

Author SHA1 Message Date
Kovid Goyal
6a3529b7c2 version 0.30.1 2023-10-05 16:38:03 +05:30
Kovid Goyal
a2671c9101 Update changelog 2023-10-05 10:49:13 +05:30
Kovid Goyal
9e514df604 More linter fixes 2023-10-05 10:07:25 +05:30
Kovid Goyal
8865d3231a Fix themes that dont define a background color incorrectly being classified as light
The default bg in kitty is dark
2023-10-05 09:36:59 +05:30
Kovid Goyal
5fb661d72d ... 2023-10-05 09:34:21 +05:30
Kovid Goyal
fd12c5a1e0 Dont assume /dev/stderr exists
Fixes #6671
2023-10-04 06:26:56 +05:30
Kovid Goyal
5008b89804 Merge branch 'arm-alias' of https://github.com/glensc/kitty 2023-10-03 21:21:57 +05:30
Elan Ruusamäe
706cde84ae kitten: Add armv7l alias to arm
Fix Unknown CPU architecture armv7l
2023-10-03 18:26:11 +03:00
Kovid Goyal
d9cd92d4ed ... 2023-10-03 12:07:19 +05:30
Kovid Goyal
4b41a7d182 Fix #6650 2023-10-03 12:04:54 +05:30
Kovid Goyal
fcce5c9a64 Expose at_prompt property in kitty @ ls output 2023-10-03 11:33:08 +05:30
Kovid Goyal
4c37fff496 Fix secure restore state runtime warning from cocoa being printed to stderr 2023-10-03 11:23:56 +05:30
Kovid Goyal
450aa59303 Merge branch 'dependabot/go_modules/all-go-deps-911bbdbafd' of https://github.com/kovidgoyal/kitty 2023-10-02 09:16:53 +05:30
dependabot[bot]
77156be0f4 Bump the all-go-deps group with 1 update
Bumps the all-go-deps group with 1 update: [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil).

- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.8...v3.23.9)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-go-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-02 03:42:17 +00:00
Kovid Goyal
f37cce2ae4 ... 2023-10-01 08:20:15 +05:30
Kovid Goyal
dde80b9ad6 Dont need setuptools since we only use python stdlib 2023-09-30 08:09:06 +05:30
Kovid Goyal
1aaaa3f1e9 Fix incorrect exception when tic fails 2023-09-30 07:53:13 +05:30
Kovid Goyal
e04e5a157f Note that nushell supports the kitty keyboard protocol 2023-09-29 19:48:46 +05:30
Kovid Goyal
ed32bf35a7 clean up some docs text 2023-09-26 20:30:27 +05:30
Kovid Goyal
ef7d4934d2 Add window groups to kitty @ ls output
Fixes #6655
2023-09-26 18:41:52 +05:30
Kovid Goyal
bda9155be1 ... 2023-09-26 10:04:15 +05:30
Kovid Goyal
3fef881956 Fix #6653 2023-09-26 09:44:45 +05:30
Kovid Goyal
2502111697 Make mypy happy 2023-09-25 21:30:42 +05:30
Kovid Goyal
acd6b168fd ... 2023-09-25 21:16:24 +05:30
Kovid Goyal
164dd0d637 man pages: Fix table markup in kitty man pages not being rendered correctly at all window sizes
Fixes #5095
2023-09-25 21:09:27 +05:30
Kovid Goyal
ee3118ffaf Merge branch 'dependabot/go_modules/all-go-deps-508be90fc6' of https://github.com/kovidgoyal/kitty 2023-09-25 10:04:07 +05:30
dependabot[bot]
4f277deb6d Bump the all-go-deps group with 7 updates
Bumps the all-go-deps group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/ALTree/bigfloat](https://github.com/ALTree/bigfloat) | `0.0.0-20220102081255-38c8b72a9924` | `0.2.0` |
| [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) | `2.8.0` | `2.9.1` |
| [github.com/google/uuid](https://github.com/google/uuid) | `1.3.0` | `1.3.1` |
| [github.com/seancfoley/ipaddress-go](https://github.com/seancfoley/ipaddress-go) | `1.5.4` | `1.5.5` |
| [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) | `3.23.7` | `3.23.8` |
| [golang.org/x/image](https://github.com/golang/image) | `0.11.0` | `0.12.0` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.11.0` | `0.12.0` |


Updates `github.com/ALTree/bigfloat` from 0.0.0-20220102081255-38c8b72a9924 to 0.2.0
- [Commits](https://github.com/ALTree/bigfloat/commits/v0.2.0)

Updates `github.com/alecthomas/chroma/v2` from 2.8.0 to 2.9.1
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Changelog](https://github.com/alecthomas/chroma/blob/master/.goreleaser.yml)
- [Commits](https://github.com/alecthomas/chroma/compare/v2.8.0...v2.9.1)

Updates `github.com/google/uuid` from 1.3.0 to 1.3.1
- [Release notes](https://github.com/google/uuid/releases)
- [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/uuid/compare/v1.3.0...v1.3.1)

Updates `github.com/seancfoley/ipaddress-go` from 1.5.4 to 1.5.5
- [Release notes](https://github.com/seancfoley/ipaddress-go/releases)
- [Commits](https://github.com/seancfoley/ipaddress-go/compare/v1.5.4...v1.5.5)

Updates `github.com/shirou/gopsutil/v3` from 3.23.7 to 3.23.8
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.23.7...v3.23.8)

Updates `golang.org/x/image` from 0.11.0 to 0.12.0
- [Commits](https://github.com/golang/image/compare/v0.11.0...v0.12.0)

Updates `golang.org/x/sys` from 0.11.0 to 0.12.0
- [Commits](https://github.com/golang/sys/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: github.com/ALTree/bigfloat
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
- dependency-name: github.com/alecthomas/chroma/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
- dependency-name: github.com/google/uuid
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-go-deps
- dependency-name: github.com/seancfoley/ipaddress-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-go-deps
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-go-deps
- dependency-name: golang.org/x/image
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 03:51:21 +00:00
Kovid Goyal
f16e9500f1 Simplify count-lines-of-code 2023-09-24 15:52:25 +05:30
Kovid Goyal
45bfeeef21 Update FAQ on sudo + terminfo 2023-09-24 13:41:16 +05:30
Kovid Goyal
d96fdb80ed Shell integration now aliases sudo to make the kitty terminfo db available in the sudo environment
This should make terminfo completely transparent for most users on the
local machine and on remote machines that are connected to with the ssh
kitten.
2023-09-24 13:35:29 +05:30
Kovid Goyal
0c0c6b732f ... 2023-09-24 13:14:26 +05:30
Kovid Goyal
537475d5bb Better fix for clone-in-kitty 2023-09-24 11:34:32 +05:30
Kovid Goyal
8e7b6ad3c3 Fix clone-in-kitty broken because of login wrapping 2023-09-24 11:21:32 +05:30
Kovid Goyal
68b861b188 macOS: When running the default shell, run it via the login program so that calls to `getlogin()` work
Fixes #6511
2023-09-24 11:12:02 +05:30
Kovid Goyal
59e4c6660e run-shell: Allow specifying the cwd 2023-09-24 10:40:21 +05:30
Kovid Goyal
38be3e98a1 More linter fixes 2023-09-24 09:16:27 +05:30
Kovid Goyal
4af1a38507 More linter fixes 2023-09-24 09:06:15 +05:30
Kovid Goyal
70110d54b0 Use resolved shell for --hold 2023-09-24 08:34:08 +05:30
Kovid Goyal
76c6f91685 Expand environment variables in the shell option
See #6511 for discussion
2023-09-24 08:28:42 +05:30
Kovid Goyal
3d6c3a9979 Merge branch 'patch-1' of https://github.com/jake-stewart/kitty 2023-09-23 21:12:07 +05:30
jake-stewart
7b3513d010 fix double backslash
it looks like RST does not require backslashes to be escaped when encased in double backticks. double backslash in double backticks causes two backslashes to render. the problem can be seen on this page https://sw.kovidgoyal.net/kitty/conf/
2023-09-23 22:50:41 +08:00
Kovid Goyal
c280a28155 Dont use os.Remove on failures in syscall_shm
Use shm_unlink instead
2023-09-23 11:16:30 +05:30
Kovid Goyal
24598b846c ... 2023-09-23 11:09:51 +05:30
Kovid Goyal
dc43f0d42f ... 2023-09-23 11:08:55 +05:30
Kovid Goyal
5fede41205 Always use fallocate() on Linux for SHM creation 2023-09-23 10:55:15 +05:30
Kovid Goyal
6619bf33b0 Using fcntl() based fallocate on darwin doesnt work with file descriptors returned by shm_open 2023-09-23 10:39:10 +05:30
Kovid Goyal
627c80125b More linter fixes 2023-09-23 10:19:46 +05:30
Kovid Goyal
38bac98c12 Fix build of fallocate_darwin.go 2023-09-23 10:08:04 +05:30
Kovid Goyal
2e4f3dab41 Use fallocate() rather than truncate() when creating SHM memory
With truncate() the OS might not actually allocate the space leading to
a SIGBUS if /dev/shm runs out of space when actually using the mmap.

By using fallocate we ensure that once the SHM mmap is created it wont
fail
2023-09-23 09:53:17 +05:30
Kovid Goyal
911c80aa3b More linter fixes 2023-09-22 12:20:37 +05:30
Kovid Goyal
fd85dfb417 DRYer 2023-09-22 12:13:17 +05:30
Kovid Goyal
b26c4c16d0 ... 2023-09-22 12:11:07 +05:30
Kovid Goyal
c650bd0aac icat: Dont open the controlling terminal to query for size if stdout is a terminal, use it instead 2023-09-22 12:10:21 +05:30
Kovid Goyal
fc1331cfdc Dont call tcgetattr when no operations are specified 2023-09-22 09:37:48 +05:30
Kovid Goyal
fe4fdaefb9 Remove unused code 2023-09-22 09:25:21 +05:30
Kovid Goyal
704ae40dee More linter fixes 2023-09-22 09:24:31 +05:30
Kovid Goyal
0a2f164062 Change kitty +kitten -> kitten in docs
All kittens except for the broadcast and panel kittens have now been
ported to Go and so can be run with just kitten rather than kitty
+kitten. So update the docs to use this canonical form for launching
kittens
2023-09-21 12:25:02 +05:30
Kovid Goyal
eb05f6864f Update changelog 2023-09-20 09:17:00 +05:30
Kovid Goyal
b21bbbe14c Fix ssh kitten override parsing ignoring settings inherited from ssh.conf
Fixes #6639
2023-09-20 09:15:38 +05:30
Kovid Goyal
18e5b74699 More linter fixes 2023-09-20 08:43:50 +05:30
Kovid Goyal
d16a29b942 More linter fixes 2023-09-19 11:50:09 +05:30
Kovid Goyal
dda5771ccd Yet another stupid entry in Info.plist for Apple's security theatre
Fixes #6632
2023-09-18 22:31:52 +05:30
Kovid Goyal
65c777e335 Better error message for APC payload too large 2023-09-18 22:09:46 +05:30
Kovid Goyal
a8633756de More linter fixes 2023-09-18 21:36:34 +05:30
Kovid Goyal
1a32e62ebf More linter fixes 2023-09-18 21:07:39 +05:30
Kovid Goyal
7faf216f9e More linter fixes 2023-09-18 20:59:47 +05:30
Kovid Goyal
6bafdedd65 Fix some linter issues 2023-09-18 20:38:08 +05:30
Kovid Goyal
bd036040a6 themes kitten: Allow absolute paths for --config-file-name
Fixes #6638
2023-09-18 20:31:30 +05:30
Kovid Goyal
c94cfdbf65 ... 2023-09-18 18:47:32 +05:30
Kovid Goyal
35766a1a86 Link to a couple of kittens for more advanced scrollback paging in the docs 2023-09-18 11:01:17 +05:30
Kovid Goyal
616a104cce Remove unused code 2023-09-18 10:50:43 +05:30
Kovid Goyal
a5e74d406c fix link in changelog 2023-09-18 08:59:22 +05:30
Kovid Goyal
30c37a5809 ... 2023-09-18 08:46:22 +05:30
94 changed files with 699 additions and 417 deletions

View File

@@ -153,15 +153,6 @@
}
},
{
"name": "setuptools",
"unix": {
"filename": "setuptools-53.0.0.tar.gz",
"hash": "sha256:1b18ef17d74ba97ac9c0e4b4265f123f07a8ae85d9cd093949fa056d3eeeead5",
"urls": ["pypi"]
}
},
{
"name": "libpng",
"unix": {

View File

@@ -2,20 +2,16 @@
import subprocess
ignored = []
for line in subprocess.check_output(['git', 'status', '--ignored', '--porcelain']).decode().splitlines():
if line.startswith('!! '):
ignored.append(line[3:])
files_to_exclude = '\n'.join(ignored)
ls_files = subprocess.check_output([ 'git', 'ls-files']).decode('utf-8')
all_files = set(ls_files.splitlines())
all_files.discard('')
cp = subprocess.run(['git', 'check-attr', 'linguist-generated', '--stdin'],
check=True, stdout=subprocess.PIPE, input=subprocess.check_output([ 'git', 'ls-files']))
check=True, stdout=subprocess.PIPE, input='\n'.join(all_files).encode('utf-8'))
for line in cp.stdout.decode().splitlines():
if line.endswith(' true'):
files_to_exclude += '\n' + line.split(':')[0]
fname = line.split(':', 1)[0]
all_files.discard(fname)
p = subprocess.Popen([
'cloc', '--exclude-list-file', '/dev/stdin', 'kitty', 'kittens', 'tools', 'kitty_tests', 'docs',
], stdin=subprocess.PIPE)
p.communicate(files_to_exclude.encode('utf-8'))
raise SystemExit(p.wait())
all_files -= {'nerd-fonts-glyphs.txt', 'rowcolumn-diacritics.txt'}
cp = subprocess.run(['cloc', '--list-file', '-'], input='\n'.join(all_files).encode())
raise SystemExit(cp.returncode)

View File

@@ -43,12 +43,30 @@ The :doc:`ssh kitten <kittens/ssh>` is redesigned with powerful new features:
Detailed list of changes
-------------------------------------
0.30.0 [future]
0.30.1 [2023-10-05]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Shell integration: Automatically alias sudo to make the kitty terminfo files available in the sudo environment. Can be turned off via :opt:`shell_integration`
- ssh kitten: Fix a regression in 0.28.0 that caused using ``--kitten`` to
override :file:`ssh.conf` not inheriting settings from :file:`ssh.conf`
(:iss:`6639`)
- themes kitten: Allow absolute paths for ``--config-file-name`` (:iss:`6638`)
- Expand environment variables in the :opt:`shell` option (:iss:`6511`)
- macOS: When running the default shell, run it via the login program so that calls to ``getlogin()`` work (:iss:`6511`)
- X11: Fix a crash on startup when the ibus service returns errors and the GLFW_IM_MODULE env var is set to ibus (:iss:`6650`)
0.30.0 [2023-09-18]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A new :doc:`transfer kitten </kittens/transfer>` that can be used to transfer files efficiently over the TTY device
- ssh kitten: A new configuration directive `to automatically forward the kitty remote control socket <kitten-ssh.forward_remote_control>`
- ssh kitten: A new configuration directive :opt:`to automatically forward the kitty remote control socket <kitten-ssh.forward_remote_control>`
- Allow :doc:`easily building kitty from source </build>` needing the installation of only C and Go compilers.
All other dependencies are automatically vendored

View File

@@ -12,7 +12,7 @@ import re
import subprocess
import sys
import time
from functools import partial
from functools import lru_cache, partial
from typing import Any, Callable, Dict, Iterable, List, Tuple
from docutils import nodes
@@ -546,9 +546,41 @@ def add_html_context(app: Any, pagename: str, templatename: str, context: Any, d
context['toctree'] = include_sub_headings
@lru_cache
def monkeypatch_man_writer() -> None:
'''
Monkeypatch the docutils man translator to output better tables
'''
from docutils.writers.manpage import Table, Translator
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: Translator, node: object) -> None:
setattr(self, '_active_table', PatchedTable())
setattr(Translator, 'visit_table', visit_table)
def setup(app: Any) -> None:
os.makedirs('generated/conf', exist_ok=True)
from kittens.runner import all_kitten_names
monkeypatch_man_writer()
kn = all_kitten_names()
write_cli_docs(kn)
write_remote_control_protocol_docs()

View File

@@ -32,8 +32,8 @@ Comments can be added to the config file as lines starting with the ``#``
character. This works only if the ``#`` character is the first character in the
line.
Lines can be split by starting the next line with the ``\\`` character.
All leading whitespace and the ``\\`` character are removed.
Lines can be split by starting the next line with the ``\`` character.
All leading whitespace and the ``\`` character are removed.
.. _include:

View File

@@ -99,7 +99,7 @@ These issues all have the same root cause: the kitty terminfo files not being
available. The most common way this happens is SSHing into a computer that does
not have the kitty terminfo files. The simplest fix for that is running::
kitty +kitten ssh myserver
kitten ssh myserver
It will automatically copy over the terminfo files and also magically enable
:doc:`shell integration </shell-integration>` on the remote machine.
@@ -108,7 +108,7 @@ This :doc:`ssh kitten <kittens/ssh>` takes all the same command line arguments
as :program:`ssh`, you can alias it to something small in your shell's rc files
to avoid having to type it each time::
alias s="kitty +kitten ssh"
alias s="kitten ssh"
If this does not work, see :ref:`manual_terminfo_copy` for alternative ways to
get the kitty terminfo files onto a remote computer.
@@ -130,12 +130,15 @@ by running ``sudo visudo`` and adding the following line::
Defaults env_keep += "TERM TERMINFO"
If none of these are suitable for you, you can run sudo as follows::
If none of these are suitable for you, you can run sudo as ::
sudo TERMINFO="$TERMINFO" -s -H
sudo TERMINFO="$TERMINFO"
This will start a new root shell with the correct :envvar:`TERMINFO` value from your
current environment copied over.
This will make :envvar:`TERMINFO` available
in the sudo environment. Create an alias in your shell rc files to make this
convenient::
alias sudo="sudo TERMINFO=\"$TERMINFO\""
If you have double width characters in your prompt, you may also need to
explicitly set a UTF-8 locale, like::
@@ -148,7 +151,7 @@ I cannot use the key combination X in program Y?
First, run::
kitty +kitten show_key -m kitty
kitten show_key -m kitty
Press the key combination X. If the kitten reports the key press
that means kitty is correctly sending the key press to terminal programs.
@@ -172,7 +175,7 @@ How do I change the colors in a running kitty instance?
The easiest way to do it is to use the :doc:`themes kitten </kittens/themes>`,
to choose a new color theme. Simply run::
kitty +kitten themes
kitten themes
And choose your theme from the list.
@@ -391,7 +394,7 @@ For example::
This maps :kbd:`alt+s` to :kbd:`ctrl+s`. To figure out what bytes to use for
the :sc:`send_text <send_text>` you can use the ``show_key`` kitten. Run::
kitty +kitten show_key
kitten show_key
Then press the key you want to emulate. Note that this kitten will only show
keys that actually reach the terminal program, in particular, keys mapped to
@@ -399,7 +402,7 @@ actions in kitty will not be shown. To check those first map them to
:ac:`no_op`. You can also start a kitty instance without any shortcuts to
interfere::
kitty -o clear_all_shortcuts=yes kitty +kitten show_key
kitty -o clear_all_shortcuts=yes kitten show_key
How do I open a new window or tab with the same working directory as the current window?

View File

@@ -16,7 +16,7 @@ For some discussion regarding the design choices, see :iss:`33`.
To see a quick demo, inside a |kitty| terminal run::
kitty +kitten icat path/to/some/image.png
kitten icat path/to/some/image.png
You can also see a screenshot with more sophisticated features such as
alpha-blending and text over graphics.
@@ -524,8 +524,8 @@ Unicode placeholders
You can also use a special Unicode character ``U+10EEEE`` as a placeholder for
an image. This approach is less flexible, but it allows using images inside
any host application that supports Unicode and foreground colors (tmux, vim, weechat, etc.)
and as a way to pass escape codes through to the underlying terminal.
any host application that supports Unicode, foreground colors (tmux, vim, weechat, etc.),
and a way to pass escape codes through to the underlying terminal.
The central idea is that we use a single *Private Use* Unicode character as a
*placeholder* to indicate to the terminal that an image is supposed to be

View File

@@ -144,7 +144,7 @@ kitty with the following bash snippet:
set terminal pngcairo enhanced font 'Fira Sans,10'
set autoscale
set samples 1000
set output '|kitty +kitten icat --stdin yes'
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'

View File

@@ -58,15 +58,15 @@ Timestamps for the above video:
14:15
Interactive Kitty Shell: :kbd:`Ctrl+Shift+Esc`
14:36
Broadcast text: ``launch --allow-remote-control kitty +kitten broadcast``
Broadcast text: ``launch --allow-remote-control kitten broadcast``
15:18
Kitty Remote Control Protocol
15:52
Interactive Kitty Shell: Help
16:34
Choose theme interactively: ``kitty +kitten themes -h``
Choose theme interactively: ``kitten themes -h``
17:23
Choose theme by name: ``kitty +kitten themes [options] [theme_name]``
Choose theme by name: ``kitten themes [options] [theme_name]``
.. raw:: html

View File

@@ -28,7 +28,7 @@ issues in that proposal, listed at the :ref:`bottom of this document
You can see this protocol with all enhancements in action by running::
kitty +kitten show_key -m kitty
kitten show_key -m kitty
inside the kitty terminal to report key events.
@@ -48,6 +48,7 @@ In addition to kitty, this protocol is also implemented in:
* The `Helix text editor <https://github.com/helix-editor/helix/pull/4939>`__
* The `far2l file manager <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__
* The `awrit web browser <https://github.com/chase/awrit>`__
* The `nushell shell <https://github.com/nushell/nushell/pull/10540>`__
.. versionadded:: 0.20.0

View File

@@ -9,13 +9,13 @@ clipboard
The ``clipboard`` kitten can be used to read or write to the system clipboard
from the shell. It even works over SSH. Using it is as simple as::
echo hooray | kitty +kitten clipboard
echo hooray | kitten clipboard
All text received on :file:`STDIN` is copied to the clipboard.
To get text from the clipboard::
kitty +kitten clipboard --get-clipboard
kitten clipboard --get-clipboard
The text will be written to :file:`STDOUT`. Note that by default kitty asks for
permission when a program attempts to read the clipboard. This can be
@@ -29,22 +29,22 @@ more than just plain text from the system clipboard. You can transfer arbitrary
data types. Best illustrated with some examples::
# Copy an image to the clipboard:
kitty +kitten clipboard picture.png
kitten clipboard picture.png
# Copy an image and some text to the clipboard:
kitty +kitten clipboard picture.jpg text.txt
kitten clipboard picture.jpg text.txt
# Copy text from STDIN and an image to the clipboard:
echo hello | kitty +kitten clipboard picture.png /dev/stdin
echo hello | kitten clipboard picture.png /dev/stdin
# Copy any raster image available on the clipboard to a PNG file:
kitty +kitten clipboard -g picture.png
kitten clipboard -g picture.png
# Copy an image to a file and text to STDOUT:
kitty +kitten clipboard -g picture.png /dev/stdout
kitten clipboard -g picture.png /dev/stdout
# List the formats available on the system clipboard
kitty +kitten clipboard -g -m . /dev/stdout
kitten clipboard -g -m . /dev/stdout
Normally, the kitten guesses MIME types based on the file names. To control the
MIME types precisely, use the :option:`--mime <kitty +kitten clipboard --mime>` option.

View File

@@ -39,7 +39,7 @@ Usage
In the kitty terminal, run::
kitty +kitten diff file1 file2
kitten diff file1 file2
to see the diff between :file:`file1` and :file:`file2`.
@@ -48,7 +48,7 @@ example:
.. code-block:: sh
alias d="kitty +kitten diff"
alias d="kitten diff"
Now all you need to do to diff two files is::
@@ -103,9 +103,9 @@ Add the following to :file:`~/.gitconfig`:
prompt = false
trustExitCode = true
[difftool "kitty"]
cmd = kitty +kitten diff $LOCAL $REMOTE
cmd = kitten diff $LOCAL $REMOTE
[difftool "kitty.gui"]
cmd = kitty kitty +kitten diff $LOCAL $REMOTE
cmd = kitten diff $LOCAL $REMOTE
Now to use kitty-diff to view git diffs, you can simply do::

View File

@@ -1,6 +1,14 @@
Hyperlinked grep
=================
.. note::
As of ripgrep versions newer that 13.0 it supports hyperlinks
natively so you can just add the following alias in your shell rc file:
``alias rg="rg --hyperlink-format=kitty"`` no need to use this kitten.
But, see below for instructions on how to customize kitty to have it open
the hyperlinks from ripgrep in your favorite editor.
This kitten allows you to search your files using `ripgrep
<https://github.com/BurntSushi/ripgrep>`__ and open the results directly in your
favorite editor in the terminal, at the line containing the search result,
@@ -26,7 +34,7 @@ following contents:
Now, run a search with::
kitty +kitten hyperlinked_grep something
kitten hyperlinked_grep something
Hold down the :kbd:`Ctrl+Shift` keys and click on any of the result lines, to
open the file in :program:`vim` at the matching line. If you use some editor
@@ -36,7 +44,7 @@ accordingly.
Finally, add an alias to your shell's rc files to invoke the kitten as
:command:`hg`::
alias hg="kitty +kitten hyperlinked_grep"
alias hg="kitten hyperlinked_grep"
You can now run searches with::

View File

@@ -6,7 +6,7 @@ icat
The ``icat`` kitten can be used to display arbitrary images in the |kitty|
terminal. Using it is as simple as::
kitty +kitten icat image.jpeg
kitten icat image.jpeg
kitten icat image.jpeg
It supports all image types supported by `ImageMagick
@@ -15,7 +15,7 @@ It supports all image types supported by `ImageMagick
You might want to create an alias in your shell's configuration files::
alias icat="kitty +kitten icat"
alias icat="kitten icat"
Then you can simply use ``icat image.png`` to view images.

View File

@@ -33,14 +33,14 @@ To try it out, simply run:
.. code-block:: sh
kitty +kitten ssh some-hostname-to-connect-to
kitten ssh some-hostname-to-connect-to
You should end up at a shell prompt on the remote host, with shell integration
enabled. If you like it you can add an alias to it in your shell's rc files:
.. code-block:: sh
alias s="kitty +kitten ssh"
alias s="kitten ssh"
So now you can just type ``s hostname`` to connect.
@@ -79,13 +79,13 @@ Additionally, you can pass config options on the command line:
.. code-block:: sh
kitty +kitten ssh --kitten interpreter=python servername
kitten ssh --kitten interpreter=python servername
The :code:`--kitten` argument can be specified multiple times, with directives
from :file:`ssh.conf`. These are merged with :file:`ssh.conf` as if they were
appended to the end of that file. They apply only to the host being SSHed to by
this invocation, so any :opt:`hostname <kitten-ssh.hostname>` directives are
ignored.
from :file:`ssh.conf`. These override the final options used for the matched host, as if they
had been appended to the end of the matching section for that host in
:file:`ssh.conf`. They apply only to the host being SSHed to by this invocation,
so any :opt:`hostname <kitten-ssh.hostname>` directives are ignored.
.. warning::

View File

@@ -5,7 +5,7 @@ The themes kitten allows you to easily change color themes, from a collection of
over three hundred pre-built themes available at `kitty-themes
<https://github.com/kovidgoyal/kitty-themes>`_. To use it, simply run::
kitty +kitten themes
kitten themes
.. image:: ../screenshots/themes.png
@@ -72,7 +72,7 @@ Changing the theme non-interactively
You can specify the theme name as an argument when invoking the kitten to have
it change to that theme instantly. For example::
kitty +kitten themes --reload-in=all Dimmed Monokai
kitten themes --reload-in=all Dimmed Monokai
Will change the theme to ``Dimmed Monokai`` in all running kitty instances. See
below for more details on non-interactive operation.

View File

@@ -15,7 +15,7 @@ clicked. Let us illustrate with some examples, first. Create the file
# Open any image in the full kitty window by clicking on it
protocol file
mime image/*
action launch --type=overlay kitty +kitten icat --hold ${FILE_PATH}
action launch --type=overlay kitten icat --hold ${FILE_PATH}
Now, run ``ls --hyperlink=auto`` in kitty and click on the filename of an
image, holding down :kbd:`ctrl+shift`. It will be opened over the current

View File

@@ -266,7 +266,9 @@ 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:`vim` to get more powerful
features, you can see tips for doing so, in :iss:`this thread <719>`.
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>`.
If you wish to store very large amounts of scrollback to view using the piping
or :sc:`show_scrollback <show_scrollback>` features, you can use the

View File

@@ -91,6 +91,10 @@ no-complete
Note that for the fish shell this does not take effect, since fish already
comes with a kitty completion script.
no-sudo
Do not alias :program:`sudo` to ensure the kitty terminfo files are
available in the sudo environment
More ways to browse command output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -214,7 +218,7 @@ Shell integration over SSH
The easiest way to have shell integration work when SSHing into remote systems
is to use the :doc:`ssh kitten <kittens/ssh>`. Simply run::
kitty +kitten ssh hostname
kitten ssh hostname
And, by magic, you will be logged into the remote system with fully functional
shell integration. Alternately, you can :ref:`setup shell integration manually

View File

@@ -113,7 +113,7 @@ def generate(
sz = screen->parser_buf_pos - pos;
g.payload_sz = sizeof(payload);
if (!base64_decode32(screen->parser_buf + pos, sz, payload, &g.payload_sz)) {{
REPORT_ERROR("Failed to parse {command_class} command payload with error: %s", "output buffer for base64_decode too small"); return; }}
REPORT_ERROR("Failed to parse {command_class} command payload with error: payload size (%zu) too large", sz); return; }}
pos = screen->parser_buf_pos;
}}
break;

View File

@@ -308,6 +308,10 @@ static NSDictionary<NSString*,NSNumber*> *global_shortcuts = nil;
return NSTerminateCancel;
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}
static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag

4
glfw/dbus_glfw.c vendored
View File

@@ -33,12 +33,12 @@
static void
report_error(DBusError *err, const char *fmt, ...) {
static char buf[1024];
static char buf[4096];
va_list args;
va_start(args, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
snprintf(buf + n, sizeof(buf), ". DBUS error: %s", err->message);
if (n >= 0 && (size_t)n < (sizeof(buf) - 256)) snprintf(buf + n, sizeof(buf) - n, ". DBUS error: %s", err->message ? err->message : "(null)");
_glfwInputError(GLFW_PLATFORM_ERROR, "%s", buf);
dbus_error_free(err);
}

18
go.mod
View File

@@ -3,19 +3,19 @@ module kitty
go 1.21
require (
github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924
github.com/alecthomas/chroma/v2 v2.8.0
github.com/ALTree/bigfloat v0.2.0
github.com/alecthomas/chroma/v2 v2.9.1
github.com/bmatcuk/doublestar/v4 v4.6.0
github.com/disintegration/imaging v1.6.2
github.com/dlclark/regexp2 v1.10.0
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/seancfoley/ipaddress-go v1.5.4
github.com/shirou/gopsutil/v3 v3.23.7
github.com/google/uuid v1.3.1
github.com/seancfoley/ipaddress-go v1.5.5
github.com/shirou/gopsutil/v3 v3.23.9
github.com/zeebo/xxh3 v1.0.2
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b
golang.org/x/image v0.11.0
golang.org/x/sys v0.11.0
golang.org/x/image v0.12.0
golang.org/x/sys v0.12.0
howett.net/plist v1.0.0
)
@@ -24,9 +24,9 @@ require (
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/seancfoley/bintree v1.2.1 // indirect
github.com/seancfoley/bintree v1.2.3 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
)

40
go.sum
View File

@@ -1,9 +1,9 @@
github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924 h1:DG4UyTVIujioxwJc8Zj8Nabz1L1wTgQ/xNBSQDfdP3I=
github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924/go.mod h1:+NaH2gLeY6RPBPPQf4aRotPPStg+eXc8f9ZaE4vRfD4=
github.com/ALTree/bigfloat v0.2.0 h1:AwNzawrpFuw55/YDVlcPw0F0cmmXrmngBHhVrvdXPvM=
github.com/ALTree/bigfloat v0.2.0/go.mod h1:+NaH2gLeY6RPBPPQf4aRotPPStg+eXc8f9ZaE4vRfD4=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/chroma/v2 v2.8.0 h1:w9WJUjFFmHHB2e8mRpL9jjy3alYDlU0QLDezj1xE264=
github.com/alecthomas/chroma/v2 v2.8.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
github.com/alecthomas/chroma/v2 v2.9.1 h1:0O3lTQh9FxazJ4BYE/MOi/vDGuHn7B+6Bu902N2UZvU=
github.com/alecthomas/chroma/v2 v2.9.1/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
@@ -20,8 +20,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@@ -35,12 +35,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/seancfoley/bintree v1.2.1 h1:Z/iNjRKkXnn0CTW7jDQYtjW5fz2GH1yWvOTJ4MrMvdo=
github.com/seancfoley/bintree v1.2.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU=
github.com/seancfoley/ipaddress-go v1.5.4 h1:ZdjewWC1J2y5ruQjWHwK6rA1tInWB6mz1ftz6uTm+Uw=
github.com/seancfoley/ipaddress-go v1.5.4/go.mod h1:fpvVPC+Jso+YEhNcNiww8HQmBgKP8T4T6BTp1SLxxIo=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
github.com/seancfoley/bintree v1.2.3 h1:6SPPax/9Dilcs3mDTj3CarRCWPZJV30KyP3cjcEwF70=
github.com/seancfoley/bintree v1.2.3/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU=
github.com/seancfoley/ipaddress-go v1.5.5 h1:Q2isCacDQ3A46hxSbM9Q2+Gs4IopCVz1oH88L5eEgP4=
github.com/seancfoley/ipaddress-go v1.5.5/go.mod h1:C+VHKCmxTfYODkkItOj9lMemZLMigwo28E+ARlPqpk0=
github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E=
github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -52,9 +52,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@@ -69,8 +68,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ=
golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -87,12 +86,11 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -100,7 +98,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -60,22 +60,22 @@ the clipboard. Some examples:
.. code:: sh
# Copy an image to the clipboard:
kitty +kitten clipboard picture.png
kitten clipboard picture.png
# Copy an image and some text to the clipboard:
kitty +kitten clipboard picture.jpg text.txt
kitten clipboard picture.jpg text.txt
# Copy text from STDIN and an image to the clipboard:
echo hello | kitty +kitten clipboard picture.png /dev/stdin
echo hello | kitten clipboard picture.png /dev/stdin
# Copy any raster image available on the clipboard to a PNG file:
kitty +kitten clipboard -g picture.png
kitten clipboard -g picture.png
# Copy an image to a file and text to STDOUT:
kitty +kitten clipboard -g picture.png /dev/stdout
kitten clipboard -g picture.png /dev/stdout
# List the formats available on the system clipboard
kitty +kitten clipboard -g -m . /dev/stdout
kitten clipboard -g -m . /dev/stdout
'''
usage = '[files to copy to/from]'

View File

@@ -263,6 +263,9 @@ func walk(base string, patterns []string, names *utils.Set[string], pmap, path_n
return err
}
return filepath.WalkDir(base, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
is_allowed := allowed(path, patterns...)
if !is_allowed {
if d.IsDir() {
@@ -297,7 +300,9 @@ func (self *Collection) collect_files(left, right string) error {
if err != nil {
return err
}
err = walk(right, conf.Ignore_name, right_names, right_path_map, path_name_map)
if err = walk(right, conf.Ignore_name, right_names, right_path_map, path_name_map); err != nil {
return err
}
common_names := left_names.Intersect(right_names)
changed_names := utils.NewSet[string](common_names.Len())
for n := range common_names.Iterable() {

View File

@@ -19,16 +19,16 @@ var _ = fmt.Print
func TestDiffCollectWalk(t *testing.T) {
tdir := t.TempDir()
j := func(x ...string) string { return filepath.Join(append([]string{tdir}, x...)...) }
os.MkdirAll(j("a", "b"), 0o700)
os.WriteFile(j("a/b/c"), nil, 0o600)
os.WriteFile(j("b"), nil, 0o600)
os.WriteFile(j("d"), nil, 0o600)
os.WriteFile(j("e"), nil, 0o600)
os.WriteFile(j("#d#"), nil, 0o600)
os.WriteFile(j("e~"), nil, 0o600)
os.MkdirAll(j("f"), 0o700)
os.WriteFile(j("f/g"), nil, 0o600)
os.WriteFile(j("h space"), nil, 0o600)
_ = os.MkdirAll(j("a", "b"), 0o700)
_ = os.WriteFile(j("a/b/c"), nil, 0o600)
_ = os.WriteFile(j("b"), nil, 0o600)
_ = os.WriteFile(j("d"), nil, 0o600)
_ = os.WriteFile(j("e"), nil, 0o600)
_ = os.WriteFile(j("#d#"), nil, 0o600)
_ = os.WriteFile(j("e~"), nil, 0o600)
_ = os.MkdirAll(j("f"), 0o700)
_ = os.WriteFile(j("f/g"), nil, 0o600)
_ = os.WriteFile(j("h space"), nil, 0o600)
expected_names := utils.NewSetWithItems("d", "e", "f/g", "h space")
expected_pmap := map[string]string{

View File

@@ -81,23 +81,37 @@ func clear_background(style *chroma.Style) *chroma.Style {
return style
}
func ansi_formatter(w io.Writer, style *chroma.Style, it chroma.Iterator) error {
func ansi_formatter(w io.Writer, style *chroma.Style, it chroma.Iterator) (err error) {
const SGR_PREFIX = "\033["
const SGR_SUFFIX = "m"
style = clear_background(style)
before, after := make([]byte, 0, 64), make([]byte, 0, 64)
nl := []byte{'\n'}
write_sgr := func(which []byte) {
write_sgr := func(which []byte) (err error) {
if len(which) > 1 {
w.Write(utils.UnsafeStringToBytes(SGR_PREFIX))
w.Write(which[:len(which)-1])
w.Write(utils.UnsafeStringToBytes(SGR_SUFFIX))
if _, err = w.Write(utils.UnsafeStringToBytes(SGR_PREFIX)); err != nil {
return err
}
if _, err = w.Write(which[:len(which)-1]); err != nil {
return err
}
if _, err = w.Write(utils.UnsafeStringToBytes(SGR_SUFFIX)); err != nil {
return err
}
}
return
}
write := func(text string) {
write_sgr(before)
w.Write(utils.UnsafeStringToBytes(text))
write_sgr(after)
write := func(text string) (err error) {
if err = write_sgr(before); err != nil {
return err
}
if _, err = w.Write(utils.UnsafeStringToBytes(text)); err != nil {
return err
}
if err = write_sgr(after); err != nil {
return err
}
return
}
for token := it(); token != chroma.EOF; token = it() {
@@ -127,11 +141,17 @@ func ansi_formatter(w io.Writer, style *chroma.Style, it chroma.Iterator) error
for text != "" {
idx := strings.IndexByte(text, '\n')
if idx < 0 {
write(text)
if err = write(text); err != nil {
return err
}
break
}
write(text[:idx])
w.Write(nl)
if err = write(text[:idx]); err != nil {
return err
}
if _, err = w.Write(nl); err != nil {
return err
}
text = text[idx+1:]
}
}

View File

@@ -76,13 +76,15 @@ func get_ssh_file(hostname, rpath string) (string, error) {
}
ans := filepath.Join(tdir, rpath)
if count == 1 {
filepath.WalkDir(tdir, func(path string, d fs.DirEntry, err error) error {
if err = filepath.WalkDir(tdir, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
ans = path
return fs.SkipAll
}
return nil
})
}); err != nil {
return "", err
}
}
return ans, nil
}

View File

@@ -40,7 +40,7 @@ func read_relevant_kitty_opts(path string) KittyOpts {
return nil
}
cp := config.ConfigParser{LineHandler: handle_line}
cp.ParseFiles(path)
_ = cp.ParseFiles(path)
return ans
}
@@ -53,7 +53,7 @@ func (self *Handler) handle_wheel_event(up bool) {
if up {
amt *= -1
}
self.dispatch_action(`scroll_by`, strconv.Itoa(amt))
_ = self.dispatch_action(`scroll_by`, strconv.Itoa(amt))
}
type line_pos struct {
@@ -113,6 +113,7 @@ func (self *Handler) drag_scroll_tick(timer_id loop.IdType) error {
}
var debugprintln = tty.DebugPrintln
var _ = debugprintln
func (self *Handler) update_mouse_selection(ev *loop.MouseEvent) {
if !self.mouse_selection.IsActive() {

View File

@@ -159,7 +159,7 @@ var format_as_sgr struct {
title, margin, added, removed, added_margin, removed_margin, filler, margin_filler, hunk_margin, hunk, selection, search string
}
var statusline_format, added_count_format, removed_count_format, message_format, selection_format func(...any) string
var statusline_format, added_count_format, removed_count_format, message_format func(...any) string
func create_formatters() {
ctx := style.Context{AllowEscapeCodes: true}
@@ -169,7 +169,6 @@ func create_formatters() {
return ans
}
format_as_sgr.filler = only_open("bg=" + conf.Filler_bg.AsRGBSharp())
debugprintln(11111, conf.Margin_filler_bg.IsSet)
if conf.Margin_filler_bg.IsSet {
format_as_sgr.margin_filler = only_open("bg=" + conf.Margin_filler_bg.Color.AsRGBSharp())
} else {
@@ -392,8 +391,6 @@ func image_lines(left_path, right_path string, screen_size screen_size, margin_s
return append(ans, ll), nil
}
type formatter = func(...any) string
func first_binary_line(left_path, right_path string, columns, margin_size int, renderer func(path string) (string, error)) (*LogicalLine, error) {
available_cols := columns/2 - margin_size
ll := LogicalLine{
@@ -771,10 +768,3 @@ func render(collection *Collection, diff_map map[string]*Patch, screen_size scre
}
return &LogicalLines{lines: ll, margin_size: margin_size, columns: columns}, err
}
func (self *LogicalLines) num_of_screen_lines() (ans int) {
for _, l := range self.lines {
ans += len(l.screen_lines)
}
return
}

View File

@@ -142,7 +142,7 @@ func (self *Handler) initialize() {
func (self *Handler) generate_diff() {
self.diff_map = nil
jobs := make([]diff_job, 0, 32)
self.collection.Apply(func(path, typ, changed_path string) error {
_ = self.collection.Apply(func(path, typ, changed_path string) error {
if typ == "diff" {
if is_path_text(path) && is_path_text(changed_path) {
jobs = append(jobs, diff_job{path, changed_path})
@@ -188,7 +188,7 @@ func (self *Handler) highlight_all() {
}
func (self *Handler) load_all_images() {
self.collection.Apply(func(path, item_type, changed_path string) error {
_ = self.collection.Apply(func(path, item_type, changed_path string) error {
if path != "" && is_image(path) {
image_collection.AddPaths(path)
self.image_count++
@@ -627,11 +627,9 @@ func (self *Handler) dispatch_action(name, args string) error {
}
done = self.scroll_lines(amt) != 0
default:
npos := self.scroll_pos
npos := ScrollPos{}
if strings.Contains(args, `end`) {
npos = self.max_scroll_pos
} else {
npos = ScrollPos{}
}
done = npos != self.scroll_pos
self.scroll_pos = npos

View File

@@ -134,7 +134,7 @@ window, :code:`window` a new kitty window, :code:`tab` a new tab,
:code:`os_window` a new OS window and :code:`background` run in the background.
The actual action is whatever arguments are provided to the kitten, for
example:
:code:`kitty +kitten hints --type=linenum --linenum-action=tab vim +{line} {path}`
:code:`kitten hints --type=linenum --linenum-action=tab vim +{line} {path}`
will open the matched path at the matched line number in vim in
a new kitty tab. Note that in order to use :option:`--program` to copy or paste
the provided arguments, you need to use the special value :code:`self`.

View File

@@ -286,6 +286,9 @@ func (self *stdout_filter) Write(p []byte) (n int, err error) {
func main(_ *cli.Command, _ *Options, args []string) (rc int, err error) {
delegate_to_rg, sanitized_args, kitten_opts, err := parse_args(args...)
if err != nil {
return 1, err
}
if delegate_to_rg {
sanitized_args = append([]string{"rg"}, sanitized_args...)
err = unix.Exec(RgExe(), sanitized_args, os.Environ())

View File

@@ -38,14 +38,14 @@ func DetectSupport(timeout time.Duration) (memory, files, direct bool, err error
}
if len(shm_files_to_delete) > 0 && transfer_by_memory != supported {
for _, name := range shm_files_to_delete {
name.Unlink()
_ = name.Unlink()
}
}
}()
lp.OnInitialize = func() (string, error) {
var iid uint32
lp.AddTimer(timeout, false, func(loop.IdType) error {
_, _ = lp.AddTimer(timeout, false, func(loop.IdType) error {
return fmt.Errorf("Timed out waiting for a response form the terminal: %w", os.ErrDeadlineExceeded)
})
@@ -54,7 +54,7 @@ func DetectSupport(timeout time.Duration) (memory, files, direct bool, err error
g1 := &graphics.GraphicsCommand{}
g1.SetTransmission(t).SetAction(graphics.GRT_action_query).SetImageId(iid).SetDataWidth(1).SetDataHeight(1).SetFormat(
graphics.GRT_format_rgb).SetDataSize(uint64(len(payload)))
g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
_ = g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
return iid
}
@@ -63,7 +63,9 @@ func DetectSupport(timeout time.Duration) (memory, files, direct bool, err error
if err == nil {
file_query_id = g(graphics.GRT_transmission_tempfile, tf.Name())
temp_files_to_delete = append(temp_files_to_delete, tf.Name())
tf.Write([]byte{1, 2, 3})
if _, err = tf.Write([]byte{1, 2, 3}); err != nil {
print_error("Failed to write to temporary file for data transfer, file based transfer is disabled. Error: %v", err)
}
tf.Close()
} else {
print_error("Failed to create temporary file for data transfer, file based transfer is disabled. Error: %v", err)

View File

@@ -42,7 +42,7 @@ const (
supported
)
var transfer_by_file, transfer_by_memory, transfer_by_stream transfer_mode
var transfer_by_file, transfer_by_memory transfer_mode
var files_channel chan input_arg
var output_channel chan *image_data
@@ -146,11 +146,15 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
if err != nil {
return 1, err
}
t, err := tty.OpenControllingTerm()
if err != nil {
return 1, fmt.Errorf("Failed to open controlling terminal with error: %w", err)
if tty.IsTerminal(os.Stdout.Fd()) {
screen_size, err = tty.GetSize(int(os.Stdout.Fd()))
} else {
t, oerr := tty.OpenControllingTerm()
if oerr != nil {
return 1, fmt.Errorf("Failed to open controlling terminal with error: %w", oerr)
}
screen_size, err = t.GetSize()
}
screen_size, err = t.GetSize()
if err != nil {
return 1, fmt.Errorf("Failed to query terminal using TIOCGWINSZ with error: %w", err)
}
@@ -162,7 +166,9 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
if opts.Clear {
cc := &graphics.GraphicsCommand{}
cc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_visible)
cc.WriteWithPayloadTo(os.Stdout, nil)
if err = cc.WriteWithPayloadTo(os.Stdout, nil); err != nil {
return 1, err
}
}
if screen_size.Xpixel == 0 || screen_size.Ypixel == 0 {
return 1, fmt.Errorf("Terminal does not support reporting screen sizes in pixels, use a terminal such as kitty, WezTerm, Konsole, etc. that does.")
@@ -224,7 +230,6 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
// tmux doesn't allow responses from the terminal so we can't detect if memory or file based transferring is supported
transfer_by_memory = unsupported
transfer_by_file = unsupported
transfer_by_stream = supported
}
if opts.DetectSupport {
if transfer_by_memory == supported {

View File

@@ -75,7 +75,7 @@ detecting image display support.
--print-window-size
type=bool-set
Print out the window size as <:italic:`width`>x<:italic:`height`> (in pixels) and quit. This is a
convenience method to query the window size if using :code:`kitty +kitten icat`
convenience method to query the window size if using :code:`kitten icat`
from a scripting language that cannot make termios calls.

View File

@@ -123,6 +123,7 @@ func load_one_frame_image(ctx *images.Context, imgd *image_data, src *opened_inp
}
var debugprintln = tty.DebugPrintln
var _ = debugprintln
func (frame *image_frame) set_disposal(anchor_frame int, disposal byte) int {
anchor_frame, frame.compose_onto = images.SetGIFFrameDisposal(frame.number, anchor_frame, disposal)

View File

@@ -93,7 +93,7 @@ func process_dirs(args ...string) (results []input_arg, err error) {
return nil, &fs.PathError{Op: "Stat", Path: arg, Err: err}
}
if s.IsDir() {
filepath.WalkDir(arg, func(path string, d fs.DirEntry, walk_err error) error {
if err = filepath.WalkDir(arg, func(path string, d fs.DirEntry, walk_err error) error {
if walk_err != nil {
if d == nil {
err = &fs.PathError{Op: "Stat", Path: arg, Err: walk_err}
@@ -107,7 +107,9 @@ func process_dirs(args ...string) (results []input_arg, err error) {
}
}
return nil
})
}); err != nil {
return nil, err
}
} else {
results = append(results, input_arg{arg: arg, value: arg})
}
@@ -124,7 +126,7 @@ type opened_input struct {
func (self *opened_input) Rewind() {
if self.file != nil {
self.file.Seek(0, io.SeekStart)
_, _ = self.file.Seek(0, io.SeekStart)
}
}

View File

@@ -95,7 +95,7 @@ func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) (err erro
}
defer f.Close()
data_size, _ = f.Seek(0, io.SeekEnd)
f.Seek(0, io.SeekStart)
_, _ = f.Seek(0, io.SeekStart)
mmap, err = shm.CreateTemp("icat-*", uint64(data_size))
if err != nil {
return fmt.Errorf("Failed to create a SHM file for transmission: %w", err)
@@ -108,7 +108,7 @@ func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) (err erro
if errors.Is(err, io.EOF) {
break
}
mmap.Unlink()
_ = mmap.Unlink()
return fmt.Errorf("Failed to read data from image output data file: %w", err)
}
}
@@ -128,10 +128,10 @@ func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) (err erro
gc := gc_for_image(imgd, frame_num, frame)
gc.SetTransmission(graphics.GRT_transmission_sharedmem)
gc.SetDataSize(uint64(data_size))
gc.WriteWithPayloadTo(os.Stdout, utils.UnsafeStringToBytes(mmap.Name()))
err = gc.WriteWithPayloadTo(os.Stdout, utils.UnsafeStringToBytes(mmap.Name()))
mmap.Close()
return nil
return
}
func transmit_file(imgd *image_data, frame_num int, frame *image_frame) (err error) {
@@ -174,8 +174,7 @@ func transmit_file(imgd *image_data, frame_num int, frame *image_frame) (err err
if data_size > 0 {
gc.SetDataSize(uint64(data_size))
}
gc.WriteWithPayloadTo(os.Stdout, utils.UnsafeStringToBytes(fname))
return nil
return gc.WriteWithPayloadTo(os.Stdout, utils.UnsafeStringToBytes(fname))
}
func transmit_stream(imgd *image_data, frame_num int, frame *image_frame) (err error) {
@@ -192,8 +191,7 @@ func transmit_stream(imgd *image_data, frame_num int, frame *image_frame) (err e
}
}
gc := gc_for_image(imgd, frame_num, frame)
gc.WriteWithPayloadTo(os.Stdout, data)
return nil
return gc.WriteWithPayloadTo(os.Stdout, data)
}
func calculate_in_cell_x_offset(width, cell_width int) int {
@@ -291,7 +289,7 @@ func transmit_image(imgd *image_data) {
frame.filename = ""
}
if frame.shm != nil {
frame.shm.Unlink()
_ = frame.shm.Unlink()
frame.shm.Close()
frame.shm = nil
}
@@ -386,11 +384,15 @@ func transmit_image(imgd *image_data) {
case opts.Loop > 0:
c.SetNumberOfLoops(uint64(opts.Loop) + 1)
}
c.WriteWithPayloadTo(os.Stdout, nil)
if imgd.err = c.WriteWithPayloadTo(os.Stdout, nil); imgd.err != nil {
return
}
case 1:
c := frame_control_cmd
c.SetAnimationControl(2) // set animation to loading mode
c.WriteWithPayloadTo(os.Stdout, nil)
if imgd.err = c.WriteWithPayloadTo(os.Stdout, nil); imgd.err != nil {
return
}
}
}
}
@@ -400,7 +402,9 @@ func transmit_image(imgd *image_data) {
if is_animated {
c := frame_control_cmd
c.SetAnimationControl(3) // set animation to normal mode
c.WriteWithPayloadTo(os.Stdout, nil)
if imgd.err = c.WriteWithPayloadTo(os.Stdout, nil); imgd.err != nil {
return
}
}
if imgd.move_to.x == 0 {
fmt.Println() // ensure cursor is on new line

View File

@@ -57,12 +57,13 @@ func RunSSHAskpass() {
fatal(fmt.Errorf("Failed to create SHM file with error: %w", err))
}
defer data_shm.Close()
defer data_shm.Unlink()
defer func() { _ = data_shm.Unlink() }()
data_shm.Slice()[0] = 0
shm.WriteWithSize(data_shm, data, 1)
err = data_shm.Flush()
if err != nil {
if err = shm.WriteWithSize(data_shm, data, 1); err != nil {
fatal(fmt.Errorf("Failed to write to SHM file with error: %w", err))
}
if err = data_shm.Flush(); err != nil {
fatal(fmt.Errorf("Failed to flush SHM file with error: %w", err))
}
trigger_ask(data_shm.Name())

View File

@@ -169,7 +169,7 @@ func get_arcname(loc, dest, home string) (arcname string) {
arcname = dest
} else {
arcname = filepath.Clean(loc)
if filepath.HasPrefix(arcname, home) {
if strings.HasPrefix(arcname, home) {
ra, err := filepath.Rel(home, arcname)
if err == nil {
arcname = ra
@@ -391,9 +391,20 @@ func (self *ConfigSet) line_handler(key, val string) error {
func load_config(hostname_to_match string, username_to_match string, overrides []string, paths ...string) (*Config, []config.ConfigLine, error) {
ans := &ConfigSet{all_configs: []*Config{NewConfig()}}
p := config.ConfigParser{LineHandler: ans.line_handler}
err := p.LoadConfig("ssh.conf", paths, overrides)
err := p.LoadConfig("ssh.conf", paths, nil)
if err != nil {
return nil, nil, err
}
return config_for_hostname(hostname_to_match, username_to_match, ans), p.BadLines(), nil
final_conf := config_for_hostname(hostname_to_match, username_to_match, ans)
bad_lines := p.BadLines()
if len(overrides) > 0 {
h := final_conf.Hostname
override_parser := config.ConfigParser{LineHandler: final_conf.Parse}
if err = override_parser.ParseOverrides(overrides...); err != nil {
return nil, nil, err
}
bad_lines = append(bad_lines, override_parser.BadLines()...)
final_conf.Hostname = h
}
return final_conf, bad_lines, nil
}

View File

@@ -24,11 +24,14 @@ func TestSSHConfigParsing(t *testing.T) {
hostname := "unmatched"
username := ""
conf := ""
overrides := []string{}
for_python := false
cf := filepath.Join(tdir, "ssh.conf")
rt := func(expected_env ...string) {
os.WriteFile(cf, []byte(conf), 0o600)
c, bad_lines, err := load_config(hostname, username, nil, cf)
if err := os.WriteFile(cf, []byte(conf), 0o600); err != nil {
t.Fatal(err)
}
c, bad_lines, err := load_config(hostname, username, overrides, cf)
if err != nil {
t.Fatal(err)
}
@@ -52,6 +55,10 @@ func TestSSHConfigParsing(t *testing.T) {
rt()
conf = "env a=b"
rt(`export 'a'="b"`)
conf = "env a=b"
overrides = []string{"env=c=d"}
rt(`export 'a'="b"`, `export 'c'="d"`)
overrides = nil
conf = "env a=\\"
rt(`export 'a'="\\"`)

View File

@@ -65,7 +65,6 @@ func get_destination(hostname string) (username, hostname_for_match string) {
}
if !parsed && strings.Contains(hostname, "@") && hostname[0] != '@' {
_, hostname_for_match, _ = strings.Cut(hostname, "@")
parsed = true
}
return
}
@@ -116,9 +115,6 @@ func parse_kitten_args(found_extra_args []string, username, hostname_for_match s
}
}
}
if len(overrides) > 0 {
overrides = append([]string{"hostname " + username + "@" + hostname_for_match}, overrides...)
}
return
}
@@ -155,7 +151,7 @@ func set_askpass() (need_to_request_data bool) {
sentinel_exists := err == nil
if sentinel_exists || GetSSHVersion().SupportsAskpassRequire() {
if !sentinel_exists {
os.WriteFile(sentinel, []byte{0}, 0o644)
_ = os.WriteFile(sentinel, []byte{0}, 0o644)
}
need_to_request_data = false
}
@@ -322,9 +318,13 @@ func make_tarfile(cd *connection_data, get_local_env func(string) (string, bool)
return nil
}
add_data(fe{"data.sh", utils.UnsafeStringToBytes(env_script)})
if err = add_data(fe{"data.sh", utils.UnsafeStringToBytes(env_script)}); err != nil {
return nil, err
}
if cd.script_type == "sh" {
add_data(fe{"bootstrap-utils.sh", shell_integration.Data()[path.Join("shell-integration/ssh/bootstrap-utils.sh")].Data})
if err = add_data(fe{"bootstrap-utils.sh", shell_integration.Data()[path.Join("shell-integration/ssh/bootstrap-utils.sh")].Data}); err != nil {
return nil, err
}
}
if ksi != "" {
for _, fname := range shell_integration.Data().FilesMatching(
@@ -547,7 +547,7 @@ func drain_potential_tty_garbage(term *tty.Term) {
buf := make([]byte, 0, 8192)
for !bytes.Contains(data, q) {
buf = buf[:cap(buf)]
timeout := give_up_at.Sub(time.Now())
timeout := time.Until(give_up_at)
if timeout < 0 {
break
}
@@ -597,7 +597,7 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
defer func() {
if data_shm != nil {
data_shm.Close()
data_shm.Unlink()
_ = data_shm.Unlink()
}
}()
cmd := append([]string{SSHExe()}, ssh_args...)
@@ -703,9 +703,9 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
c.Stdout = &b
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
return 1, fmt.Errorf("%s\nSetup of port forward in SSH ControlMaster failed with error: %w", string(b.Bytes()), err)
return 1, fmt.Errorf("%s\nSetup of port forward in SSH ControlMaster failed with error: %w", b.String(), err)
}
port, err := strconv.Atoi(strings.TrimSpace(string(b.Bytes())))
port, err := strconv.Atoi(strings.TrimSpace(b.String()))
if err != nil {
os.Stderr.Write(b.Bytes())
return 1, fmt.Errorf("Setup of port forward in SSH ControlMaster failed with error: invalid resolved port returned: %s", b.String())
@@ -732,7 +732,7 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
restore_escape_codes += "\x1b[#Q"
}
defer func() {
term.WriteAllString(restore_escape_codes)
_ = term.WriteAllString(restore_escape_codes)
term.RestoreAndClose()
}()
err = get_remote_command(&cd)
@@ -760,13 +760,13 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
}
}
if err != nil {
c.Process.Kill()
c.Wait()
_ = c.Process.Kill()
_ = c.Wait()
return 1, err
}
}
go func() {
_ = <-sigs
<-sigs
// ignore any interrupt and terminate signals as they will usually be sent to the ssh child process as well
// and we are waiting on that.
}()
@@ -777,7 +777,7 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
var exit_err *exec.ExitError
if errors.As(err, &exit_err) {
if state := exit_err.ProcessState.String(); state == "signal: interrupt" {
unix.Kill(os.Getpid(), unix.SIGINT)
_ = unix.Kill(os.Getpid(), unix.SIGINT)
// Give the signal time to be delivered
time.Sleep(20 * time.Millisecond)
}

View File

@@ -111,12 +111,12 @@ func parse_theme_metadata() error {
for _, path := range paths {
if path != "" {
metadata, _, err := themes.ParseThemeMetadata(path)
if metadata.Name == "" {
metadata.Name = themes.ThemeNameFromFileName(filepath.Base(path))
}
if err != nil {
return err
}
if metadata.Name == "" {
metadata.Name = themes.ThemeNameFromFileName(filepath.Base(path))
}
ans = append(ans, metadata)
}
}

View File

@@ -447,10 +447,10 @@ func (self *handler) draw_theme_demo() {
if intense {
s = "bright-" + s
}
if len(c) > trunc {
c = c[:trunc]
if len(s) > trunc {
s = s[:trunc]
}
buf.WriteString(self.lp.SprintStyled("fg="+c, c))
buf.WriteString(self.lp.SprintStyled("fg="+s, s))
buf.WriteString(" ")
}
text := strings.TrimSpace(buf.String())

View File

@@ -137,10 +137,6 @@ type FileTransmissionCommand struct {
Data []byte `json:"d,omitempty"`
}
func escape_semicolons(x string) string {
return strings.ReplaceAll(x, ";", ";;")
}
var ftc_field_map = sync.OnceValue(func() map[string]reflect.StructField {
ans := make(map[string]reflect.StructField)
self := FileTransmissionCommand{}
@@ -239,10 +235,10 @@ func NewFileTransmissionCommand(serialized string) (ans *FileTransmissionCommand
return
}
field_map := ftc_field_map()
key_length, key_start, val_start, val_length := 0, 0, 0, 0
key_length, key_start, val_start := 0, 0, 0
handle_value := func(key, serialized_val string) error {
key = strings.TrimLeft(key, `;;`)
key = strings.TrimLeft(key, `;`)
if field, ok := field_map[key]; ok {
val := v.FieldByIndex(field.Index)
switch val.Kind() {
@@ -305,7 +301,7 @@ func NewFileTransmissionCommand(serialized string) (ans *FileTransmissionCommand
}
} else {
if ch == ';' {
val_length = i - val_start
val_length := i - val_start
if key_length > 0 && val_start > 0 {
err = handle_value(serialized[key_start:key_start+key_length], serialized[val_start:val_start+val_length])
if err != nil {
@@ -315,7 +311,6 @@ func NewFileTransmissionCommand(serialized string) (ans *FileTransmissionCommand
key_length = 0
key_start = i + 1
val_start = 0
val_length = 0
}
}
}

View File

@@ -19,7 +19,6 @@ import (
"kitty/kittens/unicode_input"
"kitty/tools/cli/markup"
"kitty/tools/rsync"
"kitty/tools/tty"
"kitty/tools/tui"
"kitty/tools/tui/loop"
"kitty/tools/utils"
@@ -145,7 +144,6 @@ type remote_file struct {
compression_type Compression
remote_symlink_value string
actual_file output_file
patch_file patch_file
}
func (self *remote_file) close() (err error) {
@@ -176,7 +174,9 @@ func (self *remote_file) Write(data []byte) (n int, err error) {
if self.actual_file == nil {
parent := filepath.Dir(self.expanded_local_path)
if parent != "" {
os.MkdirAll(parent, 0o755)
if err = os.MkdirAll(parent, 0o755); err != nil {
return 0, err
}
}
if self.expect_diff {
if pf, err := new_patch_file(self.expanded_local_path, self.patcher); err != nil {
@@ -263,7 +263,7 @@ func (self *remote_file) apply_metadata() {
}
}
} else {
os.Chmod(self.expanded_local_path, self.permissions)
_ = os.Chmod(self.expanded_local_path, self.permissions)
}
}
@@ -455,8 +455,6 @@ type handler struct {
last_data_write_id loop.IdType
}
var debugprintln = tty.DebugPrintln
func (self *manager) send(c FileTransmissionCommand, send func(string) loop.IdType) loop.IdType {
send(self.prefix)
send(c.Serialize(false))
@@ -486,7 +484,7 @@ func (self *handler) abort_with_error(err error, delay ...time.Duration) {
self.lp.Println(`Waiting to ensure terminal cancels transfer, will quit in no more than`, d)
self.manager.send(FileTransmissionCommand{Action: Action_cancel}, self.lp.QueueWriteString)
self.manager.state = state_canceled
self.lp.AddTimer(d, false, self.do_error_quit)
_, _ = self.lp.AddTimer(d, false, self.do_error_quit)
}
func (self *handler) do_error_quit(loop.IdType) error {
@@ -713,10 +711,12 @@ func files_for_receive(opts *Options, dest string, files []*remote_file, remote_
for spec_id, files_for_spec := range spec_map {
spec := spec_paths[spec_id]
tree := make_tree(files_for_spec, filepath.Dir(expand_home(spec)))
walk_tree(tree, func(x *tree_node) error {
if err = walk_tree(tree, func(x *tree_node) error {
ans = append(ans, x.entry)
return nil
})
}); err != nil {
return nil, err
}
}
} else {
number_of_source_files := 0
@@ -728,10 +728,12 @@ func files_for_receive(opts *Options, dest string, files []*remote_file, remote_
if dest_is_dir {
dest_path := filepath.Join(dest, filepath.Base(files_for_spec[0].remote_path))
tree := make_tree(files_for_spec, filepath.Dir(expand_home(dest_path)))
walk_tree(tree, func(x *tree_node) error {
if err = walk_tree(tree, func(x *tree_node) error {
ans = append(ans, x.entry)
return nil
})
}); err != nil {
return nil, err
}
} else {
f := files_for_spec[0]
f.expanded_local_path = expand_home(dest)
@@ -884,9 +886,13 @@ func (self *handler) on_file_transfer_response(ftc *FileTransmissionCommand) (er
if self.manager.transfer_done {
self.manager.send(FileTransmissionCommand{Action: Action_finish}, self.lp.QueueWriteString)
self.quit_after_write_code = 0
self.refresh_progress(0)
if err = self.refresh_progress(0); err != nil {
return err
}
} else if self.transmit_started {
self.refresh_progress(0)
if err = self.refresh_progress(0); err != nil {
return err
}
}
return
}
@@ -984,7 +990,7 @@ func (self *handler) draw_files() {
if p.total_transferred > 0 {
self.render_progress(`Total`, Progress{
spinner_char: sc, bytes_so_far: p.total_transferred, total_bytes: p.total_bytes_to_transfer,
secs_so_far: time.Now().Sub(p.started_at).Seconds(), is_complete: is_complete,
secs_so_far: time.Since(p.started_at).Seconds(), is_complete: is_complete,
bytes_per_sec: safe_divide(p.transfered_stats_amt, p.transfered_stats_interval.Abs().Seconds()),
})
self.lp.Println()
@@ -1049,11 +1055,15 @@ func (self *handler) on_key_event(ev *loop.KeyEvent) error {
if self.check_paths_printed && !self.transmit_started {
self.abort_with_error(fmt.Errorf(`Canceled by user`))
} else {
self.on_interrupt()
if _, err := self.on_interrupt(); err != nil {
return err
}
}
} else if ev.MatchesPressOrRepeat("ctrl+c") {
ev.Handled = true
self.on_interrupt()
if _, err := self.on_interrupt(); err != nil {
return err
}
}
return nil
}
@@ -1102,7 +1112,7 @@ func receive_loop(opts *Options, spec []string, dest string) (err error, rc int)
lp.OnKeyEvent = handler.on_key_event
lp.OnResize = func(old_sz, new_sz loop.ScreenSize) error {
if handler.progress_drawn {
handler.refresh_progress(0)
return handler.refresh_progress(0)
}
return nil
}

View File

@@ -348,7 +348,7 @@ type SendManager struct {
bypass string
use_rsync bool
file_progress func(*File, int)
file_done func(*File)
file_done func(*File) error
fid_map map[string]*File
all_acknowledged, all_started, has_transmitting, has_rsync bool
active_idx int
@@ -583,7 +583,7 @@ func (self *SendHandler) draw_progress_for_current_file(af *File, spinner_char s
var secs_so_far time.Duration
empty := File{}
if af.done_at == empty.done_at {
secs_so_far = time.Now().Sub(af.transmit_started_at)
secs_so_far = time.Since(af.transmit_started_at)
} else {
secs_so_far = af.done_at.Sub(af.transmit_started_at)
}
@@ -611,7 +611,9 @@ func (self *SendHandler) refresh_progress(timer_id loop.IdType) (err error) {
self.progress_update_timer = 0
}
if self.manager.active_file() == nil && !self.manager.all_acknowledged && self.done_file_ids.Len() != 0 && self.done_file_ids.Len() < len(self.manager.files) {
self.transmit_next_chunk()
if err = self.transmit_next_chunk(); err != nil {
return err
}
}
self.lp.StartAtomicUpdate()
defer self.lp.EndAtomicUpdate()
@@ -633,12 +635,12 @@ func (self *SendHandler) on_file_progress(f *File, change int) {
self.schedule_progress_update(100 * time.Millisecond)
}
func (self *SendHandler) on_file_done(f *File) {
func (self *SendHandler) on_file_done(f *File) error {
self.done_files = append(self.done_files, f)
if f.err_msg != "" {
self.failed_files = append(self.failed_files, f)
}
self.refresh_progress(0)
return self.refresh_progress(0)
}
func (self *SendHandler) send_payload(payload string) loop.IdType {
@@ -743,7 +745,9 @@ func (self *SendManager) on_file_status_update(ftc *FileTransmissionCommand) err
file.err_msg = ftc.Status
}
self.progress_tracker.on_file_done(file)
self.file_done(file)
if err := self.file_done(file); err != nil {
return err
}
if self.active_idx > -1 && file == self.files[self.active_idx] {
self.active_idx = -1
}
@@ -857,8 +861,7 @@ func (self *SendHandler) check_for_transmit_ok() (err error) {
return
}
self.transmit_ok_checked = true
self.start_transfer()
return
return self.start_transfer()
}
func (self *SendHandler) print_check_paths() {
@@ -1083,7 +1086,9 @@ func (self *SendHandler) on_text(text string, from_key_event, in_bracketed_paste
return err
}
if self.manager.all_acknowledged {
self.refresh_progress(0)
if err = self.refresh_progress(0); err != nil {
return err
}
self.transfer_finished()
}
return nil
@@ -1110,7 +1115,7 @@ func (self *SendHandler) abort_transfer(delay ...time.Duration) {
}
self.send_payload(FileTransmissionCommand{Action: Action_cancel}.Serialize())
self.manager.state = SEND_CANCELED
self.lp.AddTimer(d, false, func(loop.IdType) error {
_, _ = self.lp.AddTimer(d, false, func(loop.IdType) error {
self.lp.Quit(1)
return nil
})
@@ -1118,7 +1123,7 @@ func (self *SendHandler) abort_transfer(delay ...time.Duration) {
func (self *SendHandler) on_resize(old_size, new_size loop.ScreenSize) error {
if self.progress_drawn {
self.refresh_progress(0)
return self.refresh_progress(0)
}
return nil
}
@@ -1158,7 +1163,9 @@ func (self *SendHandler) on_writing_finished(msg_id loop.IdType, has_pending_wri
} else {
self.quit_after_write_code = 0
}
self.refresh_progress(0)
if err = self.refresh_progress(0); err != nil {
return err
}
}
if self.quit_after_write_code > -1 && !has_pending_writes {
self.lp.Quit(self.quit_after_write_code)
@@ -1168,7 +1175,9 @@ func (self *SendHandler) on_writing_finished(msg_id loop.IdType, has_pending_wri
return self.check_for_transmit_ok()
}
if chunk_transmitted {
self.refresh_progress(0)
if err = self.refresh_progress(0); err != nil {
return err
}
return self.transmit_next_chunk()
}
return

View File

@@ -10,7 +10,6 @@ in float bg_alpha;
uniform sampler2DArray sprites;
uniform float text_contrast;
uniform float text_gamma_adjustment;
uniform float text_fg_override_threshold;
in float effective_text_alpha;
in vec3 sprite_pos;
in vec3 underline_pos;
@@ -159,7 +158,6 @@ float adjust_alpha_for_incorrect_blending_by_compositor(float text_fg_alpha, flo
// We apply the correction only if there was actual text at this pixel, so as to not make
// background_opacity non-linear
// See https://github.com/kovidgoyal/kitty/issues/6209 for discussion.
const float threshold = 0.000001;
// ans = text_fg_alpha * linear2srgb(final_alpha) + (1 - text_fg_alpha) * final_alpha
return mix(final_alpha, linear2srgb(final_alpha), text_fg_alpha);
}

View File

@@ -214,6 +214,8 @@ class Child:
self.cwd = os.path.abspath(cwd)
self.stdin = stdin
self.env = env or {}
self.is_default_shell = bool(self.argv and self.argv[0] == shell_path)
self.should_run_via_run_shell_kitten = is_macos and self.is_default_shell
def final_env(self) -> Dict[str, str]:
from kitty.options.utils import DELETE_ENV_VAR
@@ -244,7 +246,7 @@ class Child:
if opts.forward_stdio:
env['KITTY_STDIO_FORWARDED'] = '3'
self.unmodified_argv = list(self.argv)
if 'disabled' not in opts.shell_integration:
if not self.should_run_via_run_shell_kitten and 'disabled' not in opts.shell_integration:
from .shell_integration import modify_shell_environ
modify_shell_environ(opts, env, self.argv)
env = {k: v for k, v in env.items() if v is not DELETE_ENV_VAR}
@@ -271,10 +273,10 @@ class Child:
os.set_inheritable(stdin_read_fd, True)
else:
stdin_read_fd = stdin_write_fd = -1
env = tuple(f'{k}={v}' for k, v in self.final_env().items())
final_env = self.final_env()
env = tuple(f'{k}={v}' for k, v in final_env.items())
argv = list(self.argv)
exe = argv[0]
if is_macos and exe == shell_path:
if self.should_run_via_run_shell_kitten:
# bash will only source ~/.bash_profile if it detects it is a login
# shell (see the invocation section of the bash man page), which it
# does if argv[0] is prefixed by a hyphen see
@@ -289,8 +291,19 @@ class Child:
# https://github.com/kovidgoyal/kitty/issues/1870
# xterm, urxvt, konsole and gnome-terminal do not do it in my
# testing.
argv[0] = (f'-{exe.split("/")[-1]}')
self.final_exe = which(exe) or exe
import shlex
ksi = ' '.join(opts.shell_integration)
if ksi == 'invalid':
ksi = 'enabled'
argv = [kitten_exe(), 'run-shell', '--shell', shlex.join(argv), '--shell-integration', ksi]
if is_macos:
# In addition for getlogin() to work we need to run the shell
# via the /usr/bin/login wrapper, sigh.
# https://github.com/kovidgoyal/kitty/issues/6511
import pwd
user = pwd.getpwuid(os.geteuid()).pw_name
argv = ['/usr/bin/login', '-f', '-l', '-p', user] + argv
self.final_exe = which(argv[0]) or argv[0]
self.final_argv0 = argv[0]
pid = fast_data_types.spawn(
self.final_exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd,

View File

@@ -22,7 +22,7 @@ class Version(NamedTuple):
appname: str = 'kitty'
kitty_face = '🐱'
version: Version = Version(0, 30, 0)
version: Version = Version(0, 30, 1)
str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat

View File

@@ -12,12 +12,11 @@ from .child import Child
from .cli import parse_args
from .cli_stub import LaunchCLIOptions
from .clipboard import set_clipboard_string, set_primary_selection
from .constants import shell_path
from .fast_data_types import add_timer, get_boss, get_options, get_os_window_title, patch_color_profiles
from .options.utils import env as parse_env
from .tabs import Tab, TabManager
from .types import OverlayType, run_once
from .utils import cmdline_for_hold, get_editor, log_error, resolve_custom_file, which
from .utils import cmdline_for_hold, get_editor, log_error, resolve_custom_file, resolved_shell, which
from .window import CwdRequest, CwdRequestType, Watchers, Window
try:
@@ -591,7 +590,7 @@ def _launch(
set_primary_selection(stdin)
else:
if opts.hold:
cmd = kw['cmd'] or [shell_path]
cmd = kw['cmd'] or resolved_shell()
if not os.path.isabs(cmd[0]):
cmd[0] = which(cmd[0]) or cmd[0]
kw['cmd'] = cmdline_for_hold(cmd)
@@ -907,6 +906,12 @@ def clone_and_launch(msg: str, window: Window) -> None:
cmdline = []
if not cmdline:
cmdline = list(window.child.argv)
if cmdline and cmdline[0].startswith('-'): # on macOS, run via run-shell kitten
if window.child.is_default_shell:
cmdline = window.child.unmodified_argv
else:
cmdline[0] = cmdline[0][1:]
cmdline[0] = which(cmdline[0]) or cmdline[0]
if cmdline and cmdline[0] == window.child.final_argv0:
cmdline[0] = window.child.final_exe
if cmdline and cmdline == [window.child.final_exe] + window.child.argv[1:]:

View File

@@ -267,7 +267,7 @@ action launch --type=os-window $EDITOR $FILE_PATH
# Open image files with icat
protocol file
mime image/*
action launch --type=os-window kitty +kitten icat --hold $FILE_PATH
action launch --type=os-window kitten icat --hold $FILE_PATH
# Open ssh URLs with ssh command
protocol ssh

View File

@@ -2782,7 +2782,7 @@ The shell program to execute. The default value of :code:`.` means to use
whatever shell is set as the default shell for the current user. Note that on
macOS if you change this, you might need to add :code:`--login` and
:code:`--interactive` to ensure that the shell starts in interactive mode and
reads its startup rc files.
reads its startup rc files. Environment variables are expanded in this setting.
'''
)
@@ -2832,7 +2832,7 @@ Glob patterns can be used too, for example::
To get a list of available actions, run::
kitty @ --help
kitten @ --help
A set of actions to be allowed when no password is sent can be specified by
using an empty password. For example::
@@ -3028,7 +3028,7 @@ jumping to previous prompts, browsing the output of the previous command in a
pager, etc. on supported shells. Set to :code:`disabled` to turn off shell
integration, completely. It is also possible to disable individual features, set
to a space separated list of these values: :code:`no-rc`, :code:`no-cursor`,
:code:`no-title`, :code:`no-cwd`, :code:`no-prompt-mark`, :code:`no-complete`.
:code:`no-title`, :code:`no-cwd`, :code:`no-prompt-mark`, :code:`no-complete`, :code:`no-sudo`.
See :ref:`Shell integration <shell_integration>` for details.
'''
)
@@ -4111,7 +4111,7 @@ This will send "Special text" when you press the :kbd:`Ctrl+Alt+A` key
combination. The text to be sent decodes :link:`ANSI C escapes <https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html>`
so you can use escapes like :code:`\\\\e` to send control codes or :code:`\\\\u21fb` to send
Unicode characters (or you can just input the Unicode characters directly as
UTF-8 text). You can use ``kitty +kitten show_key`` to get the key escape
UTF-8 text). You can use ``kitten show_key`` to get the key escape
codes you want to emulate.
The first argument to :code:`send_text` is the keyboard modes in which to

View File

@@ -863,7 +863,7 @@ def store_multiple(val: str, current_val: Container[str]) -> Iterable[Tuple[str,
yield val, val
allowed_shell_integration_values = frozenset({'enabled', 'disabled', 'no-rc', 'no-cursor', 'no-title', 'no-prompt-mark', 'no-complete', 'no-cwd'})
allowed_shell_integration_values = frozenset({'enabled', 'disabled', 'no-rc', 'no-cursor', 'no-title', 'no-prompt-mark', 'no-complete', 'no-cwd', 'no-sudo'})
def shell_integration(x: str) -> FrozenSet[str]:

View File

@@ -302,9 +302,9 @@ static inline void parse_graphics_code(Screen *screen,
g.payload_sz = sizeof(payload);
if (!base64_decode32(screen->parser_buf + pos, sz, payload,
&g.payload_sz)) {
REPORT_ERROR(
"Failed to parse GraphicsCommand command payload with error: %s",
"output buffer for base64_decode too small");
REPORT_ERROR("Failed to parse GraphicsCommand command payload with "
"error: payload size (%zu) too large",
sz);
return;
}
pos = screen->parser_buf_pos;

View File

@@ -82,7 +82,10 @@ class SharedMemory:
self._name = name
try:
if flags & os.O_CREAT and size:
os.ftruncate(self._fd, size)
if hasattr(os, 'posix_fallocate'):
os.posix_fallocate(self._fd, 0, size)
else:
os.ftruncate(self._fd, size)
self.stats = os.fstat(self._fd)
size = self.stats.st_size
self._mmap = mmap.mmap(self._fd, size, access=mmap.ACCESS_READ if readonly else mmap.ACCESS_WRITE)

View File

@@ -81,6 +81,7 @@ class TabDict(TypedDict):
layout_opts: Dict[str, Any]
enabled_layouts: List[str]
windows: List[WindowDict]
groups: List[Dict[str, Any]]
active_window_history: List[int]
@@ -781,6 +782,9 @@ class Tab: # {{{
is_focused=w.os_window_id == current_focused_os_window_id() and w is active_window,
is_self=w is self_window)
def list_groups(self) -> List[Dict[str, Any]]:
return [g.as_simple_dict() for g in self.windows.groups]
def matches_query(self, field: str, query: str, active_tab_manager: Optional['TabManager'] = None) -> bool:
if field == 'title':
return re.search(query, self.effective_title) is not None
@@ -1036,6 +1040,7 @@ class TabManager: # {{{
'layout_opts': tab.current_layout.layout_opts.serialized(),
'enabled_layouts': tab.enabled_layouts,
'windows': windows,
'groups': tab.list_groups(),
'active_window_history': list(tab.windows.active_window_history),
}

View File

@@ -771,7 +771,19 @@ def resolved_shell(opts: Optional[Options] = None) -> List[str]:
ans = [shell_path]
else:
import shlex
ans = shlex.split(q)
env = {}
if opts is not None:
env['TERM'] = opts.term
if 'SHELL' not in os.environ:
env['SHELL'] = shell_path
if 'HOME' not in os.environ:
env['HOME'] = os.path.expanduser('~')
if 'USER' not in os.environ:
import pwd
env['USER'] = pwd.getpwuid(os.geteuid()).pw_name
def expand(x: str) -> str:
return expandvars(x, env)
ans = list(map(expand, shlex.split(q)))
return ans

View File

@@ -206,6 +206,7 @@ class WindowDict(TypedDict):
lines: int
columns: int
user_vars: Dict[str, str]
at_prompt: bool
class PipeData(TypedDict):
@@ -648,6 +649,7 @@ class Window:
'env': self.child.environ,
'foreground_processes': self.child.foreground_processes,
'is_self': is_self,
'at_prompt': self.at_prompt,
'lines': self.screen.lines,
'columns': self.screen.columns,
'user_vars': self.user_vars,

View File

@@ -91,6 +91,12 @@ class WindowGroup:
'windows': [w.serialize_state() for w in self.windows]
}
def as_simple_dict(self) -> Dict[str, Any]:
return {
'id': self.id,
'windows': [w.id for w in self.windows],
}
def decoration(self, which: EdgeLiteral, border_mult: int = 1, is_single_window: bool = False) -> int:
if not self.windows:
return 0

View File

@@ -1383,6 +1383,7 @@ def macos_info_plist() -> bytes:
# Security
NSAppleEventsUsageDescription=access('AppleScript.'),
NSSystemAdministrationUsageDescription=access('elevated privileges.', 'requires'),
NSBluetoothAlwaysUsageDescription=access('Bluetooth.'),
# Speech
NSSpeechRecognitionUsageDescription=access('speech recognition.'),
)

View File

@@ -75,7 +75,7 @@ fi
# which is not available on older bash
builtin declare -A _ksi_prompt
_ksi_prompt=(
[cursor]='y' [title]='y' [mark]='y' [complete]='y' [cwd]='y' [ps0]='' [ps0_suffix]='' [ps1]='' [ps1_suffix]='' [ps2]=''
[cursor]='y' [title]='y' [mark]='y' [complete]='y' [cwd]='y' [sudo]='y' [ps0]='' [ps0_suffix]='' [ps1]='' [ps1_suffix]='' [ps2]=''
[hostname_prefix]='' [sourced]='y' [last_reported_cwd]=''
)
@@ -89,6 +89,7 @@ _ksi_main() {
"no-prompt-mark") _ksi_prompt[mark]='n';;
"no-complete") _ksi_prompt[complete]='n';;
"no-cwd") _ksi_prompt[cwd]='n';;
"no-sudo") _ksi_prompt[sudo]='n';;
esac
done
IFS="$ifs"
@@ -211,6 +212,11 @@ _ksi_main() {
builtin alias edit-in-kitty="kitten edit-in-kitty"
if [[ "${_ksi_prompt[sudo]}" == "y" ]]; then
# Ensure terminfo is available in sudo
[[ -n "$TERMINFO" ]] && builtin alias sudo="sudo TERMINFO=\"$TERMINFO\""
fi
if [[ "${_ksi_prompt[complete]}" == "y" ]]; then
_ksi_completions() {
builtin local src

View File

@@ -108,6 +108,13 @@ function __ksi_schedule --on-event fish_prompt -d "Setup kitty integration after
__update_cwd_osc
end
if not contains "no-sudo" $_ksi
# Ensure terminfo is available in sudo
if test -n "$TERMINFO"
alias sudo="sudo TERMINFO=\"$TERMINFO\""
end
end
# Handle clone launches
if test -n "$KITTY_IS_CLONE_LAUNCH"
set --local orig_conda_env "$CONDA_DEFAULT_ENV"

View File

@@ -240,6 +240,12 @@ exec_login_shell() {
execute_with_perl
execute_sh_with_posix_env
exec "$login_shell" "-l"
printf "%s\n" "Could not execute the shell $login_shell as a login shell" > /dev/stderr
if [ -e /dev/stderr ]; then
printf "%s\n" "Could not execute the shell $login_shell as a login shell" > /dev/stderr
elif [ -e /dev/fd/2 ]; then
printf "%s\n" "Could not execute the shell $login_shell as a login shell" > /dev/fd/2
else
printf "%s\n" "Could not execute the shell $login_shell as a login shell"
fi
exec "$login_shell"
}

View File

@@ -162,9 +162,10 @@ def compile_terminfo(base):
[tic, '-x', '-o', os.path.join(base, tname), os.path.join(base, '.terminfo', 'kitty.terminfo')],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
output = p.stdout.read()
rc = p.wait()
if rc != 0:
getattr(sys.stderr, 'buffer', sys.stderr).write(p.stdout)
getattr(sys.stderr, 'buffer', sys.stderr).write(output)
raise SystemExit('Failed to compile the terminfo database')

View File

@@ -14,7 +14,17 @@ cleanup_on_bootstrap_exit() {
tdir=""
}
die() { printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr; cleanup_on_bootstrap_exit; exit 1; }
die() {
if [ -e /dev/stderr ]; then
printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr;
elif [ -e /dev/fd/2 ]; then
printf "\033[31m%s\033[m\n\r" "$*" > /dev/fd/2;
else
printf "\033[31m%s\033[m\n\r" "$*";
fi
cleanup_on_bootstrap_exit;
exit 1;
}
python_detected="0"
detect_python() {

View File

@@ -6,7 +6,16 @@
{ \unalias command; \unset -f command; } >/dev/null 2>&1
die() { printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr; exit 1; }
die() {
if [ -e /dev/stderr ]; then
printf "\033[31m%s\033[m\n\r" "$*" > /dev/stderr;
elif [ -e /dev/fd/2 ]; then
printf "\033[31m%s\033[m\n\r" "$*" > /dev/fd/2;
else
printf "\033[31m%s\033[m\n\r" "$*";
fi
exit 1;
}
exec_kitty() {
[ -n "$kitty_exe" ] && exec "$kitty_exe" "$@"
@@ -63,7 +72,7 @@ case "$(command uname -m)" in
amd64|x86_64) arch="amd64";;
aarch64*) arch="arm64";;
armv8*) arch="arm64";;
arm) arch="arm";;
arm|armv7l) arch="arm";;
i386) arch="386";;
i686) arch="386";;
*) die "Unknown CPU architecture $(command uname -m)";;

View File

@@ -84,7 +84,7 @@ precmd_functions+=(_ksi_deferred_init)
_ksi_deferred_init() {
builtin emulate -L zsh -o no_warn_create_global -o no_aliases
# Recognized options: no-cursor, no-title, no-prompt-mark, no-complete, no-cwd.
# Recognized options: no-cursor, no-title, no-prompt-mark, no-complete, no-cwd, no-sudo.
builtin local -a opt
opt=(${(s: :)KITTY_SHELL_INTEGRATION})
builtin unset KITTY_SHELL_INTEGRATION
@@ -388,6 +388,11 @@ _ksi_deferred_init() {
builtin alias edit-in-kitty="kitten edit-in-kitty"
if (( ! opt[(Ie)no-sudo] )); then
# Ensure terminfo is available in sudo
[[ -n "$TERMINFO" ]] && builtin alias sudo="sudo TERMINFO=\"$TERMINFO\""
fi
# Map alt+left/right to move by word if not already mapped. This is expected behavior on macOS and I am tired
# of answering questions about it.
[[ $(builtin bindkey "^[[1;3C") == *" undefined-key" ]] && builtin bindkey "^[[1;3C" "forward-word"

View File

@@ -19,6 +19,7 @@ type Options struct {
Shell string
ShellIntegration string
Env []string
Cwd string
}
func main(args []string, opts *Options) (rc int, err error) {
@@ -53,7 +54,7 @@ func main(args []string, opts *Options) (rc int, err error) {
os.Setenv("TERMINFO_DIRS", terminfo_dir+existing)
}
}
err = tui.RunShell(tui.ResolveShell(opts.Shell), tui.ResolveShellIntegration(opts.ShellIntegration))
err = tui.RunShell(tui.ResolveShell(opts.Shell), tui.ResolveShellIntegration(opts.ShellIntegration), opts.Cwd)
if changed {
os.Clearenv()
for _, entry := range env_before {
@@ -96,5 +97,10 @@ func EntryPoint(root *cli.Command) *cli.Command {
Help: "Specify an env var to set before running the shell. Of the form KEY=VAL. Can be specified multiple times. If no = is present KEY is unset.",
Type: "list",
})
sc.Add(cli.OptionSpec{
Name: "--cwd",
Help: "The working directory to use when executing the shell.",
})
return sc
}

View File

@@ -51,7 +51,9 @@ globin
if err != nil {
t.Fatal(err)
}
err = p.ParseOverrides("over one", "over two")
if err = p.ParseOverrides("over one", "over two"); err != nil {
t.Fatal(err)
}
diff := cmp.Diff([]string{"a one", "incb cool", "b ", "inc1 cool", "inc2 cool", "env cool", "inc notcool", "over one", "over two"}, parsed_lines)
if diff != "" {
t.Fatalf("Unexpected parsed config values:\n%s", diff)

View File

@@ -293,12 +293,8 @@ func (r *rsync) ApplyDelta(output io.Writer, target io.ReadSeeker, op Operation)
if _, err = target.Seek(int64(r.BlockSize*int(op.BlockIndex)), io.SeekStart); err != nil {
return err
}
n, err = io.ReadAtLeast(target, buffer, r.BlockSize)
if err != nil {
if err != io.ErrUnexpectedEOF {
return err
}
err = nil
if n, err = io.ReadAtLeast(target, buffer, r.BlockSize); err != nil && err != io.ErrUnexpectedEOF {
return err
}
block = buffer[:n]
return write(block)

View File

@@ -336,7 +336,9 @@ func set_comment_in_zip_file(path string, comment string) error {
defer src.Close()
buf := bytes.Buffer{}
dest := zip.NewWriter(&buf)
dest.SetComment(comment)
if err = dest.SetComment(comment); err != nil {
return err
}
for _, sf := range src.File {
err = dest.Copy(sf)
if err != nil {
@@ -344,8 +346,7 @@ func set_comment_in_zip_file(path string, comment string) error {
}
}
dest.Close()
utils.AtomicUpdateFile(path, buf.Bytes(), 0o644)
return nil
return utils.AtomicUpdateFile(path, buf.Bytes(), 0o644)
}
func fetch_cached(name, url, cache_path string, max_cache_age time.Duration) (string, error) {
@@ -358,15 +359,16 @@ func fetch_cached(name, url, cache_path string, max_cache_age time.Duration) (st
var jm JSONMetadata
if err == nil {
defer zf.Close()
err = json.Unmarshal(utils.UnsafeStringToBytes(zf.Comment), &jm)
if max_cache_age < 0 {
return cache_path, nil
}
cache_age, err := utils.ISO8601Parse(jm.Timestamp)
if err == nil {
if time.Now().Before(cache_age.Add(max_cache_age)) {
if err = json.Unmarshal(utils.UnsafeStringToBytes(zf.Comment), &jm); err == nil {
if max_cache_age < 0 {
return cache_path, nil
}
cache_age, err := utils.ISO8601Parse(jm.Timestamp)
if err == nil {
if time.Now().Before(cache_age.Add(max_cache_age)) {
return cache_path, nil
}
}
}
}
if max_cache_age < 0 {
@@ -429,7 +431,9 @@ func fetch_cached(name, url, cache_path string, max_cache_age time.Duration) (st
jm.Etag = resp.Header.Get("ETag")
jm.Timestamp = utils.ISO8601Format(time.Now())
comment, _ := json.Marshal(jm)
w.SetComment(utils.UnsafeBytesToString(comment))
if err = w.SetComment(utils.UnsafeBytesToString(comment)); err != nil {
return "", err
}
for _, file := range r.File {
err = w.Copy(file)
if err != nil {
@@ -466,8 +470,9 @@ type ThemeMetadata struct {
func ParseThemeMetadata(path string) (*ThemeMetadata, map[string]string, error) {
var in_metadata, in_blurb, finished_metadata bool
ans := ThemeMetadata{}
ans := ThemeMetadata{Is_dark: true} // the default background in kitty is dark
settings := map[string]string{}
read_is_dark := func(key, val string) (err error) {
settings[key] = val
if key == "background" {
@@ -475,7 +480,7 @@ func ParseThemeMetadata(path string) (*ThemeMetadata, map[string]string, error)
if val != "" {
bg, err := style.ParseColor(val)
if err == nil {
ans.Is_dark = utils.Max(bg.Red, bg.Green, bg.Green) < 115
ans.Is_dark = utils.Max(bg.Red, bg.Green, bg.Blue) < 115
}
}
}
@@ -620,7 +625,7 @@ type ReloadDestination string
const (
RELOAD_IN_PARENT ReloadDestination = "parent"
RELOAD_IN_ALL = "all"
RELOAD_IN_ALL ReloadDestination = "all"
)
func reload_config(reload_in ReloadDestination) bool {
@@ -637,7 +642,7 @@ func reload_config(reload_in ReloadDestination) bool {
if all, err := process.Processes(); err == nil {
for _, p := range all {
if c, err := p.CmdlineSlice(); err == nil && is_kitty_gui_cmdline(c...) {
p.SendSignal(unix.SIGUSR1)
_ = p.SendSignal(unix.SIGUSR1)
}
}
return true
@@ -656,7 +661,7 @@ func (self *Theme) SaveInDir(dirpath string) (err error) {
}
func (self *Theme) SaveInConf(config_dir, reload_in, config_file_name string) (err error) {
os.MkdirAll(config_dir, 0o755)
_ = os.MkdirAll(config_dir, 0o755)
path := filepath.Join(config_dir, `current-theme.conf`)
code, err := self.Code()
if err != nil {
@@ -666,7 +671,10 @@ func (self *Theme) SaveInConf(config_dir, reload_in, config_file_name string) (e
if err != nil {
return err
}
confpath := filepath.Join(config_dir, config_file_name)
confpath := config_file_name
if !filepath.IsAbs(config_file_name) {
confpath = filepath.Join(config_dir, config_file_name)
}
if q, err := filepath.EvalSymlinks(confpath); err == nil {
confpath = q
}
@@ -676,7 +684,7 @@ func (self *Theme) SaveInConf(config_dir, reload_in, config_file_name string) (e
}
nraw := patch_conf(utils.UnsafeBytesToString(raw), self.metadata.Name)
if len(raw) > 0 {
os.WriteFile(confpath+".bak", raw, 0o600)
_ = os.WriteFile(confpath+".bak", raw, 0o600)
}
err = utils.AtomicUpdateFile(confpath, utils.UnsafeStringToBytes(nraw), 0o600)
if err != nil {

View File

@@ -35,7 +35,9 @@ func TestThemeCollections(t *testing.T) {
tdir := t.TempDir()
pt := func(expected ThemeMetadata, lines ...string) {
os.WriteFile(filepath.Join(tdir, "temp.conf"), []byte(strings.Join(lines, "\n")), 0o600)
if err := os.WriteFile(filepath.Join(tdir, "temp.conf"), []byte(strings.Join(lines, "\n")), 0o600); err != nil {
t.Fatal(err)
}
actual, _, err := ParseThemeMetadata(filepath.Join(tdir, "temp.conf"))
if err != nil {
t.Fatal(err)
@@ -46,14 +48,16 @@ func TestThemeCollections(t *testing.T) {
}
pt(ThemeMetadata{Name: "XYZ", Blurb: "a b", Author: "A", Is_dark: true, Num_settings: 2},
"# some crap", " ", "## ", "## author: A", "## name: XYZ", "## blurb: a", "## b", "", "color red", "background black", "include inc.conf")
os.WriteFile(filepath.Join(tdir, "inc.conf"), []byte("background white"), 0o600)
if err := os.WriteFile(filepath.Join(tdir, "inc.conf"), []byte("background white"), 0o600); err != nil {
t.Fatal(err)
}
pt(ThemeMetadata{Name: "XYZ", Blurb: "a b", Author: "A", Num_settings: 2},
"# some crap", " ", "## ", "## author: A", "## name: XYZ", "## blurb: a", "## b", "", "color red", "background black", "include inc.conf")
buf := bytes.Buffer{}
zw := zip.NewWriter(&buf)
fw, _ := zw.Create("x/themes.json")
fw.Write([]byte(`[
if _, err := fw.Write([]byte(`[
{
"author": "X Y",
"blurb": "A dark color scheme for the kitty terminal.",
@@ -67,11 +71,17 @@ func TestThemeCollections(t *testing.T) {
{
"name": "Empty", "file": "empty.conf"
}
]`))
]`)); err != nil {
t.Fatal(err)
}
fw, _ = zw.Create("x/empty.conf")
fw.Write([]byte("empty"))
if _, err := fw.Write([]byte("empty")); err != nil {
t.Fatal(err)
}
fw, _ = zw.Create("x/themes/Alabaster_Dark.conf")
fw.Write([]byte("alabaster"))
if _, err := fw.Write([]byte("alabaster")); err != nil {
t.Fatal(err)
}
zw.Close()
received_etag := ""
@@ -91,8 +101,7 @@ func TestThemeCollections(t *testing.T) {
}))
defer ts.Close()
_, err := fetch_cached("test", ts.URL, tdir, 0)
if err != nil {
if _, err := fetch_cached("test", ts.URL, tdir, 0); err != nil {
t.Fatal(err)
}
r, err := zip.OpenReader(filepath.Join(tdir, "test.zip"))

View File

@@ -179,6 +179,9 @@ func (self *Term) set_termios_attrs(when uintptr, modify func(*unix.Termios)) (e
}
func (self *Term) ApplyOperations(when uintptr, operations ...TermiosOperation) (err error) {
if len(operations) == 0 {
return
}
return self.set_termios_attrs(when, func(t *unix.Termios) {
for _, op := range operations {
op(t)
@@ -214,7 +217,7 @@ func (self *Term) Restore() error {
}
func (self *Term) RestoreAndClose() error {
self.Restore()
_ = self.Restore()
return self.Close()
}
@@ -240,7 +243,9 @@ func (self *Term) SuspendAndRun(callback func() error) error {
return err
}
err = callback()
resume()
if rerr := resume(); rerr != nil {
err = rerr
}
return err
}
@@ -323,21 +328,25 @@ func (self *Term) DebugPrintln(a ...any) {
chunk := msg[i:end]
encoded = encoded[:cap(encoded)]
base64.StdEncoding.Encode(encoded, chunk)
self.WriteString("\x1bP@kitty-print|")
self.Write(encoded)
self.WriteString("\x1b\\")
_, _ = self.WriteString("\x1bP@kitty-print|")
_, _ = self.Write(encoded)
_, _ = self.WriteString("\x1b\\")
}
}
func (self *Term) GetSize() (*unix.Winsize, error) {
func GetSize(fd int) (*unix.Winsize, error) {
for {
sz, err := unix.IoctlGetWinsize(self.Fd(), unix.TIOCGWINSZ)
sz, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != unix.EINTR {
return sz, err
}
}
}
func (self *Term) GetSize() (*unix.Winsize, error) {
return GetSize(self.Fd())
}
// go doesn't have a wrapper for ctermid()
func Ctermid() string { return "/dev/tty" }
@@ -363,25 +372,3 @@ func DebugPrintln(a ...any) {
term.DebugPrintln(a...)
}
}
func DrainControllingTTY(wait_for time.Duration) {
tty, err := OpenControllingTerm(SetRaw, SetNoEcho)
if err != nil {
return
}
sel := utils.CreateSelect(1)
sel.RegisterRead(tty.Fd())
for {
n, err := sel.Wait(wait_for)
if err == unix.EINTR {
continue
}
if err != nil {
return
}
if n > 0 && sel.IsReadyToRead(tty.Fd()) {
tty.Read(make([]byte, 256))
}
break
}
}

View File

@@ -183,7 +183,9 @@ func DownloadFileWithProgress(destpath, url string, kill_if_signaled bool) (err
return lp.OnWakeup()
}
lp.AddTimer(rd.spinner.interval, true, on_timer_tick)
if _, err = lp.AddTimer(rd.spinner.interval, true, on_timer_tick); err != nil {
return
}
err = lp.Run()
dl_data.mutex.Lock()
if dl_data.temp_file_path != "" && !dl_data.download_finished {

View File

@@ -39,7 +39,7 @@ func (self *temp_resource) remove() {
self.path = ""
}
if self.mmap != nil {
self.mmap.Unlink()
_ = self.mmap.Unlink()
self.mmap = nil
}
}
@@ -151,7 +151,7 @@ func (self *ImageCollection) ResizeForPageSize(width, height int) {
func (self *ImageCollection) DeleteAllVisiblePlacements(lp *loop.Loop) {
g := self.new_graphics_command()
g.SetAction(GRT_action_delete).SetDelete(GRT_delete_visible)
g.WriteWithPayloadToLoop(lp, nil)
_ = g.WriteWithPayloadToLoop(lp, nil)
}
func (self *ImageCollection) PlaceImageSubRect(lp *loop.Loop, key string, page_size Size, left, top, width, height int) {
@@ -179,7 +179,7 @@ func (self *ImageCollection) PlaceImageSubRect(lp *loop.Loop, key string, page_s
gc := self.new_graphics_command()
gc.SetAction(GRT_action_display).SetLeftEdge(uint64(left)).SetTopEdge(uint64(top)).SetWidth(uint64(width)).SetHeight(uint64(height))
gc.SetImageId(r.image_id).SetPlacementId(1).SetCursorMovement(GRT_cursor_static)
gc.WriteWithPayloadToLoop(lp, nil)
_ = gc.WriteWithPayloadToLoop(lp, nil)
}
func (self *ImageCollection) Initialize(lp *loop.Loop) {
@@ -193,15 +193,16 @@ func (self *ImageCollection) Initialize(lp *loop.Loop) {
g1 := self.new_graphics_command()
g1.SetTransmission(t).SetAction(GRT_action_query).SetImageId(self.image_id_counter).SetDataWidth(1).SetDataHeight(1).SetFormat(
GRT_format_rgb).SetDataSize(uint64(len(payload)))
g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
_ = g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
return self.image_id_counter
}
tf, err := images.CreateTempInRAM()
if err == nil {
tf.Write([]byte{1, 2, 3})
if _, err = tf.Write([]byte{1, 2, 3}); err == nil {
self.detection_file_id = g(GRT_transmission_tempfile, tf.Name())
self.temp_file_map[self.detection_file_id] = &temp_resource{path: tf.Name()}
}
tf.Close()
self.detection_file_id = g(GRT_transmission_tempfile, tf.Name())
self.temp_file_map[self.detection_file_id] = &temp_resource{path: tf.Name()}
}
sf, err := shm.CreateTemp("icat-", 3)
if err == nil {
@@ -222,7 +223,7 @@ func (self *ImageCollection) Finalize(lp *loop.Loop) {
if r.image_id > 0 {
g := self.new_graphics_command()
g.SetAction(GRT_action_delete).SetDelete(GRT_free_by_id).SetImageId(r.image_id)
g.WriteWithPayloadToLoop(lp, nil)
_ = g.WriteWithPayloadToLoop(lp, nil)
}
}
img.renderings = nil
@@ -333,7 +334,7 @@ func transmit_by_escape_code(lp *loop.Loop, image_id uint32, temp_file_map map[u
atomic := lp.IsAtomicUpdateActive()
lp.EndAtomicUpdate()
gc.SetTransmission(GRT_transmission_direct)
gc.WriteWithPayloadToLoop(lp, frame.Data())
_ = gc.WriteWithPayloadToLoop(lp, frame.Data())
if atomic {
lp.StartAtomicUpdate()
}
@@ -348,7 +349,7 @@ func transmit_by_shm(lp *loop.Loop, image_id uint32, temp_file_map map[uint32]*t
mmap.Close()
temp_file_map[image_id] = &temp_resource{mmap: mmap}
gc.SetTransmission(GRT_transmission_sharedmem)
gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(mmap.Name()))
_ = gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(mmap.Name()))
}
func transmit_by_file(lp *loop.Loop, image_id uint32, temp_file_map map[uint32]*temp_resource, frame *images.ImageFrame, gc *GraphicsCommand) {
@@ -365,7 +366,7 @@ func transmit_by_file(lp *loop.Loop, image_id uint32, temp_file_map map[uint32]*
return
}
gc.SetTransmission(GRT_transmission_tempfile)
gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(f.Name()))
_ = gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(f.Name()))
}
func (self *ImageCollection) transmit_rendering(lp *loop.Loop, r *rendering) {
@@ -411,17 +412,17 @@ func (self *ImageCollection) transmit_rendering(lp *loop.Loop, r *rendering) {
c.SetTargetFrame(uint64(frame.Number))
c.SetGap(int32(frame.Delay_ms))
c.SetNumberOfLoops(1)
c.WriteWithPayloadToLoop(lp, nil)
_ = c.WriteWithPayloadToLoop(lp, nil)
case 1:
c := frame_control_cmd
c.SetAnimationControl(2) // set animation to loading mode
c.WriteWithPayloadToLoop(lp, nil)
_ = c.WriteWithPayloadToLoop(lp, nil)
}
}
}
if is_animated {
c := frame_control_cmd
c.SetAnimationControl(3) // set animation to normal mode
c.WriteWithPayloadToLoop(lp, nil)
_ = c.WriteWithPayloadToLoop(lp, nil)
}
}

View File

@@ -246,7 +246,7 @@ func compress_with_zlib(data []byte) []byte {
var b bytes.Buffer
b.Grow(len(data) + 128)
w := zlib.NewWriter(&b)
w.Write(data)
_, _ = w.Write(data)
w.Close()
return b.Bytes()
}
@@ -254,7 +254,7 @@ func compress_with_zlib(data []byte) []byte {
func (self *GraphicsCommand) AsAPC(payload []byte) string {
buf := strings.Builder{}
buf.Grow(1024)
self.WriteWithPayloadTo(&buf, payload)
_ = self.WriteWithPayloadTo(&buf, payload)
return buf.String()
}
@@ -417,7 +417,7 @@ func GraphicsCommandFromAPCPayload(raw []byte) *GraphicsCommand {
var gc GraphicsCommand
add_key := func(pos int) {
gc.SetString(current_key, utils.UnsafeBytesToString(raw[value_start_at:pos]))
_ = gc.SetString(current_key, utils.UnsafeBytesToString(raw[value_start_at:pos]))
}
for pos, ch := range raw {

View File

@@ -71,7 +71,9 @@ func TestGraphicsCommandSerialization(t *testing.T) {
b.Write(decoded)
r, _ := zlib.NewReader(&b)
o := bytes.Buffer{}
io.Copy(&o, r)
if _, err = io.Copy(&o, r); err != nil {
t.Fatal(err)
}
r.Close()
decoded = o.Bytes()
}
@@ -93,7 +95,7 @@ func TestGraphicsCommandSerialization(t *testing.T) {
test_chunked_payload([]byte("abcd"))
data := make([]byte, 8111)
rand.Read(data)
_, _ = rand.Read(data)
test_chunked_payload(data)
test_chunked_payload([]byte(strings.Repeat("a", 8007)))

View File

@@ -273,7 +273,7 @@ func (self *Loop) Run() (err error) {
defer term.RestoreAndClose()
fmt.Println("Press any key to exit.\r")
buf := make([]byte, 16)
term.Read(buf)
_, _ = term.Read(buf)
}
}
}
@@ -426,10 +426,10 @@ type DefaultColor int
const (
BACKGROUND DefaultColor = 11
FOREGROUND = 10
CURSOR = 12
SELECTION_BG = 17
SELECTION_FG = 19
FOREGROUND DefaultColor = 10
CURSOR DefaultColor = 12
SELECTION_BG DefaultColor = 17
SELECTION_FG DefaultColor = 19
)
func (self *Loop) SetDefaultColor(which DefaultColor, val style.RGBA) {

View File

@@ -128,7 +128,9 @@ func decode_sgr_mouse(text string, screen_size ScreenSize) *MouseEvent {
if len(parts[2]) < 1 {
return nil
}
ans.Pixel.Y, err = strconv.Atoi(parts[2])
if ans.Pixel.Y, err = strconv.Atoi(parts[2]); err != nil {
return nil
}
if last_letter == 'm' {
ans.Event_type = MOUSE_RELEASE
} else if cb&MOTION_INDICATOR != 0 {

View File

@@ -42,7 +42,7 @@ func is_temporary_error(err error) bool {
}
func kill_self(sig unix.Signal) {
unix.Kill(os.Getpid(), sig)
_ = unix.Kill(os.Getpid(), sig)
// Give the signal time to be delivered
time.Sleep(20 * time.Millisecond)
}
@@ -189,10 +189,11 @@ func (self *Loop) handle_rune(raw rune) error {
return nil
}
func (self *Loop) handle_end_of_bracketed_paste() {
func (self *Loop) handle_end_of_bracketed_paste() error {
if self.OnText != nil {
self.OnText("", false, false)
return self.OnText("", false, false)
}
return nil
}
func (self *Loop) on_signal(s unix.Signal) error {
@@ -265,7 +266,7 @@ func (self *Loop) run() (err error) {
signal.Notify(signal_channel, handled_signals...)
defer signal.Reset(handled_signals...)
controlling_term, err := tty.OpenControllingTerm()
controlling_term, err := tty.OpenControllingTerm(tty.SetRaw)
if err != nil {
return err
}
@@ -274,10 +275,6 @@ func (self *Loop) run() (err error) {
controlling_term.RestoreAndClose()
self.controlling_term = nil
}()
err = controlling_term.ApplyOperations(tty.TCSANOW, tty.SetRaw)
if err != nil {
return nil
}
self.keep_going = true
self.pending_mouse_events = utils.NewRingBuffer[MouseEvent](4)
@@ -401,7 +398,7 @@ func (self *Loop) run() (err error) {
return err
}
err = controlling_term.SuspendAndRun(func() error {
unix.Kill(os.Getpid(), unix.SIGSTOP)
_ = unix.Kill(os.Getpid(), unix.SIGSTOP)
time.Sleep(20 * time.Millisecond)
return nil
})

View File

@@ -13,6 +13,7 @@ import (
)
var debugprintln = tty.DebugPrintln
var _ = debugprintln
type timer struct {
interval time.Duration
@@ -27,7 +28,7 @@ func (self *timer) update_deadline(now time.Time) {
}
func (self timer) String() string {
return fmt.Sprintf("Timer(id=%d, callback=%s, deadline=%s, repeats=%v)", self.id, utils.FunctionName(self.callback), self.deadline.Sub(time.Now()), self.repeats)
return fmt.Sprintf("Timer(id=%d, callback=%s, deadline=%s, repeats=%v)", self.id, utils.FunctionName(self.callback), time.Until(self.deadline), self.repeats)
}
func (self *Loop) add_timer(interval time.Duration, repeats bool, callback TimerCallback) (IdType, error) {

View File

@@ -79,7 +79,7 @@ func (self *Loop) wait_for_write_to_complete(sentinel IdType, tty_write_channel
end_time := time.Now().Add(timeout)
for num_sent < len(self.pending_writes) {
timeout = end_time.Sub(time.Now())
timeout = time.Until(end_time)
if timeout <= 0 {
return os.ErrDeadlineExceeded
}
@@ -104,7 +104,7 @@ func (self *Loop) wait_for_write_to_complete(sentinel IdType, tty_write_channel
}
}
for {
timeout = end_time.Sub(time.Now())
timeout = time.Until(end_time)
if timeout <= 0 {
return os.ErrDeadlineExceeded
}

View File

@@ -41,7 +41,7 @@ func read_relevant_kitty_opts(path string) KittyOpts {
return nil
}
cp := config.ConfigParser{LineHandler: handle_line}
cp.ParseFiles(path)
_ = cp.ParseFiles(path)
if ans.Shell == "" {
ans.Shell = kitty.KittyConfigDefaults.Shell
}
@@ -131,10 +131,7 @@ func get_shell_name(argv0 string) (ans string) {
if strings.HasSuffix(strings.ToLower(ans), ".exe") {
ans = ans[:len(ans)-4]
}
if strings.HasPrefix(ans, "-") {
ans = ans[1:]
}
return
return strings.TrimPrefix(ans, "-")
}
func rc_modification_allowed(ksi string) bool {
@@ -147,7 +144,7 @@ func rc_modification_allowed(ksi string) bool {
return ksi != ""
}
func RunShell(shell_cmd []string, shell_integration_env_var_val string) (err error) {
func RunShell(shell_cmd []string, shell_integration_env_var_val, cwd string) (err error) {
shell_name := get_shell_name(shell_cmd[0])
var shell_env map[string]string
if rc_modification_allowed(shell_integration_env_var_val) && shell_integration.IsSupportedShell(shell_name) {
@@ -181,6 +178,9 @@ func RunShell(shell_cmd []string, shell_integration_env_var_val string) (err err
env = os.Environ()
}
// fmt.Println(fmt.Sprintf("%s %v\n%#v", utils.FindExe(exe), shell_cmd, env))
if cwd != "" {
_ = os.Chdir(cwd)
}
return unix.Exec(utils.FindExe(exe), shell_cmd, env)
}
@@ -194,16 +194,19 @@ func RunCommandRestoringTerminalToSaneStateAfter(cmd []string) {
if err == nil {
var state_before unix.Termios
if term.Tcgetattr(&state_before) == nil {
term.WriteString(loop.SAVE_PRIVATE_MODE_VALUES)
if _, err = term.WriteString(loop.SAVE_PRIVATE_MODE_VALUES); err != nil {
fmt.Fprintln(os.Stderr, "failed to write to controlling terminal with error:", err)
return
}
defer func() {
term.WriteString(strings.Join([]string{
_, _ = term.WriteString(strings.Join([]string{
loop.RESTORE_PRIVATE_MODE_VALUES,
"\x1b[=u", // reset kitty keyboard protocol to legacy
"\x1b[1 q", // blinking block cursor
loop.DECTCEM.EscapeCodeToSet(), // cursor visible
"\x1b]112\a", // reset cursor color
}, ""))
term.Tcsetattr(tty.TCSANOW, &state_before)
_ = term.Tcsetattr(tty.TCSANOW, &state_before)
term.Close()
}()
} else {

View File

@@ -324,8 +324,9 @@ func parse_identify_record(ans *IdentifyRecord, raw *IdentifyOutput) (err error)
if found {
ans.Canvas.Left, err = strconv.Atoi(x)
if err == nil {
ans.Canvas.Top, err = strconv.Atoi(y)
ok = true
if ans.Canvas.Top, err = strconv.Atoi(y); err == nil {
ok = true
}
}
}
}
@@ -340,8 +341,9 @@ func parse_identify_record(ans *IdentifyRecord, raw *IdentifyOutput) (err error)
if found {
ans.Width, err = strconv.Atoi(w)
if err == nil {
ans.Height, err = strconv.Atoi(h)
ok = true
if ans.Height, err = strconv.Atoi(h); err == nil {
ok = true
}
}
}
if !ok {
@@ -352,8 +354,9 @@ func parse_identify_record(ans *IdentifyRecord, raw *IdentifyOutput) (err error)
if found {
ans.Dpi.X, err = strconv.ParseFloat(x, 64)
if err == nil {
ans.Dpi.Y, err = strconv.ParseFloat(y, 64)
ok = true
if ans.Dpi.Y, err = strconv.ParseFloat(y, 64); err == nil {
ok = true
}
}
}
if !ok {

View File

@@ -0,0 +1,20 @@
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
package shm
import (
"errors"
"fmt"
"golang.org/x/sys/unix"
)
var _ = fmt.Print
func Fallocate_simple(fd int, size int64) (err error) {
for {
if err = unix.Fallocate(fd, 0, 0, size); !errors.Is(err, unix.EINTR) {
return
}
}
}

View File

@@ -0,0 +1,16 @@
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
//go:build !linux
package shm
import (
"errors"
"fmt"
)
var _ = fmt.Print
func Fallocate_simple(fd int, size int64) (err error) {
return errors.ErrUnsupported
}

View File

@@ -92,16 +92,22 @@ func CreateTemp(pattern string, size uint64) (MMap, error) {
return create_temp(pattern, size)
}
func truncate_or_unlink(ans *os.File, size uint64) (err error) {
for {
err = unix.Ftruncate(int(ans.Fd()), int64(size))
if !errors.Is(err, unix.EINTR) {
break
func truncate_or_unlink(ans *os.File, size uint64, unlink func(string) error) (err error) {
fd := int(ans.Fd())
sz := int64(size)
if err = Fallocate_simple(fd, sz); err != nil {
if !errors.Is(err, errors.ErrUnsupported) {
return fmt.Errorf("fallocate() failed on fd from shm_open(%s) with size: %d with error: %w", ans.Name(), size, err)
}
for {
if err = unix.Ftruncate(fd, sz); !errors.Is(err, unix.EINTR) {
break
}
}
}
if err != nil {
ans.Close()
os.Remove(ans.Name())
_ = ans.Close()
_ = unlink(ans.Name())
return fmt.Errorf("Failed to ftruncate() SHM file %s to size: %d with error: %w", ans.Name(), size, err)
}
return
@@ -152,7 +158,7 @@ func ReadWithSizeAndUnlink(name string, file_callback ...func(fs.FileInfo) error
}
defer func() {
mmap.Close()
mmap.Unlink()
_ = mmap.Unlink()
}()
slice, err := ReadWithSize(mmap, 0)
if err != nil {
@@ -164,7 +170,10 @@ func ReadWithSizeAndUnlink(name string, file_callback ...func(fs.FileInfo) error
}
func Read(self MMap, b []byte) (n int, err error) {
pos, _ := self.Seek(0, io.SeekCurrent)
pos, err := self.Seek(0, io.SeekCurrent)
if err != nil {
return 0, err
}
if pos < 0 {
pos = 0
}
@@ -174,7 +183,7 @@ func Read(self MMap, b []byte) (n int, err error) {
return 0, io.EOF
}
n = copy(b, s[pos:])
self.Seek(int64(n), io.SeekCurrent)
_, err = self.Seek(int64(n), io.SeekCurrent)
return
}
@@ -191,7 +200,9 @@ func Write(self MMap, b []byte) (n int, err error) {
return 0, io.ErrShortWrite
}
n = copy(s[pos:], b)
self.Seek(int64(n), io.SeekCurrent)
if _, err = self.Seek(int64(n), io.SeekCurrent); err != nil {
return n, err
}
if n < len(b) {
return n, io.ErrShortWrite
}
@@ -220,7 +231,9 @@ func test_integration_with_python(args []string) (rc int, err error) {
if err != nil {
return 1, err
}
WriteWithSize(mmap, data, 0)
if err = WriteWithSize(mmap, data, 0); err != nil {
return 1, err
}
mmap.Close()
fmt.Println(mmap.Name())
}

View File

@@ -30,7 +30,7 @@ type file_based_mmap struct {
func file_mmap(f *os.File, size uint64, access AccessFlags, truncate bool, special_name string) (MMap, error) {
if truncate {
err := truncate_or_unlink(f, size)
err := truncate_or_unlink(f, size, os.Remove)
if err != nil {
return nil, err
}

View File

@@ -73,15 +73,15 @@ type syscall_based_mmap struct {
func syscall_mmap(f *os.File, size uint64, access AccessFlags, truncate bool) (MMap, error) {
if truncate {
err := truncate_or_unlink(f, size)
err := truncate_or_unlink(f, size, shm_unlink)
if err != nil {
return nil, fmt.Errorf("truncate failed with error: %w", err)
}
}
region, err := mmap(int(size), access, int(f.Fd()), 0)
if err != nil {
f.Close()
os.Remove(f.Name())
_ = f.Close()
_ = shm_unlink(f.Name())
return nil, fmt.Errorf("mmap failed with error: %w", err)
}
return &syscall_based_mmap{f: f, region: region}, nil

View File

@@ -16,7 +16,7 @@ var _ = fmt.Print
func TestSHM(t *testing.T) {
data := make([]byte, 13347)
rand.Read(data)
_, _ = rand.Read(data)
mm, err := CreateTemp("test-kitty-shm-", uint64(len(data)))
if err != nil {
t.Fatal(err)

View File

@@ -52,7 +52,7 @@ type EscapeCodeParser struct {
// Callbacks
HandleRune func(rune) error
HandleEndOfBracketedPaste func()
HandleEndOfBracketedPaste func() error
HandleCSI func([]byte) error
HandleOSC func([]byte) error
HandleDCS func([]byte) error
@@ -199,7 +199,9 @@ func (self *EscapeCodeParser) dispatch_char(ch utils.UTF8State) error {
if self.bracketed_paste_buffer[len(self.bracketed_paste_buffer)-1] == '~' {
self.reset_state()
if self.HandleEndOfBracketedPaste != nil {
self.HandleEndOfBracketedPaste()
if err := self.HandleEndOfBracketedPaste(); err != nil {
return err
}
}
}
return nil