Compare commits

..

910 Commits

Author SHA1 Message Date
Kovid Goyal
17e4995e93 version 0.27.1 2023-02-07 16:10:29 +05:30
Kovid Goyal
e161b5a4de Merge branch 'completion' of https://github.com/page-down/kitty 2023-02-04 13:35:58 +05:30
pagedown
52b643b6c6 Completion: Handle kitty +complete setup fish2
Provide the currently supported fish completion script when requesting
version 2.
2023-02-04 15:55:22 +08:00
Kovid Goyal
9bdb647454 kitty @ shell: Fix global options being ignored
Also no need to exec a separate process for every command
2023-02-04 12:54:49 +05:30
Kovid Goyal
0cabc3e109 Indicate when caps lock is on while reading password 2023-02-04 11:06:24 +05:30
Kovid Goyal
d06d6d7646 Add the command that can be used to get the default config file 2023-02-03 19:29:45 +05:30
Kovid Goyal
f1dc072045 Clean up previous PR 2023-02-03 16:14:24 +05:30
Kovid Goyal
9adc474e3c Merge branch 'completion' of https://github.com/page-down/kitty 2023-02-03 16:03:03 +05:30
pagedown
370aa3aaa6 Completion: Delegate kitty +complete to kitten
Implement `kitten __complete__ setup` in Go.
Fix zsh completion script to check `kitten`.
2023-02-03 18:16:04 +08:00
Kovid Goyal
bed4f33be8 Remove unused code 2023-02-03 09:51:54 +05:30
Kovid Goyal
8ce80d8962 Switch to using Go stdlib for ECDH crypto 2023-02-03 09:50:42 +05:30
Kovid Goyal
27ae9104ac Bump required Go version to 1.20
This allows us to use the stdlib for ECDH crypto used by remote control.
Fixes #5976
2023-02-03 09:32:56 +05:30
Kovid Goyal
331f1b7f2b Merge branch 'ksi' of https://github.com/page-down/kitty 2023-02-03 09:30:14 +05:30
pagedown
df1a99a974 Shell integration: More builtin commands 2023-02-03 10:56:19 +08:00
Kovid Goyal
7ea4270c88 ... 2023-02-03 08:02:28 +05:30
Kovid Goyal
a8480a4ca6 Update changelog for previous PR 2023-02-02 17:51:25 +05:30
Kovid Goyal
783bfb2823 Merge branch 'master' of https://github.com/shimt/kitty 2023-02-02 17:50:02 +05:30
Shinichi MOTOKI
a88164e3a2 Fix function key definitions in terminfo/termcap 2023-02-02 20:01:56 +09:00
Kovid Goyal
a7cbe3776d Wayland GNOME: Fix for ibus not working when using XWayland
See 8ce25208c3

I dont know what it is with GNOME. Every single release they break
backward compatibility somewhere, somehow. They must have special
talents.

Fixes #5967
2023-02-02 10:25:33 +05:30
Kovid Goyal
78d0cc40a3 Fix readSelectionFromPasteboard not actually inserting the text 2023-02-02 06:14:34 +05:30
Kovid Goyal
01720a8d4f Fix typo seems to have no actual effect, but... 2023-02-02 06:07:30 +05:30
Kovid Goyal
1d45cf4f91 Use crypto/rand rather than math/rand
Who knows how random math/rand actually is
2023-02-02 06:04:17 +05:30
Kovid Goyal
a9da57d9b3 Forgot to use builtin for alias 2023-02-01 19:27:39 +05:30
Kovid Goyal
a280328731 kitty->kitten typo 2023-02-01 19:11:39 +05:30
Kovid Goyal
17d2315d0c Merge branch 'docs' of https://github.com/page-down/kitty 2023-02-01 19:11:13 +05:30
pagedown
e27920527c Docs: Remove the text role target that is no longer needed 2023-02-01 19:26:38 +08:00
Kovid Goyal
960f5ff065 Merge branch 'docs' of https://github.com/page-down/kitty 2023-02-01 15:46:51 +05:30
pagedown
8fe936882d Docs: Improve usage and help documents for kitten 2023-02-01 17:14:54 +08:00
Kovid Goyal
682428fb54 Optimize the services implementation
Dont construct the selection string when we are merely checking if a
selection exists.
2023-02-01 12:46:19 +05:30
Kovid Goyal
1c6bae636b Only accept service requests when we actually have a selection 2023-02-01 12:17:59 +05:30
Kovid Goyal
c201bac900 ... 2023-02-01 12:17:15 +05:30
Kovid Goyal
5eaa935ede icat: Dont try to further compress PNG images when using stream based transmission 2023-02-01 11:45:01 +05:30
Kovid Goyal
a73f09cf89 Clarify that a=f is needed for chunked transmission of animation frame data 2023-02-01 11:43:15 +05:30
Kovid Goyal
092dc3d01f ... 2023-02-01 11:28:52 +05:30
Kovid Goyal
5c0d477a18 icat kitten: Fix transmission of frame data in direct mode
Sometimes frame data is > 2048 but does not compress smaller, which
broke the if statement checking for first loop.

Fixes #5958
2023-02-01 10:51:59 +05:30
Kovid Goyal
414ca86e3f Remaining fixes from #5962
Fixes #5962
2023-02-01 10:26:53 +05:30
Kovid Goyal
fbbfb25702 Better fix for kitten not being in PATH
Add it to PATH just as we add the kitty dir to PATH. Ensures the correct
kitten is in PATH, corresponding to the correct kitty.
2023-02-01 10:16:50 +05:30
Kovid Goyal
6ea812679f Fix modify_font not working for strikethrough position
Fixes #5946
2023-02-01 08:14:54 +05:30
Kovid Goyal
5a997a5f7a grammar 2023-01-31 21:02:58 +05:30
Kovid Goyal
47641456da Ensure edit-in-kitty works even if kitten is not in PATH
Still needs to be implemented for fish shell
2023-01-31 20:41:39 +05:30
Kovid Goyal
077f71cad5 Another place to update that talks about symlinking to PATH 2023-01-31 20:31:33 +05:30
Kovid Goyal
8f71f6112a Update installation instructions to note that kitty and kitten both need to be added to PATH 2023-01-31 20:29:41 +05:30
Kovid Goyal
8bdd4d0596 ssh kitten: Install kitty bootstrap on systems other than linux/darwin as now we have kitten which works on more types of systems 2023-01-31 20:16:20 +05:30
Kovid Goyal
df45a4e759 Add a note that --detach is not available on macOS 2023-01-31 17:52:36 +05:30
Kovid Goyal
70111d130e version 0.27.0 2023-01-31 10:48:56 +05:30
Kovid Goyal
ce6dacd0d4 Also build 32-bit kitten for Linux 2023-01-31 10:48:56 +05:30
Kovid Goyal
f3c434b7c1 Now that we are releasing 0.27.0 dont need to fetch release version to download latest kitten 2023-01-31 10:48:56 +05:30
Kovid Goyal
54b6344985 Add a note that --spacing is ignored for overlay windows 2023-01-30 12:00:41 +05:30
Kovid Goyal
18fc8dad37 Instead of calling insertText duplicate some of its code so we arent limited in the size of text we can insert 2023-01-29 19:56:53 +05:30
Kovid Goyal
9b5034f904 macOS: Integrate with system services 2023-01-29 19:47:50 +05:30
Kovid Goyal
f2c8819d25 Add an example for displaying a PNG with bash 2023-01-29 10:27:03 +05:30
Kovid Goyal
53482f4c84 Show bad length in base64 decode error message 2023-01-29 10:17:00 +05:30
Kovid Goyal
e1c50cf124 Merge branch 'revert' of https://github.com/page-down/kitty 2023-01-27 21:12:53 +05:30
pagedown
aacb4db2dc Remote control: Improve create-marker error messages
No more missing color errors when text/regex are missing.
Use `mark group` in error messages instead of `color`.
2023-01-27 23:31:06 +08:00
pagedown
8638e42135 Revert "Fix #5937"
This reverts commit 4b322560c3.
Only two arguments are required to create a marker.
2023-01-27 23:15:13 +08:00
Kovid Goyal
4b322560c3 Fix #5937 2023-01-27 15:15:47 +05:30
Kovid Goyal
0a4ad1fe12 Merge branch 'indent' of https://github.com/page-down/kitty 2023-01-27 11:19:54 +05:30
pagedown
907f658fcc ... 2023-01-27 13:40:31 +08:00
pagedown
1e7e10f96f Docs: Fix mixed tab and space indentation in the example code 2023-01-27 13:39:27 +08:00
Kovid Goyal
5338fcdc1e Add a note about why we play with file descriptors 2023-01-26 21:50:10 +05:30
Kovid Goyal
f8991ce3c8 ask kitten: Get readline to work even when stdout is redirected 2023-01-26 21:47:43 +05:30
Kovid Goyal
b408abe304 Move compile_commands.json to build directory 2023-01-26 14:25:22 +05:30
Kovid Goyal
084671b26e Also preread STDIN when using /dev/stdin as the source 2023-01-26 12:57:12 +05:30
Kovid Goyal
1cc69b3edd Move pre-read code into a separate function for clarity 2023-01-26 12:49:21 +05:30
Kovid Goyal
d88105319d clipboard kitten: Allow STDIN to be connected to a program that itself uses the tty directly
Read in STDIN first, and only then start terminal IO, hopefully allowing
the other program to finish its terminal IO before we start.

Fixes #5934
2023-01-26 12:40:08 +05:30
Kovid Goyal
eb50fac8de Add a test for creation of anonymous tempfiles 2023-01-26 11:51:02 +05:30
Kovid Goyal
4185e30d73 Code to more securely create anonymous temp files on Linux 2023-01-26 11:41:01 +05:30
Kovid Goyal
3a126ffa9d Restore permissions check on pwfile
just use RW instead of R as the expected mode
2023-01-26 08:48:35 +05:30
Kovid Goyal
4f5e3f6cf1 Fix ruff invocation in ALE 2023-01-26 08:44:16 +05:30
Kovid Goyal
dd6e206f9b Remove unused import 2023-01-26 08:29:37 +05:30
Kovid Goyal
ea920ffdf9 Merge branch 'master' of https://github.com/schlomie/kitty 2023-01-26 08:21:16 +05:30
Loren Schlomer
366d65f592 Fixes the ssh kitten
kovidgoyal@5e645a7 fixes the password file creation, allowing it to be
unlinked, but read_data_from_shared_memory/1 rejects the shared object
if it is not read only, and will break the ssh kitten for all
platforms.

This change removes the read only check, relying only on the file
ownership check.

This fully fixes #5928

Signed-off-by: Loren Schlomer <me@schlomie.com>
2023-01-25 11:14:12 -08:00
Kovid Goyal
5e645a7be7 Fix ssh kitten not working on FreeBSD
Apparently on FreeBSD one cannot unlink shared mem if it is not created
with write permissions.

Adding IWRITE to the permissions when creating the shared memory is
harmless. It means any process running as the user can either write to
the file or delete it. Deleting was already possible except on FreeBSD.
As for writing, it's needed on FreeBSD for shared memory to be useable
at all, and since processes running as the user can already completely
access all their data, kitty config files, tty pipes, etc. allowing them
to write to the SHM used here doesnt grant any significant new
capability, since they could just write to ssh.conf in the kitty config
folder to get the ssh kitten to do whatever they like.

Fixes #5928
2023-01-25 23:34:31 +05:30
Kovid Goyal
e3040a9c91 Make the various path finding functions thread safe and cache their results 2023-01-25 16:24:27 +05:30
Kovid Goyal
a01d68ed85 ... 2023-01-25 16:12:47 +05:30
Kovid Goyal
f070b17fee Also load ~/.config/kitty/mime.types in Go code 2023-01-25 16:08:12 +05:30
Kovid Goyal
22d562ca41 DRYer 2023-01-25 15:38:23 +05:30
Kovid Goyal
102197fabe Merge branch 'mime-types' of https://github.com/page-down/kitty 2023-01-25 15:28:40 +05:30
pagedown
83f505e209 Update known textual mimes to Python
Also add default aliases for JavaScript and XML in Go.
2023-01-25 16:42:15 +08:00
Kovid Goyal
5a86bc2411 Add default aliases for YAML and TOML 2023-01-25 11:54:09 +05:30
Kovid Goyal
b9c324586e Also recognize a few well known MIME types as being textual 2023-01-24 18:30:46 +05:30
Kovid Goyal
41fb3c79c5 DRYer 2023-01-24 18:26:01 +05:30
Kovid Goyal
5066623089 better fix for file completion in Go
When neither extensions for mime are specified assume we want to match
all files.
2023-01-23 18:01:17 +05:30
Kovid Goyal
8e98b4123e Fix completion for --password-file not completing file names 2023-01-23 17:58:31 +05:30
Kovid Goyal
8f88aab9d2 remove unused code 2023-01-23 17:51:10 +05:30
Kovid Goyal
d8bbb16d5e Make the single instance data type checked 2023-01-23 17:45:11 +05:30
Kovid Goyal
60791bb57b Session files: Expand environment variables 2023-01-23 17:34:53 +05:30
Kovid Goyal
11f98592f7 We still need full keyboard protocol for @ send-text 2023-01-23 16:33:08 +05:30
Kovid Goyal
97467acb1f kitten @ cmd: Dont generate key release events
We dont need them and they sometimes can spill over into the prompt if
the command is very fast.
2023-01-23 16:18:46 +05:30
Kovid Goyal
cc1f0bc3fe Function to drain controlling tty 2023-01-23 16:07:00 +05:30
Kovid Goyal
a009d6b258 kitty shell: Add completion for help and exit commands 2023-01-23 15:34:45 +05:30
Kovid Goyal
0903ae7b4d Do not use prewarming for wrapped kittens 2023-01-23 15:21:04 +05:30
Kovid Goyal
35c1ebd3f9 Merge branch 'fix-open-actions-shell' of https://github.com/page-down/kitty 2023-01-23 14:03:54 +05:30
pagedown
352f940010 Fix SHELL env var in open-actions.conf and launch-actions.conf
Only the executable path is used when expanding `$SHELL`.
Also fix the non-working example `{SHELL}` in the documentation.
2023-01-23 14:15:27 +08:00
Kovid Goyal
1f00c27097 Also create an automatic text/plain alias when reading from clipboard 2023-01-22 22:04:53 +05:30
Kovid Goyal
6b2d37366f Add trailing newline when printing available MIME types 2023-01-22 21:57:17 +05:30
Kovid Goyal
a4075ff041 X11: Fix a crash when listing clipboard MIME types and the clipboard is owned by self
Fixes #5920
2023-01-22 21:19:03 +05:30
Kovid Goyal
7a526d9588 clipboard kitten: When copying, automatically add a text/plain alias if there is at least one text/* MIME and no actual text/plain MIME 2023-01-22 20:41:37 +05:30
Kovid Goyal
5b4e4f032d ask kitten: Output JSON when used standalone 2023-01-22 11:48:51 +05:30
Kovid Goyal
0a1b399447 ... 2023-01-22 08:58:14 +05:30
Kovid Goyal
6a64df1afb Abort show_error kitten if stdin is a tty 2023-01-22 08:48:55 +05:30
Kovid Goyal
dc1851acdb Add some messages to kitten help for kittens that are not meant to be run by end users. 2023-01-22 08:46:29 +05:30
Kovid Goyal
096c1e328e Improve progress printout 2023-01-22 08:41:38 +05:30
Kovid Goyal
1a44c2117b GitHub requires a User-Agent 2023-01-22 08:00:29 +05:30
Kovid Goyal
bd13238d9b Should only return ENOTSUPP if SHM_DIR doesnt exist, not the fil we are trying to open 2023-01-21 17:46:37 +05:30
Kovid Goyal
b1c27d4c2f ... 2023-01-21 17:42:50 +05:30
Kovid Goyal
dc0093cb51 SHM FS: Return a not supported error if SHM_DIR does not exist 2023-01-21 17:40:59 +05:30
Kovid Goyal
b1934ce267 kitten: When guessing MIME types use a builtin list as a fallback, generated from the MIME type definitions available on the build system 2023-01-21 17:35:41 +05:30
Kovid Goyal
16f767de7e Remove unneeded code 2023-01-21 13:20:29 +05:30
Kovid Goyal
93e9332474 Use separate connections for every request to github
GitHub has been flaking out a lot of late with SSL errors when re-using
connections. Also allows us to get rid of the dependency on requests.
2023-01-21 12:56:00 +05:30
Kovid Goyal
81cc09aa61 Increase number of retries when uploading to github as it is getting flakier than ever 2023-01-20 07:11:52 +05:30
Kovid Goyal
e5bc7255b2 ... 2023-01-20 07:07:28 +05:30
Kovid Goyal
75048d56bc ... 2023-01-19 07:54:03 +05:30
Kovid Goyal
19f853c29f Add a note about all the things wrong with modifyOtherKeys 2023-01-18 22:57:56 +05:30
Kovid Goyal
26ca3f9bad Simplify code 2023-01-18 16:16:11 +05:30
Kovid Goyal
bf7d27691c Also add the EINTR fix from previous commit to writing to loop 2023-01-18 16:09:19 +05:30
Kovid Goyal
22532b4805 kitten @: Fix occasional hang until key is pressed while waiting for response from terminal
Fixes #5890
2023-01-18 16:07:42 +05:30
Kovid Goyal
68a006444e Ensure that marking a child for removal works even when the child is still in the queue to be added
Fixes #5895
2023-01-18 15:43:41 +05:30
Kovid Goyal
2d846f53a1 ... 2023-01-18 14:44:40 +05:30
Kovid Goyal
63077e5432 Dont do extremely small reads 2023-01-18 10:13:07 +05:30
Kovid Goyal
5edb1e2d6b micro-optimization 2023-01-18 09:58:29 +05:30
Kovid Goyal
0c7b4df6fc Ensure we are not using iterators when closing 2023-01-18 09:40:31 +05:30
Kovid Goyal
03abbb315a Fix using cursor=none not working on text that has reverse video
Fixes #5897
2023-01-18 09:23:49 +05:30
Kovid Goyal
dc03c14af2 Fix #5896 2023-01-18 08:51:17 +05:30
Kovid Goyal
821f52a748 ... 2023-01-17 12:39:41 +05:30
Kovid Goyal
750f2fa4d0 Use go 1.20 facilities for unsafe string <-> bytes 2023-01-17 12:38:54 +05:30
Kovid Goyal
009fd6418c Fix #5894 2023-01-17 12:05:23 +05:30
Kovid Goyal
ce161e610f ... 2023-01-17 11:52:06 +05:30
Kovid Goyal
b1b9c3704b Merge branch 'patch-2' of https://github.com/eltociear/kitty 2023-01-17 08:38:57 +05:30
Ikko Eltociear Ashimine
fd245e894b Fix typo in overview.rst
specifed -> specified
2023-01-17 12:05:46 +09:00
Kovid Goyal
59170a3627 Add a note to CONTRIBUTING.md about bug management 2023-01-16 17:16:58 +05:30
Kovid Goyal
61143557a9 Re-organize the terminfo FAQ entries into a single one 2023-01-16 16:32:35 +05:30
Kovid Goyal
9a77fdcd04 A new option undercurl_style to control the rendering of undercurls
Fixes #5883
2023-01-16 14:23:10 +05:30
Kovid Goyal
0c8ec3c57b Cleanup previous PR 2023-01-15 13:01:43 +05:30
Jake(Jaehak Song)
b799eba81e Save the overlay when DECTCEM is turned off and restore it when turned on. 2023-01-15 13:01:43 +05:30
Jake(Jaehak Song)
9d1de50bf9 shell.nix: add a missing dependency 'UniformTypeIdentifiers' for macOS 2023-01-15 13:01:43 +05:30
Kovid Goyal
d55a9b582b Use ruff for import sorting 2023-01-15 11:07:10 +05:30
Kovid Goyal
865fc24975 When reporting unused activity in a window, ignore activity that occurs soon after a window resize
Fixes #5881
2023-01-15 09:09:07 +05:30
Kovid Goyal
45b0788f28 Dont rely on existence of sh to report exec failure 2023-01-14 16:03:34 +05:30
Kovid Goyal
bc73273cb3 ... 2023-01-14 15:58:26 +05:30
Kovid Goyal
dd5cfe38b7 Update README 2023-01-14 15:56:03 +05:30
Kovid Goyal
6b8e5ea225 Rename kitty-tool to kitten
It's easier to type, and cuter.

Also, most, if not all of the TUI parts of
kitty's kittens will eventually be re-written into kitten.

The only downside I can see is that we cant tab complete kitty
anymore, but hopefully there will be less reason to run kitty
from the shell as command line tools migrate to kitten.

Meowrrrr!!!
2023-01-14 15:44:52 +05:30
Kovid Goyal
60310ced05 Also build 32-bit ARM kitty-tool for Linux 2023-01-14 11:20:31 +05:30
Kovid Goyal
f61b007645 ... 2023-01-11 11:53:43 +05:30
Kovid Goyal
d4e34a4c31 themes kitten: Nicer error message when no internet connection is present
Fixes #5877
2023-01-11 09:00:58 +05:30
Kovid Goyal
15524ee0fb ... 2023-01-10 19:41:46 +05:30
Kovid Goyal
58a4b4218e ... 2023-01-10 17:35:15 +05:30
Kovid Goyal
ac67d9c72d Allow dumping bytes sent to child for debugging 2023-01-10 15:39:56 +05:30
Kovid Goyal
b9692d480a Allow passing memoryview to paste() 2023-01-10 10:56:03 +05:30
Kovid Goyal
3a2da22509 DRYer 2023-01-10 09:35:15 +05:30
Kovid Goyal
bf8d0c9732 Fix a bug when copying large amounts of text with OSC 52 introduced by the new multi-format clipboard support 2023-01-10 09:29:54 +05:30
Kovid Goyal
836b652f4d Enable checks for unused noqa 2023-01-09 17:28:35 +05:30
Kovid Goyal
69255f7525 broadcast kitten: Allow pressing a key to stop echoing of input into the broadcast window itself 2023-01-09 17:19:35 +05:30
Kovid Goyal
6e41409a3f Dont run isort on generated conf files 2023-01-09 16:51:59 +05:30
Kovid Goyal
7fe5d7b58f Replace isort with ruff 2023-01-09 16:47:42 +05:30
Kovid Goyal
f15d27bb62 Use ruff on CI 2023-01-09 15:55:45 +05:30
Kovid Goyal
a068e3e655 Fix issues reported by ruff 2023-01-09 15:54:41 +05:30
Kovid Goyal
d248d5ad75 Move to pyproject.toml and ruff 2023-01-09 15:49:49 +05:30
Kovid Goyal
44866a6e79 Add sample Go code to get screen size 2023-01-07 15:00:51 +05:30
Kovid Goyal
1fe84f6057 Update icat kitten docs 2023-01-07 14:37:32 +05:30
Kovid Goyal
41207aa830 kitty @ get-colors: Report the current tab bar colors for the active OS window rather than configured values. Fixes #5865 2023-01-07 13:56:36 +05:30
Kovid Goyal
66a2e6f80d ... 2023-01-06 22:06:58 +05:30
Kovid Goyal
397ac36011 Also mention terminal multiplxers can cause graphics to fail 2023-01-06 16:36:39 +05:30
Kovid Goyal
02063a5a6a Make some variables local no need for them to be global 2023-01-06 16:35:17 +05:30
Kovid Goyal
b3926ae9e7 Remove unused code 2023-01-06 16:32:04 +05:30
Kovid Goyal
3743ae50e7 Simplify icat code and write to STDOUT rather than the terminal device
The terminal device is now used only for detection.
2023-01-06 16:16:15 +05:30
Kovid Goyal
2205bf4426 add a comment 2023-01-06 14:42:14 +05:30
Kovid Goyal
def35078d1 ... 2023-01-06 14:26:15 +05:30
Kovid Goyal
1b5fac3189 Cleanup previous PR 2023-01-06 14:25:21 +05:30
Kovid Goyal
dab7f71d2f Merge branch 'master' of https://github.com/TrellixVulnTeam/kitty_864P 2023-01-06 14:17:38 +05:30
TrellixVulnTeam
1223130ef7 Adding tarfile member sanitization to extractall() 2023-01-06 08:07:51 +00:00
Kovid Goyal
4e90ae68a4 ... 2023-01-06 11:33:47 +05:30
Kovid Goyal
e16e3c1582 Clarify the common use case for --config-file-name 2023-01-06 10:42:46 +05:30
Kovid Goyal
ddf36383b4 Dont need to fetch the current version since GitHub provides a redirecting constant download URL 2023-01-05 20:09:32 +05:30
Kovid Goyal
77a3916f6f We need go >= 1.19 2023-01-05 19:41:42 +05:30
Kovid Goyal
5d42d1f955 Remove the old python icat implementation
Keep the python backend code as it is used by the diff kitten to display
image diffs.
2023-01-05 19:34:12 +05:30
Kovid Goyal
a2c68a927e icat: When using --place ensure screen doesnt scroll by leaving cursor at top-left corner of image. 2023-01-05 19:15:13 +05:30
Kovid Goyal
cab7856495 Finish resize handling for the magick engine 2023-01-05 19:15:13 +05:30
Kovid Goyal
c317c934f3 More work on ImageMagick 2023-01-05 19:15:13 +05:30
Kovid Goyal
4d21be9eb5 Port python's shutil.which() 2023-01-05 19:15:13 +05:30
Kovid Goyal
fd71d2035d Start work on rendering with ImageMagick 2023-01-05 19:15:13 +05:30
Kovid Goyal
7ebb281855 Allow controlling num of CPUs for images operations 2023-01-05 19:15:13 +05:30
Kovid Goyal
2d3da1db6d Dont scan all pixels of JPEG images when EXIF rotated to check for opacity 2023-01-05 19:15:13 +05:30
Kovid Goyal
458adf967a Dont use extra memory for mirror operations 2023-01-05 19:15:13 +05:30
Kovid Goyal
eec4c6b802 Dont transmit animation control commands for non-animated images 2023-01-05 19:15:13 +05:30
Kovid Goyal
0b9b207513 Implement scaling for GIF as well 2023-01-05 19:15:13 +05:30
Kovid Goyal
7e8017604e Copy comment explaining min gap and set it to the correct value 2023-01-05 19:15:13 +05:30
Kovid Goyal
520b935cd3 ... 2023-01-05 19:15:12 +05:30
Kovid Goyal
9cb83a6ec2 ... 2023-01-05 19:15:12 +05:30
Kovid Goyal
7c2317d301 Fix divide by zero 2023-01-05 19:15:12 +05:30
Kovid Goyal
7237e5cf9c Get GIF basically working 2023-01-05 19:15:12 +05:30
Kovid Goyal
cd5dab581b DRYer 2023-01-05 19:15:12 +05:30
Kovid Goyal
481cebbd29 Transmission format should be per frame 2023-01-05 19:15:12 +05:30
Kovid Goyal
4623f580b9 Get 24 bit RGB transmission working 2023-01-05 19:15:12 +05:30
Kovid Goyal
6291d0d400 Code to check if an image is Opaque 2023-01-05 19:15:12 +05:30
Kovid Goyal
36d82267bb ... 2023-01-05 19:15:12 +05:30
Kovid Goyal
f9feb4954a Wire up pasting to RGB 2023-01-05 19:15:12 +05:30
Kovid Goyal
d192dcb0d7 Code to convert images to NRGB 2023-01-05 19:15:12 +05:30
Kovid Goyal
143fd6e4dd Start work on transmitting RGB images 2023-01-05 19:15:12 +05:30
Kovid Goyal
df06578c2d Implement --scale-up and --place 2023-01-05 19:15:12 +05:30
Kovid Goyal
73a055fe12 Fix failing test 2023-01-05 19:15:12 +05:30
Kovid Goyal
1fa1a478d9 Get --background working 2023-01-05 19:15:12 +05:30
Kovid Goyal
5a3a547c65 Work on adding support for rendering transforms 2023-01-05 19:15:12 +05:30
Kovid Goyal
373ab95f14 Basic go based rendering 2023-01-05 19:15:11 +05:30
Kovid Goyal
7f866b2b1f Start work on rendering images with Go 2023-01-05 19:15:11 +05:30
Kovid Goyal
24db38ba7e Set data size for SHM transmission as on some platforms the actual SHM size is not equal to the requested size 2023-01-05 19:15:11 +05:30
Kovid Goyal
efdfaaec30 ... 2023-01-05 19:15:11 +05:30
Kovid Goyal
d694f48c91 Get the other two transmission modes working as well 2023-01-05 19:15:11 +05:30
Kovid Goyal
5562a4d52f Get file mode transmission working for unmodified PNG 2023-01-05 19:15:11 +05:30
Kovid Goyal
ce4c71c465 Start work on the transmit backend 2023-01-05 19:15:11 +05:30
Kovid Goyal
31df90a64e Dont allow abort while waiting for query response 2023-01-05 19:15:11 +05:30
Kovid Goyal
22d69d24d0 Fix panic when no timers are left after dispatch 2023-01-05 19:15:11 +05:30
Kovid Goyal
d76e0850ae More work on porting icat 2023-01-05 19:15:11 +05:30
Kovid Goyal
b520882b62 ... 2023-01-05 19:15:11 +05:30
Kovid Goyal
79acab1547 More work on porting icat 2023-01-05 19:15:11 +05:30
Kovid Goyal
4690f3c7c0 ... 2023-01-05 19:15:11 +05:30
Kovid Goyal
cf1d9eb303 Parse more icat cli flags 2023-01-05 19:15:11 +05:30
Kovid Goyal
ba2a3f228d Implement --detect-timeout 2023-01-05 19:15:11 +05:30
Kovid Goyal
a757587ea2 Fix SHM on OpenBSD 2023-01-05 19:15:10 +05:30
Kovid Goyal
ea756db544 Get transmission medium detection working 2023-01-05 19:15:10 +05:30
Kovid Goyal
2d1a2c30bf MMap.Name() should return the SHM name not the full filesystem path 2023-01-05 19:15:10 +05:30
Kovid Goyal
6ace082bc2 Add openbsd and dragonfly support to shm 2023-01-05 19:15:10 +05:30
Kovid Goyal
7e161ea94b Get syscall based SHM working 2023-01-05 19:15:10 +05:30
Kovid Goyal
d01d5297b8 Start work on a SHM implementation in Go 2023-01-05 19:15:10 +05:30
Kovid Goyal
7a1140cd03 Start work on porting icat to Go 2023-01-05 19:15:10 +05:30
Kovid Goyal
aab81c2d32 Turn off hyperlink target display by default
I find it too intrusive for limited benefit. Most the hyperlinks I
click come from trusted programs anyway.
2023-01-05 15:30:43 +05:30
Kovid Goyal
49418c2f53 Show the hyperlink target bar on the top more often than the bottom. This is because the text cursor is usually closer to the bottom. 2023-01-05 15:28:02 +05:30
Kovid Goyal
a548e3eb4d Fix some animations pausing before starting 2023-01-04 11:18:17 +05:30
Kovid Goyal
779a7b7deb ... 2023-01-04 11:15:47 +05:30
Kovid Goyal
c83a8b0773 zsh completion; Fix leading ~ in filenames being quoted on insertion into commandline 2023-01-04 11:07:56 +05:30
Kovid Goyal
035c3de4bb Add completion for file args to clipboard kitten 2023-01-04 10:39:24 +05:30
Kovid Goyal
e2543e8968 Fix #5852 2023-01-04 08:20:04 +05:30
Kovid Goyal
bc2492c212 dont show URL targetbar when mouse is hidden 2023-01-01 12:11:19 +05:30
Kovid Goyal
c03310b5e5 Cleanup previous PR 2022-12-31 14:03:16 +05:30
Kovid Goyal
bd33cef092 Merge branch 'sequence' of https://github.com/ppwwyyxx/kitty 2022-12-31 13:38:37 +05:30
Yuxin Wu
832506d785 move is_modifier_key to glfw.c and expose in Python 2022-12-30 23:32:46 -08:00
Yuxin Wu
13b09346b9 reset current window after processing sequence 2022-12-30 23:07:50 -08:00
Yuxin Wu
1c10c5fcc4 replay modifier key as well 2022-12-30 23:07:50 -08:00
Yuxin Wu
510c5bd73b handle release 2022-12-30 23:07:49 -08:00
Yuxin Wu
774fdd7e94 Send sequence events to child if they don't match kitty. 2022-12-30 23:07:36 -08:00
Kovid Goyal
58497161c0 X11: When pasting text/plain try UTF8_STRING first then text/plain/charset=utf-8
Fixes #5842
Also fixes pasting from GTK+2 applications like leafpad.
2022-12-30 22:20:43 +05:30
Kovid Goyal
f831c34813 Update the FAQ on vim with a comprehensive set of settings needed to get it to work with modern terminals 2022-12-30 13:52:08 +05:30
Kovid Goyal
456af90ad2 Remote control: Allow matching for self window even over sockets when run inside a kitty window
Have kitty-tool send the value of KITTY_WINDOW_ID if present.
2022-12-30 12:17:31 +05:30
Kovid Goyal
c18bff7821 Remote control: Allow matching the parent of an overlay window 2022-12-30 11:29:05 +05:30
Kovid Goyal
080d1bf935 Fox object lifetime management 2022-12-30 10:08:49 +05:30
Kovid Goyal
4f9ed6546a Pass key events mapped to scroll actions to the program running in the terminal when the terminal is in alternate screen mode
Fixes #5839
2022-12-30 08:54:31 +05:30
Kovid Goyal
c76bbeabd6 ... 2022-12-30 08:34:58 +05:30
Kovid Goyal
0f24ce60f8 Fix @ send-text --stdin always assuming STDIN is a tty 2022-12-30 08:29:30 +05:30
Kovid Goyal
6a06769931 ... 2022-12-29 17:27:57 +05:30
Kovid Goyal
468b6fab02 Also use sanitized URL for allow_hyperlinks=ask 2022-12-29 17:05:18 +05:30
Kovid Goyal
306f9e5735 Prettify URLs before displaying them to the user 2022-12-29 17:04:02 +05:30
Kovid Goyal
f4ac03b791 Show the target of terminal hyperlinks when hovering over them with the mouse
Fixes #5830
2022-12-29 16:43:45 +05:30
Kovid Goyal
b8abdd2b50 Retry failed deletes from github 2022-12-29 12:50:16 +05:30
Kovid Goyal
e673747ef4 readline: add alt+arrow to move by word default binding. Common on macOS 2022-12-27 10:59:13 +05:30
Kovid Goyal
6e4376e44e A few more wrapping serialization tests 2022-12-27 09:11:15 +05:30
Kovid Goyal
f6801d48d1 Add a test to ensure \n does not change wrapping status 2022-12-27 08:48:26 +05:30
Kovid Goyal
ca57198927 Merge branch 'patch-1' of https://github.com/eltociear/kitty 2022-12-26 21:00:33 +05:30
Ikko Ashimine
e78000c879 Fix typo in iqsort.h
comparision -> comparison
2022-12-27 00:27:16 +09:00
Kovid Goyal
68cf9f7514 Switch to tracking linewrap on the last cell in a line
This allows us to have newline not affect the wrap status of a line.

Now a lines wrapping status is changed only when the last cell
in the line is changed. This actually matches the behavior of many other
terminal emulators so is probably a good thing from a ecosystem
compatibility perspective.

The fish shell expects this weird behavior of newline not changing
wrapping status, for unknown reasons, which is the actual motivation for
doing all this work.

Fixes #5766
2022-12-26 20:26:21 +05:30
Kovid Goyal
4556f5b8f1 Merge branch 'pr-fix-image-scrolling' of https://github.com/sergei-grechanik/kitty 2022-12-26 09:51:22 +05:30
Sergei Grechanik
32d8aac808 Fix scrolling images within margins
This commit fixes an off-by-one error in image scrolling that caused
images to not be scrolled or to be cropped at the wrong line.
2022-12-25 15:34:54 -08:00
Kovid Goyal
2e81d00c92 make go fmt happy 2022-12-24 10:53:17 +05:30
Kovid Goyal
cd92d50a0d Keyboard protocol: Remove CSI R from the allowed encodings of the F3 key as it conflicts with the *Cursor Position Report* escape code 2022-12-24 10:32:28 +05:30
Kovid Goyal
155dd426c5 Merge branch 'ssh-kitten' of https://github.com/page-down/kitty 2022-12-24 10:04:58 +05:30
pagedown
a8f2816ac2 ssh kitten: Compile terminfo with tic coming from pkgsrc under NetBSD 2022-12-24 11:53:52 +08:00
pagedown
0ddc5d030c ssh kitten: Fall back to using openssl when base64 does not exist 2022-12-24 11:53:45 +08:00
Kovid Goyal
a2c2d81373 Cleanup readline prompt rendering 2022-12-23 15:23:42 +05:30
Kovid Goyal
307ce1cf87 Remove not needed wrapper function since now we use a struct to set attrs 2022-12-23 13:50:55 +05:30
Kovid Goyal
61ceb12e07 Merge branch 'singlekey-endian' of https://github.com/jamessan/kitty
Fixes #5802
2022-12-23 08:12:23 +05:30
James McCoy
b45dc20693 Define SingleKey bitfields according to endianness
Closes #5802
2022-12-22 15:07:54 -05:00
Kovid Goyal
bcedbe5ec1 Revert "Change the terminfo entry for cud1 to not alter text to comply with the terminfo man page"
This reverts commit d8284befd3.
See https://github.com/kovidgoyal/kitty/issues/5766#issuecomment-1363025173
2022-12-22 21:49:32 +05:30
Kovid Goyal
038639e2d3 Bump bundled zlib 2022-12-22 19:26:34 +05:30
Kovid Goyal
c857492f37 Merge pull request #5803 from jamessan/runtime-dir
tests: Use tempdir for XDG_RUNTIME_DIR
2022-12-22 11:07:44 +05:30
Kovid Goyal
42923ab673 ... 2022-12-22 10:19:34 +05:30
James McCoy
9afd0309fc tests: Use tempdir for XDG_RUNTIME_DIR 2022-12-21 22:21:48 -05:00
Kovid Goyal
b9d098de2d Update mpv support link to point to the actual merged commit 2022-12-22 07:16:53 +05:30
Kovid Goyal
09e6f740de Merge branch 'macos-shortcuts' of https://github.com/page-down/kitty 2022-12-21 16:41:43 +05:30
pagedown
1023084eb9 macOS: Allow to customize Hide, Minimize, and Quit global menu shortcuts
All previously hard-coded shortcuts under macOS can be configured now.
2022-12-20 21:08:26 +08:00
Kovid Goyal
aa9679e56b Fix typo in key definition 2022-12-20 15:01:40 +05:30
Kovid Goyal
d8284befd3 Change the terminfo entry for cud1 to not alter text to comply with the terminfo man page
Fixes #5766
2022-12-20 09:16:05 +05:30
Kovid Goyal
e4ee2cf995 Move the alt+left/right binding into zsh integration
It works OOTB in bash and fish already.
2022-12-19 11:25:12 +05:30
Kovid Goyal
e3f6f47f10 ... 2022-12-19 05:35:18 +05:30
Kovid Goyal
e5941b1b44 Add a link for the vim t_ut issue 2022-12-18 22:32:20 +05:30
Kovid Goyal
65c64d8745 macOS: Bind :kbd:option+left and :kbd:option+right to :kbd:alt+b and :kbd:alt+f. This mimics the default bindings in Terminal.app
Fixes #5793
2022-12-18 20:34:42 +05:30
Kovid Goyal
40093a4702 Add tests for GraphicsCommand serialization 2022-12-18 11:56:30 +05:30
Kovid Goyal
3815cba8f3 Add stringer interface to GraphicsCommand 2022-12-17 15:34:43 +05:30
Kovid Goyal
7410cd62f9 remove unused code 2022-12-17 09:00:44 +05:30
Kovid Goyal
ae0a8e73d2 ... 2022-12-17 08:59:56 +05:30
Kovid Goyal
8f3a8c828f Add an APC to GraphicsCommand parser 2022-12-16 21:05:17 +05:30
Kovid Goyal
6efb5dc2c2 Auto-create an OS Window if none exists on new_tab 2022-12-16 19:34:37 +05:30
Kovid Goyal
bb33f6c0ac Start work on graphics support in kitty-tool 2022-12-16 18:06:52 +05:30
Kovid Goyal
d34284ee1c Merge branch 'docs' of https://github.com/page-down/kitty 2022-12-16 13:06:20 +05:30
pagedown
74cae7b787 ... 2022-12-16 14:27:02 +08:00
Kovid Goyal
c6360537e5 Try to fix tests failing on Python 3.11 2022-12-16 10:05:05 +05:30
Kovid Goyal
7d28d7413f Merge branch 'patch-1' of https://github.com/lodisy/kitty 2022-12-16 09:41:10 +05:30
Michael
d3f3e9ec38 docs: fix overview.rst
add missing `be`, L88
2022-12-16 12:06:25 +08:00
Kovid Goyal
928becece4 Fix #5773 2022-12-14 15:45:43 +05:30
Kovid Goyal
80db167abb Add mpv to the list of things that speak the graphics protocol 2022-12-14 10:31:56 +05:30
Kovid Goyal
a5a6880a19 Respect enable_audio_bell when a layout action fails 2022-12-14 06:53:14 +05:30
Kovid Goyal
da13d03b98 Merge branch 'rc-launch' of https://github.com/page-down/kitty 2022-12-13 20:32:20 +05:30
pagedown
0a5c409a12 Remote control: Add the missing option value overlay-main 2022-12-13 22:48:46 +08:00
Kovid Goyal
eeb772ad07 @launch: When an overlay window is specified in a particular tab via --match use the active window of that tab as the base, not the current tab. Fixes #5768 2022-12-13 20:15:21 +05:30
Kovid Goyal
2b66775f45 explicitly ignore a few errors 2022-12-13 16:19:46 +05:30
Kovid Goyal
3f65ce0e71 Make sizes explicit in a few reallocs 2022-12-13 12:11:37 +05:30
Kovid Goyal
d235b673d1 also test \ is escaped 2022-12-13 10:21:19 +05:30
Kovid Goyal
0ab618c2dc Fix #5767 2022-12-13 10:20:02 +05:30
Kovid Goyal
fefafda9a0 Fix #5764 2022-12-12 21:26:54 +05:30
Kovid Goyal
902373ed20 Also make lists and dicts of strings escape code safe 2022-12-12 19:24:44 +05:30
Kovid Goyal
aac57550c9 rc protocol: Encode strings values in an escape code safe way
Go emits UTF-8 encoded JSON not ascii encoded JSON. Still need to fix
lists and dicts of strings
2022-12-12 18:48:54 +05:30
Kovid Goyal
95e05ce9ec Fix #5761 2022-12-12 16:49:18 +05:30
Kovid Goyal
b6c6316b7b Merge branch 'rc-ls' of https://github.com/page-down/kitty 2022-12-12 10:32:51 +05:30
pagedown
91576cc42f Remote control: Keep the same naming style for ls command output 2022-12-12 12:53:58 +08:00
Kovid Goyal
032e01ebf7 ... 2022-12-11 20:55:06 +05:30
Kovid Goyal
bd70100e09 Fix typo in FAQ 2022-12-10 13:00:09 +05:30
Kovid Goyal
ff6d2e3c10 Merge branch 'kitten-hyperlink-grep' of https://github.com/page-down/kitty 2022-12-10 12:58:57 +05:30
pagedown
2f292bb5d2 DRYer 2022-12-10 15:13:19 +08:00
pagedown
52cf443daf Docs: rg --no-heading has been handled 2022-12-10 15:12:32 +08:00
Kovid Goyal
f03a665e09 Remote control: When matching windows allow using negative id numbers to match recently created windows
Fixes #5753
2022-12-10 11:17:55 +05:30
Kovid Goyal
66e7919171 Add a FAQ entry about not being able to use a keybinding in a terminal program
I am tired of people asking this same question endlessly. At least now I
can just point them to this link.
2022-12-08 14:16:01 +05:30
Kovid Goyal
1289dd2ff0 Cleanup previous PR 2022-12-08 13:30:54 +05:30
Kovid Goyal
fa50e0d6cc Merge branch 'kitten-hyperlinked-grep' of https://github.com/page-down/kitty 2022-12-08 13:26:28 +05:30
pagedown
8c7a5288ae hyperlinked_grep kitten: Handle more rg command line options
Skip for unsupported options.
2022-12-08 14:51:13 +08:00
Kovid Goyal
7fe5c79d53 Also mask signals when SIGNALFD is not available
This makes behavior across platforms consistent.
Fixes #4636
2022-12-07 12:25:14 +05:30
Kovid Goyal
ea5ffa4304 ... 2022-12-07 10:18:15 +05:30
Kovid Goyal
89b32e4545 Update changelog with clipboard kitten new features 2022-12-07 10:04:02 +05:30
Kovid Goyal
879b27a045 ... 2022-12-07 06:48:19 +05:30
Kovid Goyal
9cb0e4d09d Block handled signals early in startup before glfw is initialized to ensure that if the graphics libraries start a thread behind our backs, that threads defaults to haveing the signals blocked unless the library explicitly unblocks them. See #4636 2022-12-07 06:35:18 +05:30
Kovid Goyal
94410f2866 Handle EBUSY as well 2022-12-06 12:20:20 +05:30
Kovid Goyal
a3ba8647ba Document the new OSC 5522 protocol 2022-12-06 12:18:55 +05:30
Kovid Goyal
f35ee1bb40 Fix using primary selection with the extended protocol 2022-12-06 11:15:52 +05:30
Kovid Goyal
23b3b171fa Merge branch 'conf' of https://github.com/page-down/kitty 2022-12-05 17:54:10 +05:30
pagedown
30b25709d2 Fix the base path for envinclude 2022-12-05 14:53:26 +08:00
pagedown
9c488bb877 Docs: Remove extra backslashes from commented config
Update docs to use \e in the example.
2022-12-05 14:27:40 +08:00
Kovid Goyal
14a33dbd94 Put the non-boilerplate functions in their proper place 2022-12-05 08:07:50 +05:30
Kovid Goyal
e37ee422b6 ... 2022-12-05 07:53:30 +05:30
Kovid Goyal
d7d96c2e7b When using the include directive in kitty.conf make the environment variable KITTY_OS available for OS specific config 2022-12-04 21:03:24 +05:30
Kovid Goyal
fda4aa21a1 When drawing the tab bar have the default left and right margins drawn in a color matching the neighboring tab
Fixes #5719
2022-12-04 20:51:41 +05:30
Kovid Goyal
3cbca4955e ... 2022-12-04 20:48:15 +05:30
Kovid Goyal
8e0e70e2d6 Simplify passing colors to the borders shader 2022-12-04 16:08:32 +05:30
Kovid Goyal
7a348d6ef1 Store updated tab bar edge colors on every tab bar redraw 2022-12-04 14:38:56 +05:30
Kovid Goyal
cf8f904720 Function to guess the effective color at the edge of the current screen line 2022-12-04 14:23:21 +05:30
Kovid Goyal
fe53555dba Document the additions to the clipboard kitten 2022-12-04 11:37:02 +05:30
Kovid Goyal
b644a42a48 Allow using wildcard mime types when copying from clipboard 2022-12-03 14:06:16 +05:30
Kovid Goyal
5c9c9a67bc Fix make asan
Suppress leak detection when running gen-go-code.py otherwise it fails
since python always leaks
2022-12-03 12:34:32 +05:30
Kovid Goyal
76f6288e69 ... 2022-12-03 12:25:23 +05:30
Kovid Goyal
6422b323c6 Implement MIME aliases for clipboard 2022-12-03 12:20:03 +05:30
Kovid Goyal
a622a149f6 Allow arbitrary bytes in the mime metadata key 2022-12-03 09:21:36 +05:30
Kovid Goyal
fa6527cdf3 add note about how MIME types are detected 2022-12-03 08:35:58 +05:30
Kovid Goyal
0b293428c4 X11: Fix reading list of available mime types 2022-12-03 08:16:59 +05:30
Kovid Goyal
26e8a5186a Avoid extra roundtrip when only reading clipboard mime types 2022-12-03 08:06:48 +05:30
Kovid Goyal
bde737fa38 Finish implementation of clipboard writing 2022-12-03 08:02:27 +05:30
Kovid Goyal
71e09ba1fb Fix show_key kitten showing incorrect CSI encoding for F3 2022-12-01 23:33:08 +05:30
Kovid Goyal
3e69cf81af DRYer 2022-12-01 22:40:47 +05:30
Kovid Goyal
f5d2c35755 Move implementation of +hold to Go
No need to pay python interpreter startup cost for --hold
2022-12-01 22:34:56 +05:30
Kovid Goyal
38a7fa73e3 Simplify filter mode operation
Dont need channels and goroutines as writing in the loop is already
asnychronous
2022-12-01 19:54:57 +05:30
Kovid Goyal
fdd42d5f19 Implement kitty side write OSC 5522 2022-12-01 18:18:06 +05:30
Kovid Goyal
fe75493c37 Better error messages 2022-12-01 18:17:53 +05:30
Kovid Goyal
e187265d04 Dont truncate the output file just to get tis permission bits 2022-12-01 14:13:28 +05:30
Kovid Goyal
0a985134e2 Ensure permissions are correct when using atomic writes 2022-12-01 14:04:52 +05:30
Kovid Goyal
e555d963b1 DRYer 2022-12-01 13:58:06 +05:30
Kovid Goyal
3601488b26 Add a generic Values() 2022-12-01 13:47:06 +05:30
Kovid Goyal
f29ce19097 Reading arbitrary MIME from clipboard now works 2022-12-01 13:35:44 +05:30
Kovid Goyal
f6ab641b00 Clarify the action of CSI < u in Quickstart 2022-11-30 16:28:34 +05:30
Kovid Goyal
722a1020fa Cleaner implementation of max_tab_title_length
Ensures that tab decorations are not affected
2022-11-29 23:20:39 +05:30
Kovid Goyal
fbd19f3bde Merge branch 'docs' of https://github.com/page-down/kitty 2022-11-29 22:10:57 +05:30
Kovid Goyal
3cf874f6e9 Work on implementing read support in the clipboard kitten 2022-11-29 22:07:51 +05:30
pagedown
02b206eeb8 Docs: Slightly adjust the description of tab_title_max_length
Note the associated GitHub PR ID in the changelog.
2022-11-30 00:20:32 +08:00
Kovid Goyal
5c50e3869c Change the new option to limit tab title lengths to apply to the length of the title, as documented, nit the full tab 2022-11-29 17:41:27 +05:30
Kovid Goyal
6f66bbd424 ... 2022-11-29 15:15:01 +05:30
Kovid Goyal
2697ddaec3 Dont ask for permission when reading only the mime types available in the clipboard 2022-11-29 15:09:01 +05:30
Kovid Goyal
d6dcdf0751 Merge branch 'tab_max_length' of https://github.com/fratajczak/kitty 2022-11-29 14:59:18 +05:30
Kovid Goyal
11724c8a5f Terminal end of OSC 5522 read requests 2022-11-29 14:55:40 +05:30
Ferdinand Ratajczak
b6792a6d71 Add option to limit length of tab titles 2022-11-29 09:50:32 +01:00
Kovid Goyal
f0d61c2de9 Add debug output for key encoding state modifications 2022-11-29 11:20:19 +05:30
Kovid Goyal
35ae689818 Improve debug encoded key output 2022-11-29 08:06:07 +05:30
Kovid Goyal
1305199bdf Output the bytes sent to the child in --debug-input 2022-11-29 07:56:06 +05:30
Kovid Goyal
c62c31f776 More mypy bugs
It cant handle putting a ClipboardTyple fielf on ReadRequest. SO just
use a bool as we really only have two types anyway.
2022-11-28 22:03:04 +05:30
Kovid Goyal
defef3f88c Make mypy happy 2022-11-28 21:05:10 +05:30
Kovid Goyal
3ee9f723f2 The legacy osc 52 protocol now works with the new clipboard requests manager class 2022-11-28 20:53:56 +05:30
Kovid Goyal
a8725d6307 Start work on a new clipboard protocol to allow terminal programs to access more than just text/plain content from the clipboard 2022-11-28 14:23:03 +05:30
Kovid Goyal
4c72f92939 Wayland GNOME: Workaround for latest mutter release breaking full screen for semi-transparent kitty windows
Destroy the CSD surfaces when window goes full screen.
Fixes #5677
2022-11-28 14:19:13 +05:30
Kovid Goyal
2150f261ee Merge branch 'ksi-fish-cwd' of https://github.com/page-down/kitty 2022-11-27 11:46:42 +05:30
pagedown
f720bc9fab Shell integration: Report cwd on the fish prompt event 2022-11-27 14:07:19 +08:00
Kovid Goyal
d92f89e47f ZSH integration: Report cwd on every new prompt draw
Handles the case of a command reporting a different cwd to the terminal.
2022-11-27 10:09:25 +05:30
Kovid Goyal
c54a4021ef Update docs to use \e instead of \x1b for esc since we now support it 2022-11-27 10:06:04 +05:30
Kovid Goyal
375fa73826 Delegate kitty +kitten clipboard to kitty-tool 2022-11-26 20:09:43 +05:30
Kovid Goyal
5eb2142d70 Use a define rather than a generated file for wrapped kittens 2022-11-26 16:16:45 +05:30
Kovid Goyal
00223c5bba Merge branch 'hostname' of https://github.com/page-down/kitty 2022-11-26 15:43:46 +05:30
Kovid Goyal
aa9080d375 Add a note about using single quotes when passing arguments with backslash escapes to send-text
One could of course also use double quotes and escape the backslash or
just escape the backslash but I dont think we need to explain shell
quoting fully here.
2022-11-26 15:38:22 +05:30
Kovid Goyal
8d45f5011b Add support for the 🔗 role to prettify 2022-11-26 15:34:20 +05:30
Kovid Goyal
b3f096b03b kitty shell: Fix pressing enter while cursor is not at end of line causes line to be truncated visually 2022-11-26 15:30:49 +05:30
Kovid Goyal
a721ffeb7d Finish porting clipboard kitten to Go 2022-11-26 15:15:30 +05:30
pagedown
6a1b456bac DRYer: Get hostname 2022-11-26 16:08:40 +08:00
Kovid Goyal
63a08dc6cc kitty-tool @: Fix extra newline being printed when a command returns no response 2022-11-26 05:02:32 +05:30
Kovid Goyal
4969611bdb Handle backslash escapes in :code: blocks 2022-11-25 22:03:13 +05:30
Kovid Goyal
5d3a9f2628 Use base64 for args in old rc code as well 2022-11-25 21:12:59 +05:30
Kovid Goyal
15a7aeff4d Fix kitty-tool @ send-text not processing ANSI escapes 2022-11-25 21:09:51 +05:30
Kovid Goyal
f9a22d0bc7 Port ANSI escape code parser to Go 2022-11-25 21:03:09 +05:30
Kovid Goyal
402c8b6803 Use ANSI C escapes rather than python string literals 2022-11-25 19:10:15 +05:30
Kovid Goyal
ac60715ee2 Merge branch 'docs' of https://github.com/page-down/kitty 2022-11-25 17:34:46 +05:30
Kovid Goyal
cfc6bd4da5 Native code implementation for expanding ANSI escape codes 2022-11-25 17:33:41 +05:30
Kovid Goyal
4d3f3b5e91 Start moving clipboard kitten to kitty-tool 2022-11-25 12:58:10 +05:30
pagedown
55b5a45e27 Docs: Fix missing backslashes 2022-11-25 12:03:34 +08:00
Kovid Goyal
fbce5e7524 Merge branch 'patch-1' of https://github.com/zeertzjq/kitty 2022-11-24 10:16:56 +05:30
zeertzjq
daeb1b6c50 Add note about Vim's support for kitty keyboard protocol 2022-11-24 11:30:40 +08:00
Kovid Goyal
8fb2c209a9 Query for existing assets and then delete 2022-11-23 07:53:14 +05:30
Kovid Goyal
2b676b63b1 sleep defaults to one second 2022-11-22 21:56:10 +05:30
Kovid Goyal
c0d06adcb5 New sleep action
useful in combine based mappings to make kitty sleep before executing the next action
2022-11-22 21:45:19 +05:30
Kovid Goyal
51bba9110e Bash integration: Fix clone-in-kitty not working on bash >= 5.2 if environment variable values contain newlines or other special characters
Bash >= 5.2 changed the export command to output values using $' escaping when they contain special characters.
Fixes #5629
2022-11-22 16:38:24 +05:30
Kovid Goyal
4fc91dcc03 There should be no trailing space when completing directories for a file match based on patterns 2022-11-21 11:05:36 +05:30
Kovid Goyal
3c0667afd6 add some motivation for background_tint_gaps 2022-11-21 10:19:25 +05:30
Kovid Goyal
03dc24f913 Merge branch 'background-tint-gaps' of https://github.com/page-down/kitty 2022-11-21 10:17:36 +05:30
pagedown
73b5857916 Keep two blank lines between each version in the changelog 2022-11-21 12:21:13 +08:00
pagedown
08d74a6c56 Add an option to control background image tinting for window gaps 2022-11-21 12:21:06 +08:00
Kovid Goyal
4290a8f9ba Change the Accept header to current github api recommedation 2022-11-20 07:22:00 +05:30
Kovid Goyal
c6dd6ccc68 Apparently github's deletion api is flakey, retry 2022-11-20 07:18:38 +05:30
Kovid Goyal
fd7cc66689 Increase wait timeout before retry 2022-11-20 07:15:31 +05:30
Kovid Goyal
1c19fc77f1 ... 2022-11-20 06:55:22 +05:30
Kovid Goyal
4080a09748 More upload code cleanup 2022-11-19 11:31:43 +05:30
Kovid Goyal
b91eaa3b2a Cleanup the asset upload code 2022-11-19 11:23:31 +05:30
Kovid Goyal
bdb25831a7 Merge branch 'refactor-cursor-shape' of https://github.com/page-down/kitty 2022-11-19 11:08:17 +05:30
pagedown
a131f9a82e Refactor: Use a consistent name for beam cursor shape 2022-11-19 10:34:50 +08:00
Kovid Goyal
ffefd0f581 Cleanup previous PR 2022-11-18 10:42:06 +05:30
Kovid Goyal
43c0e0f586 Merge branch 'unicode' of https://github.com/page-down/kitty 2022-11-18 10:40:50 +05:30
pagedown
76669ad14d Note the Unicode version in the generated files
Files generated from the same Unicode version will be consistent
regardless of the date they were built.
2022-11-18 13:01:32 +08:00
Kovid Goyal
a9bb341e43 Add an option to control max file size for edit-in-kitty 2022-11-18 10:24:38 +05:30
Kovid Goyal
0757fcc451 Dont fail on github responses without JSON payloads 2022-11-18 10:16:29 +05:30
Kovid Goyal
dd4051bfd5 Allow getting the exe name of the active foreground process in the tab title template 2022-11-17 22:06:06 +05:30
Kovid Goyal
a6dcbe9c1d ... 2022-11-17 20:51:01 +05:30
Kovid Goyal
efaf9faa38 Implement edit-in-kitty using kitty-tool
Fixes #5546
Fixes #5630
2022-11-17 20:48:20 +05:30
Kovid Goyal
36631ddc49 ... 2022-11-17 20:25:35 +05:30
Kovid Goyal
e5e8cc72c6 Make the Unicode database version used available 2022-11-17 20:11:50 +05:30
Kovid Goyal
38547c9e7a Documentation: distinguish between examples and default values for multi-valued options 2022-11-17 17:20:40 +05:30
Kovid Goyal
e00a5ce911 Merge branch 'master' of https://github.com/ppwwyyxx/kitty 2022-11-17 17:06:56 +05:30
Kovid Goyal
0af48a4d05 Start work on implementing edit-in-kitty in kitty-tool 2022-11-17 17:05:25 +05:30
Yuxin Wu
c0d80f9a47 [docs]: don't show config codeblocks that only has a name 2022-11-17 00:05:50 -08:00
Kovid Goyal
d2dabc7d57 ... 2022-11-17 11:10:17 +05:30
Kovid Goyal
81db5eb82f Use nightly to get kitty-tool until 0.27 is released 2022-11-17 11:05:46 +05:30
Kovid Goyal
1addfea261 Avoid an extra HTTP request to set the uploaded file description
Also delete partial asset when receiving 502 errors
2022-11-17 10:44:52 +05:30
Kovid Goyal
e5be31ee14 build in non-interactive mode while publishing 2022-11-17 10:27:53 +05:30
Kovid Goyal
9cef714078 Merge branch 'pr-end-iter' of https://github.com/sergei-grechanik/kitty 2022-11-17 10:03:01 +05:30
Kovid Goyal
a5a4a1bf8f Increase timeout in test 2022-11-17 10:02:44 +05:30
Kovid Goyal
281ad13f6b Retry uploading file to Github 2022-11-17 08:45:26 +05:30
Kovid Goyal
5ad2ac259b When truncating descriptions for completion truncate at word boundaries 2022-11-17 08:29:01 +05:30
Kovid Goyal
a2f022d166 Add support for the repeat escape code to TruncatetoVisualLength() 2022-11-17 08:17:11 +05:30
Sergei Grechanik
4df6c172a3 Define END_ITER to prevent brace imbalance
Otherwise some editors/plugins get confused
2022-11-16 09:54:49 -08:00
Kovid Goyal
9db1d581f7 DRYer 2022-11-16 22:37:27 +05:30
Kovid Goyal
b3bc5a5565 ... 2022-11-16 22:35:59 +05:30
Kovid Goyal
fc20e8d04b Fix spurious EOF error when select for reading from the tty fails with a temporary error 2022-11-16 22:32:35 +05:30
Kovid Goyal
86af1d5c16 Wrap EOF errors when doing terminal I/O 2022-11-16 22:23:00 +05:30
Kovid Goyal
d8574f8f85 Fix another bug in readline cursor position tracking 2022-11-16 21:28:36 +05:30
Kovid Goyal
bdd04f37d6 Better error message for kitty shell when running unknown command 2022-11-16 20:53:08 +05:30
Kovid Goyal
a4e43b3925 Use a pager for the help interactive command as well 2022-11-16 20:44:13 +05:30
Kovid Goyal
5e880b92f5 Ensure active hyperlink is cleared when truncating output for completion descriptions 2022-11-16 20:32:42 +05:30
Kovid Goyal
d4c103e53e zsh breaks when there are escape codes in completion descriptions 2022-11-16 19:32:16 +05:30
Kovid Goyal
3e4df7d812 ... 2022-11-16 19:06:22 +05:30
Kovid Goyal
3b18f90319 Merge branch 'completion' of https://github.com/page-down/kitty 2022-11-16 19:05:58 +05:30
Kovid Goyal
e31587ec1e Ensure auto-generated entries such as --help are present for completion by calling Validate() 2022-11-16 18:05:27 +05:30
pagedown
5dc97af4d5 Add completion for kitty +list-fonts 2022-11-16 20:23:58 +08:00
Kovid Goyal
81916d0f02 Finish implementation of update-self 2022-11-16 17:44:21 +05:30
Kovid Goyal
ae93d95bbe Get progress bar rendering working 2022-11-16 16:35:15 +05:30
Kovid Goyal
dd1fcf6855 Support the repeat prev char escape code when calculating the width of a string 2022-11-16 16:25:16 +05:30
Kovid Goyal
4b05822474 Merge branch 'ksi-completion-fish' of https://github.com/page-down/kitty 2022-11-16 14:00:28 +05:30
Kovid Goyal
337f1fad3f fix double signatures 2022-11-16 13:45:27 +05:30
Kovid Goyal
463c9debe7 More work on update-self 2022-11-16 13:41:58 +05:30
pagedown
9225919112 Fix completion for fish 2022-11-16 16:03:07 +08:00
Kovid Goyal
e70c021371 Some basic TUI widgets ported to Go 2022-11-16 12:48:47 +05:30
Kovid Goyal
f3b3d6c0ef Workaround for mypy bug 2022-11-15 22:47:53 +05:30
Kovid Goyal
0c0b9e6b9c Fix deadlock in update-self 2022-11-15 22:33:23 +05:30
Kovid Goyal
d9215feda5 Allow using the cwd of the original process for launch --cwd
Fixes #5672
2022-11-15 22:18:19 +05:30
Kovid Goyal
d54fe3c16a Start work on a command to self update kitty-tool 2022-11-15 21:29:11 +05:30
Kovid Goyal
36dd5b2d00 More minor loop API additions 2022-11-15 21:00:19 +05:30
Kovid Goyal
87108a18ef Add a callback for wakeups 2022-11-15 18:01:21 +05:30
Kovid Goyal
234274c1df ... 2022-11-15 16:54:14 +05:30
Kovid Goyal
b42677b343 Utility function to download a URL to a file path with progress reporting 2022-11-15 16:53:43 +05:30
Kovid Goyal
c03af4d294 Build static binaries on CI 2022-11-15 15:07:33 +05:30
Kovid Goyal
8d12e60f62 Set a flag available at runtime when cross compiling kitty-tool 2022-11-15 15:04:28 +05:30
Kovid Goyal
5a71b8c209 Merge branch 'macos-custom-icon' of https://github.com/page-down/kitty 2022-11-15 13:28:03 +05:30
Kovid Goyal
16775c5539 ssh kitten: Add a kitty-tool wrapper script to auto-download and use kitty-tool
Needs testing.
2022-11-15 13:26:48 +05:30
pagedown
8b8263d0ff macOS: Failure to set custom app icon should not prevent launch
When running `kitty/launcher/kitty` and no bundle path is provided,
the icon of `kitty/launcher/kitty.app` should be changed instead of
the `launcher` folder.
2022-11-15 15:21:40 +08:00
Kovid Goyal
9ddd7d070e Add a note to changelog about kitty @ speed improvements 2022-11-15 12:05:59 +05:30
Kovid Goyal
780d5400cb Use full kitty-tool exe name in github description 2022-11-15 12:01:55 +05:30
Kovid Goyal
63d7b2a80b Shutdown macOS build VM after building 2022-11-15 11:32:34 +05:30
Kovid Goyal
1958d67847 Sign kitty-tool on macOS 2022-11-15 11:32:12 +05:30
Kovid Goyal
737919505d Update docs to mention kitty-tool 2022-11-14 20:58:24 +05:30
Kovid Goyal
d60ecfa8a6 Install go 1.18 for codeql build 2022-11-14 20:35:41 +05:30
Kovid Goyal
e3b22a87e4 Upload static kitty-tool builds when publishing 2022-11-14 17:07:32 +05:30
Kovid Goyal
c7d47a59f1 When running kitty-tool without arguments show usage 2022-11-14 16:36:05 +05:30
Kovid Goyal
7eae176b88 Code to build static versions of kitty-tool 2022-11-14 16:27:19 +05:30
Kovid Goyal
9361c62a1c Linux: Use a separate thread to play the beep sound
This is because on misconfigured systems canberra hangs while queueing a
sound to play. And these misconfigured systems are quite common in
Linux-land. See for example #5646

Sigh. Even playing a simple sound is failure prone on Linux.
2022-11-14 15:42:09 +05:30
Kovid Goyal
018811c96c Remove unused code
Completion and remote control have moved into kitty-tool
2022-11-14 15:42:09 +05:30
Kovid Goyal
129646c199 Use kitty-tool for all kitty @ incovations 2022-11-14 15:42:09 +05:30
Kovid Goyal
1881f4582e ... 2022-11-14 15:42:09 +05:30
Kovid Goyal
a5d05a2954 ... 2022-11-14 15:42:09 +05:30
Kovid Goyal
59b43ee844 prettify :option:--xyz> better 2022-11-14 15:42:09 +05:30
Kovid Goyal
29bde6c72c Improve formatting of completion entries with descriptions 2022-11-14 15:42:09 +05:30
Kovid Goyal
a7ce642a00 Fix rendering in cells 2022-11-14 15:42:08 +05:30
Kovid Goyal
723a9c91b5 Get completion basically working 2022-11-14 15:42:08 +05:30
Kovid Goyal
9e2c96653f More work on readline completion 2022-11-14 15:42:08 +05:30
Kovid Goyal
4974219e0f Add function to shlex for completion
Also remove the google header since we have diverged from
the original a fair bit. Add a link to the original for credit.
2022-11-14 15:42:08 +05:30
Kovid Goyal
a4de4b7c6f Report stream start position for tokens 2022-11-14 15:42:08 +05:30
Kovid Goyal
eae4899df4 Use a string builder instead of appending to a slice 2022-11-14 15:42:08 +05:30
Kovid Goyal
87b4800fdf Get rid of comment parsing from shlex
POSIX does not define comments
2022-11-14 15:42:08 +05:30
Kovid Goyal
64156fd6e6 Have the shlex tokenizer return space tokens as well 2022-11-14 15:42:08 +05:30
Kovid Goyal
1485981b11 Have the shlex tokenizer track position in stream and return defined error types 2022-11-14 15:42:08 +05:30
Kovid Goyal
8d76cf8d32 Import the google shlex package as we need more sophisticated parsing 2022-11-14 15:42:08 +05:30
Kovid Goyal
7c23536bfe Start work on readline completions 2022-11-14 15:42:08 +05:30
Kovid Goyal
f919efcd42 Move basic multi key shortcut handling into its own package 2022-11-14 15:42:08 +05:30
Kovid Goyal
388e47a2df DRYer 2022-11-14 15:42:08 +05:30
Kovid Goyal
dc787a6529 Allow pretty printing members of the Action enum 2022-11-14 15:42:08 +05:30
Kovid Goyal
cfb6d93dc0 Move cursor to end of input when traversing history list 2022-11-14 15:42:08 +05:30
Kovid Goyal
1523fef000 tests for history searching 2022-11-14 15:42:08 +05:30
Kovid Goyal
31dcb13836 cursor_y should be zero when resetting 2022-11-14 15:42:07 +05:30
Kovid Goyal
0c82832356 more work on history search 2022-11-14 15:42:07 +05:30
Kovid Goyal
ffea66357a Start work on incremental history search 2022-11-14 15:42:07 +05:30
Kovid Goyal
6b48624b81 Reset keyboard state when resetting text 2022-11-14 15:42:07 +05:30
Kovid Goyal
5a425ccaad Implement number args for repeats 2022-11-14 15:42:07 +05:30
Kovid Goyal
2f2dbfb45f Cleanup prompt handling 2022-11-14 15:42:07 +05:30
Kovid Goyal
13a266aa42 Map ctrl+c to abort the current line 2022-11-14 15:42:07 +05:30
Kovid Goyal
67b12159f4 make clean should also clean go caches 2022-11-14 15:42:07 +05:30
Kovid Goyal
8ad55f7562 Add some tests for history 2022-11-14 15:42:07 +05:30
Kovid Goyal
e1ab2383b3 Add basic history operations 2022-11-14 15:42:07 +05:30
Kovid Goyal
f77d07259a Fix mutable default value in dataclass 2022-11-14 15:42:07 +05:30
Kovid Goyal
2e07f90baf ... 2022-11-14 15:42:07 +05:30
Kovid Goyal
8574e136cd Store cwd in history 2022-11-14 15:42:07 +05:30
Kovid Goyal
c8e8cb5ad5 Add some tests for yanking 2022-11-14 15:42:07 +05:30
Kovid Goyal
f127523ae9 Get rid of the unneccessary swap on first configure
Instead use the new flag to indicate the surface should not be committed
till the next swap.
2022-11-14 15:42:07 +05:30
Kovid Goyal
22f7145e34 Add yank actions 2022-11-14 15:42:07 +05:30
Kovid Goyal
1f115870bb Need to install x11-xcb-dev explicitly in jammy 2022-11-14 15:42:06 +05:30
Kovid Goyal
3237db00fc Implement word killing actions 2022-11-14 15:42:06 +05:30
Kovid Goyal
ea583f60b3 Start work on kill ring 2022-11-14 15:42:06 +05:30
Kovid Goyal
b7816d26be Implement clear screen c-l binding 2022-11-14 15:42:06 +05:30
Kovid Goyal
19bf07abd9 Use the more efficient cell iterator api for single char horizontal cursor movement as well 2022-11-14 15:42:06 +05:30
Kovid Goyal
a008c627e3 Implement bindings for moving by simple word 2022-11-14 15:42:06 +05:30
Kovid Goyal
0068ae8f66 An easy to use iterator to iterate over the cells in a string 2022-11-14 15:42:06 +05:30
Kovid Goyal
5436408463 Fix the escape code parser not preserving complete utf-8 state between calls to ParseBytes()
Also allow it to be driven byte-by-byte
2022-11-14 15:42:06 +05:30
Kovid Goyal
d260d2f480 Add some test for vertical movement 2022-11-14 15:42:06 +05:30
Kovid Goyal
00ef9c1955 Implement vertical cursor movement 2022-11-14 15:42:06 +05:30
Kovid Goyal
5509673ff3 More tests 2022-11-14 15:42:06 +05:30
Kovid Goyal
3c4a411cad Rewrite the readline redraw code to make the screen lines explicit 2022-11-14 15:42:06 +05:30
Kovid Goyal
f945ef8ee8 handle ctrl-c better when interrupting go test 2022-11-14 15:42:06 +05:30
Kovid Goyal
260249491d Avoid Querying screen size on every resize 2022-11-14 15:42:05 +05:30
Kovid Goyal
595a78c956 DRYer 2022-11-14 15:42:05 +05:30
Kovid Goyal
cbbf8a2d34 Port output of active window and tab ids at shell startup 2022-11-14 15:42:05 +05:30
Kovid Goyal
88567f69b2 Start work on history support for readline 2022-11-14 15:42:05 +05:30
Kovid Goyal
fe91af5e09 Go stdlib doesnt even have a way to lock files 2022-11-14 15:42:05 +05:30
Kovid Goyal
5e2255591c Dont send invalid kitty-cmd escape code over tty 2022-11-14 15:42:05 +05:30
Kovid Goyal
01969cae1a More useful PARSE ERROR msg for unknown @ commands 2022-11-14 15:42:05 +05:30
Kovid Goyal
b89dfc6d1d Actually run the remote control commands from the shell 2022-11-14 15:42:05 +05:30
Kovid Goyal
59edf1d349 Code to show help 2022-11-14 15:42:05 +05:30
Kovid Goyal
9419fbc77c Fix rendering when line wraps 2022-11-14 15:42:05 +05:30
Kovid Goyal
d27cf045e5 ... 2022-11-14 15:42:05 +05:30
Kovid Goyal
f7d44330a2 remove unused code 2022-11-14 15:42:05 +05:30
Kovid Goyal
834385baff Improve performance when pasting large amounts of text into readline by not redrawing on every char 2022-11-14 15:42:05 +05:30
Kovid Goyal
c0f17c279e Add a generic ring buffer
Go's stdlib is very anemic
2022-11-14 15:42:05 +05:30
Kovid Goyal
7264bea8c9 Fix selector incorrectly marking fd as ready on EINTR 2022-11-14 15:42:04 +05:30
Kovid Goyal
1058c999c8 ... 2022-11-14 15:42:04 +05:30
Kovid Goyal
bf7dd1c369 Fix multiline prompts 2022-11-14 15:42:04 +05:30
Kovid Goyal
936a7a5f97 Dont write escape code for zero movement 2022-11-14 15:42:04 +05:30
Kovid Goyal
350060e0f6 ... 2022-11-14 15:42:04 +05:30
Kovid Goyal
430bd23870 Fix decoding of letter trailer CSI key event 2022-11-14 15:42:04 +05:30
Kovid Goyal
9f2b2eac85 More work on shell 2022-11-14 15:42:04 +05:30
Kovid Goyal
fd36435262 Add some default readline bindings 2022-11-14 15:42:04 +05:30
Kovid Goyal
27418eed88 Beep when action could not be performed 2022-11-14 15:42:04 +05:30
Kovid Goyal
48f1690913 Wire up key event handling 2022-11-14 15:42:04 +05:30
Kovid Goyal
eff239a195 Code to erase character ranges 2022-11-14 15:42:04 +05:30
Kovid Goyal
5e5cae8391 Code to move cursor right 2022-11-14 15:42:04 +05:30
Kovid Goyal
57310a772a Code to move cursor left 2022-11-14 15:42:04 +05:30
Kovid Goyal
066465bce7 Some tests for add_text 2022-11-14 15:42:04 +05:30
Kovid Goyal
1792c2268a Start writing tests for readline internal functions 2022-11-14 15:42:04 +05:30
Kovid Goyal
32059dba7e More work on readline 2022-11-14 15:42:03 +05:30
Kovid Goyal
c8296a44eb More work on readline 2022-11-14 15:42:03 +05:30
Kovid Goyal
565526624f Start work on porting kitty shell to Go 2022-11-14 15:42:03 +05:30
Kovid Goyal
f57832f501 Fix spurious rebuilds of generated go code 2022-11-14 15:42:03 +05:30
Kovid Goyal
e536ef7844 Suggestions for sub command names as well 2022-11-14 15:42:03 +05:30
Kovid Goyal
0dab006733 Allow un-ambiguous prefixes for command names 2022-11-14 15:42:03 +05:30
Kovid Goyal
75ead358a2 Show suggestions for options based on levenshtein distance 2022-11-14 15:42:03 +05:30
Kovid Goyal
654bd23109 DRYer 2022-11-14 15:42:03 +05:30
Kovid Goyal
6b04c42730 update wcswidth go version to match unicode 15 update in master 2022-11-14 15:42:03 +05:30
Kovid Goyal
8f5302a650 Hook up kitty-tool completions with shell integration 2022-11-14 15:42:03 +05:30
Kovid Goyal
74b1cac344 Allow using unabiguous long option prefixes 2022-11-14 15:42:03 +05:30
Kovid Goyal
7d5849cc17 ... 2022-11-14 15:42:03 +05:30
Kovid Goyal
d2a2af9672 Add completion for kitty-tool 2022-11-14 15:42:02 +05:30
Kovid Goyal
2633356842 No need to use a map 2022-11-14 15:42:02 +05:30
Kovid Goyal
3bd4fd999a All completion tests pass again 2022-11-14 15:42:02 +05:30
Kovid Goyal
262e2fb7a3 Various fixes from the completion merge 2022-11-14 15:42:02 +05:30
Kovid Goyal
97716fea8b More work on merging completions with parse tree 2022-11-14 15:42:02 +05:30
Kovid Goyal
bf74413c1f Work on merging completion tree with parse tree 2022-11-14 15:42:02 +05:30
Kovid Goyal
79ca0408e7 split up types.go 2022-11-14 15:42:02 +05:30
Kovid Goyal
97acb60981 Move completion package into cli 2022-11-14 15:42:02 +05:30
Kovid Goyal
3662efdf80 Nicer handling of python for typecheck 2022-11-14 15:42:02 +05:30
Kovid Goyal
e608a945de Output version information at bottom of help 2022-11-14 15:42:02 +05:30
Kovid Goyal
5771bd0c01 Make adding subcommands a bit nicer 2022-11-14 15:42:02 +05:30
Kovid Goyal
4396dede85 Get rid of the cobra dependency 2022-11-14 15:42:02 +05:30
Kovid Goyal
cbc569af64 Remove no_response from json specs 2022-11-14 15:42:02 +05:30
Kovid Goyal
90c1745976 Fix parsing of list options 2022-11-14 15:42:02 +05:30
Kovid Goyal
c4ab964d09 Tests for CLI parsing 2022-11-14 15:42:02 +05:30
Kovid Goyal
04022ed363 Various fixes to CLI parsing 2022-11-14 15:42:02 +05:30
Kovid Goyal
79cfc1e70a Move kitty-tool __complete__ to use the new CLI framework 2022-11-14 15:42:01 +05:30
Kovid Goyal
e7c14c78d0 Work on outputting help for commands 2022-11-14 15:42:01 +05:30
Kovid Goyal
cb2389efa5 Use the standard library deque
Drops a dependency
2022-11-14 15:42:01 +05:30
Kovid Goyal
49f5f25fb9 Run tests in the writeable src dir as the generated go files are present there 2022-11-14 15:42:01 +05:30
Kovid Goyal
ff4353b209 ... 2022-11-14 15:42:01 +05:30
Kovid Goyal
c07dc220a8 Fix frozen builds 2022-11-14 15:42:01 +05:30
Kovid Goyal
4316018966 ... 2022-11-14 15:42:01 +05:30
Kovid Goyal
a0bf6177e2 Use a LRUCache rather than an Unbounded one 2022-11-14 15:42:01 +05:30
Kovid Goyal
3078b9074a Also report submatch positions 2022-11-14 15:42:01 +05:30
Kovid Goyal
dffb87ced9 Make the cache re-useable 2022-11-14 15:42:01 +05:30
Kovid Goyal
4adea5b7fe Make ReplaceAll re-useable 2022-11-14 15:42:01 +05:30
Kovid Goyal
317b108497 Allow using :role:'payload' in addition to :role:payload as the former can be used in Go `` string literals 2022-11-14 15:42:01 +05:30
Kovid Goyal
7c41737370 Couple more errors found by linting 2022-11-14 15:42:01 +05:30
Kovid Goyal
4b6bae576d configure staticcheck 2022-11-14 15:42:01 +05:30
Kovid Goyal
8221713995 Allow defining options using a struct 2022-11-14 15:42:01 +05:30
Kovid Goyal
ef49634353 Fix some issues reported by staticcheck 2022-11-14 15:42:01 +05:30
Kovid Goyal
d6f42a11d7 Run go vet on CI 2022-11-14 15:42:00 +05:30
Kovid Goyal
800dbf1f4d extra message when tests have failed 2022-11-14 15:42:00 +05:30
Kovid Goyal
b1e08adbce Utility function to sort with key 2022-11-14 15:42:00 +05:30
Kovid Goyal
e7f38929d9 DRYer 2022-11-14 15:42:00 +05:30
Kovid Goyal
d0e133885c Install Go 1.18 on CI 2022-11-14 15:42:00 +05:30
Kovid Goyal
2cacd7a64a get rid of interface{} since we now require Go 1.18 2022-11-14 15:42:00 +05:30
Kovid Goyal
a44c89504b More convenient interface for sorting 2022-11-14 15:42:00 +05:30
Kovid Goyal
8807f6d539 Code to get exe name for usage message 2022-11-14 15:42:00 +05:30
Kovid Goyal
2f83bbdc85 command validation 2022-11-14 15:42:00 +05:30
Kovid Goyal
41a841c83d Validate string slice fields 2022-11-14 15:42:00 +05:30
Kovid Goyal
0cf8876f8a Validate count struct fields 2022-11-14 15:42:00 +05:30
Kovid Goyal
a3a89b3e21 More efficient multi line scanning 2022-11-14 15:42:00 +05:30
Kovid Goyal
2ddbe2a2bc Automatically camel-case destination 2022-11-14 15:42:00 +05:30
Kovid Goyal
707963b694 Code to conveniently read option values into a struct 2022-11-14 15:42:00 +05:30
Kovid Goyal
1811949706 Implement cloning of commands 2022-11-14 15:42:00 +05:30
Kovid Goyal
bc38bd75fd Start work on getting rid of the cobra dependency
Command line parsing is easy and I can do it better.
2022-11-14 15:42:00 +05:30
Kovid Goyal
54ec486d3a Now completion for hyperlinked_grep is automatic thanks to delegation
Also fix delegation for zsh when the command being completed differs
from the current command.
2022-11-14 15:42:00 +05:30
Kovid Goyal
5666b1b0fd Implement completion for fish 2022-11-14 15:41:59 +05:30
Kovid Goyal
ef9b765f81 Dont count bash's idiotic option equals as arguments 2022-11-14 15:41:59 +05:30
Kovid Goyal
a2bb360eec Dont output escape strings in descriptions 2022-11-14 15:41:59 +05:30
Kovid Goyal
e3b8de1ac0 Update test for new exe search 2022-11-14 15:41:59 +05:30
Kovid Goyal
4cbd2a0ee0 ... 2022-11-14 15:41:59 +05:30
Kovid Goyal
7cf9b21fc0 Show local executables for kityt command completion even without ./ 2022-11-14 15:41:59 +05:30
Kovid Goyal
454c2e32e7 ... 2022-11-14 15:41:59 +05:30
Kovid Goyal
53dc079c10 Use compopt to manage files and spaces 2022-11-14 15:41:59 +05:30
Kovid Goyal
08c697e99a Get delegate based completion working for bash 2022-11-14 15:41:59 +05:30
Kovid Goyal
1dce092ac0 Add trailing spaces for bash completion 2022-11-14 15:41:59 +05:30
Kovid Goyal
24c2d27eea handle bash splitting completion cmdline on equals 2022-11-14 15:41:59 +05:30
Kovid Goyal
b04b483b3f Remove common prefix for bash as well 2022-11-14 15:41:59 +05:30
Kovid Goyal
a7c997c6ef Add a debug function to print to parent kitty stdout 2022-11-14 15:41:59 +05:30
Kovid Goyal
266e51310c Basic BASH completion 2022-11-14 15:41:59 +05:30
Kovid Goyal
928a4db817 Implement delegate based completion fof the ssh and hyperlinked_grep kittens 2022-11-14 15:41:59 +05:30
Kovid Goyal
fd631bf402 Delegate based completion for @launch args 2022-11-14 15:41:59 +05:30
Kovid Goyal
dc403156a9 Delegate based completion for kitty cmd 2022-11-14 15:41:59 +05:30
Kovid Goyal
2cc359ccc8 Get zsh completion working apart from delegation 2022-11-14 15:41:58 +05:30
Kovid Goyal
cbbda23e01 Utility code to find longest common prefix/suffix and to quote strings for various shells 2022-11-14 15:41:58 +05:30
Kovid Goyal
1ff4f2df4f Refactor the CLI markup code to make it re-useable 2022-11-14 15:41:58 +05:30
Kovid Goyal
8796168469 Port code to truncate strings to visual width to Go 2022-11-14 15:41:58 +05:30
Kovid Goyal
d16ad40bbf avoid extra string copy in Stringwidth 2022-11-14 15:41:58 +05:30
Kovid Goyal
5c0858d6b7 Start work on zsh completion serialization 2022-11-14 15:41:58 +05:30
Kovid Goyal
a32a8d096d Allow commands to customize argument parsing 2022-11-14 15:41:58 +05:30
Kovid Goyal
67f556bd7c Add completion for the launch wrappers 2022-11-14 15:41:58 +05:30
Kovid Goyal
7737369fc9 Add completion for the kittens 2022-11-14 15:41:58 +05:30
Kovid Goyal
25a7ec9a07 Extra completion for some kitty options 2022-11-14 15:41:58 +05:30
Kovid Goyal
c2a2b4c087 Add various special purpose entry points 2022-11-14 15:41:58 +05:30
Kovid Goyal
3bf20594b7 Wire up completion for rc command options 2022-11-14 15:41:58 +05:30
Kovid Goyal
3a8bab90dc Get rid of WordPrefix 2022-11-14 15:41:58 +05:30
Kovid Goyal
0ff2446a1a More completion work 2022-11-14 15:41:58 +05:30
Kovid Goyal
946d44c43f Implement completespec in go 2022-11-14 15:41:58 +05:30
Kovid Goyal
26d4f5bcc9 Use the new completionspec for rc cmds 2022-11-14 15:41:58 +05:30
Kovid Goyal
d84efe105c ... 2022-11-14 15:41:58 +05:30
Kovid Goyal
f657e6e916 Allow using a base directory other than the cwd when completing files 2022-11-14 15:41:57 +05:30
Kovid Goyal
c5afceb4cb Basic completion for options 2022-11-14 15:41:57 +05:30
Kovid Goyal
18c3e46ac6 When completing on patterns exclude directories that only contain files that dont match 2022-11-14 15:41:57 +05:30
Kovid Goyal
3c29ce936b Dont recurse for file completion
We could potentially end up recursing over the entire file system. And
for completion we only present the candidates in the immediate directory
anyway.
2022-11-14 15:41:57 +05:30
Kovid Goyal
c9d986f9a8 args completion for rc commands 2022-11-14 15:41:57 +05:30
Kovid Goyal
d4b67f3b6a ... 2022-11-14 15:41:57 +05:30
Kovid Goyal
6faa908733 And more corner cases 2022-11-14 15:41:57 +05:30
Kovid Goyal
ced741b247 More corner cases 2022-11-14 15:41:57 +05:30
Kovid Goyal
c47ccc8a59 ... 2022-11-14 15:41:57 +05:30
Kovid Goyal
3326e9ef49 Move code to walk with symlinks to the utils module 2022-11-14 15:41:57 +05:30
Kovid Goyal
134fce8507 Allow completing paths with ~ prefix 2022-11-14 15:41:57 +05:30
Kovid Goyal
5d89a6c3c4 Work on completion of file args 2022-11-14 15:41:57 +05:30
Kovid Goyal
833e9625f9 Add a generated comment in *_generated.go in the style used by go generate 2022-11-14 15:41:57 +05:30
Kovid Goyal
21b572d69a Allow building kitty-tool as a static binary 2022-11-14 15:41:57 +05:30
Kovid Goyal
12d9787d0e update go deps 2022-11-14 15:41:57 +05:30
Kovid Goyal
8c6b391eda ... 2022-11-14 15:41:57 +05:30
Kovid Goyal
8c2e435793 Code to complete executables in PATH 2022-11-14 15:41:57 +05:30
Kovid Goyal
10cf7f06c6 Code to get file/dir completion candidates for a prefix 2022-11-14 15:41:56 +05:30
Kovid Goyal
4575a14873 work on framework for testing completion 2022-11-14 15:41:56 +05:30
Kovid Goyal
d679ea2cdf Allow generating completions for multiple command lines for more efficient testing 2022-11-14 15:41:56 +05:30
Kovid Goyal
54378de52b More work on command completion 2022-11-14 15:41:56 +05:30
Kovid Goyal
63287e4115 More work on completions 2022-11-14 15:41:56 +05:30
Kovid Goyal
d0efe00449 Use replace_if_needed() for at commands 2022-11-14 15:41:56 +05:30
Kovid Goyal
d703cb51cd ... 2022-11-14 15:41:56 +05:30
Kovid Goyal
005a9c7090 Add an entry point for the completion tool 2022-11-14 15:41:56 +05:30
Kovid Goyal
f4de6d2a10 More work on completions 2022-11-14 15:41:56 +05:30
Kovid Goyal
e60b331152 start work on porting completion to Go 2022-11-14 15:41:56 +05:30
Kovid Goyal
3d79eb5730 more tests for indent and wrap 2022-11-14 15:41:56 +05:30
Kovid Goyal
af7f4e97cf More work on the new formatter 2022-11-14 15:41:56 +05:30
Kovid Goyal
aad8cb3d1e Use the new formatter for CLI help output 2022-11-14 15:41:56 +05:30
Kovid Goyal
40a9ab8929 Allow ignoring lines containing a sentinel 2022-11-14 15:41:56 +05:30
Kovid Goyal
e433b90297 Dont drop trailing escape codes when stripping trailing whitespace 2022-11-14 15:41:56 +05:30
Kovid Goyal
1ac7d9c10d Basic wrap is working 2022-11-14 15:41:56 +05:30
Kovid Goyal
ef5f0025e1 Start work on more sophisticated indent+wrap implementation 2022-11-14 15:41:56 +05:30
Kovid Goyal
32804f01b2 Allow parsing strings with escape code parser 2022-11-14 15:41:55 +05:30
Kovid Goyal
7ecc1b7950 Remove markup from ref_hyperlink text 2022-11-14 15:41:55 +05:30
Kovid Goyal
a7f6105393 Use Unsafe rather than Dangerous to be consistent 2022-11-14 15:41:55 +05:30
Kovid Goyal
081390b5a2 Utility functions to allow using string/[]byte interchangeably without copies 2022-11-14 15:41:55 +05:30
Kovid Goyal
61094c6bfb Add strikethrough formatting 2022-11-14 15:41:55 +05:30
Kovid Goyal
6672904e64 Fix spurious error message when setting image to none 2022-11-14 15:41:55 +05:30
Kovid Goyal
905c4d641c Allow using many image formats in RC commands 2022-11-14 15:41:55 +05:30
Kovid Goyal
fa7a6dfd4a Implement stdin echo loop for socket i/o as well 2022-11-14 15:41:55 +05:30
Kovid Goyal
cb452ba9fc Implement sen text from stdin for the tty backend 2022-11-14 15:41:55 +05:30
Kovid Goyal
85169c989f ... 2022-11-14 15:41:55 +05:30
Kovid Goyal
e8a321d097 Port code to serialize key events as CSI to Go 2022-11-14 15:41:55 +05:30
Kovid Goyal
3a198833da Simplify escape code wrapping 2022-11-14 15:41:55 +05:30
Kovid Goyal
ea8fb10c05 Password input: Handle SIGTSTP 2022-11-14 15:41:55 +05:30
Kovid Goyal
67115530b4 Make the loop API a thin wrapper around internal methods 2022-11-14 15:41:55 +05:30
Kovid Goyal
7325921070 Allow cancel async commands without auth 2022-11-14 15:41:55 +05:30
Kovid Goyal
f86ce03d3b Fix set-colors 2022-11-14 15:41:55 +05:30
Kovid Goyal
5cf10023c9 Nicer API for setting loop options 2022-11-14 15:41:55 +05:30
Kovid Goyal
93d08011f1 ... 2022-11-14 15:41:54 +05:30
Kovid Goyal
7f77f7e408 Only send cancel async if there is an async id 2022-11-14 15:41:54 +05:30
Kovid Goyal
65c3630099 send_text other than from stdin works 2022-11-14 15:41:54 +05:30
Kovid Goyal
457aab7c41 Simplify timer removal 2022-11-14 15:41:54 +05:30
Kovid Goyal
dcec926590 Do not allow adding timers before loop is run 2022-11-14 15:41:54 +05:30
Kovid Goyal
0a2455c8be Get scroll_window working 2022-11-14 15:41:54 +05:30
Kovid Goyal
bacca88213 Get set_font_size working 2022-11-14 15:41:54 +05:30
Kovid Goyal
bd1b3d9f6e Implement streaming mode for socket IO 2022-11-14 15:41:54 +05:30
Kovid Goyal
364533b1ed Work on supporting streaming remote commands with passwords 2022-11-14 15:41:54 +05:30
Kovid Goyal
d7985689c9 Allow debugprintln to controlling tty easily 2022-11-14 15:41:54 +05:30
Kovid Goyal
6d6bba4a4c debugprintln should be in-band for the loop 2022-11-14 15:41:54 +05:30
Kovid Goyal
5cc5759f3e flush_pending_writes must be non-blocking 2022-11-14 15:41:54 +05:30
Kovid Goyal
a388a658ce Fix payload update code in multi send commands 2022-11-14 15:41:54 +05:30
Kovid Goyal
b5e2871aa0 Remove not needed chunking code 2022-11-14 15:41:54 +05:30
Kovid Goyal
192eccc6cc More work on porting rc commands 2022-11-14 15:41:54 +05:30
Kovid Goyal
a4b2e2a196 more work on porting command parsing to Go 2022-11-14 15:41:54 +05:30
Kovid Goyal
6f4968305a more work on porting rc command parsing to Go 2022-11-14 15:41:54 +05:30
Kovid Goyal
79c8862d4c Work on conversion of args parsing to go code 2022-11-14 15:41:53 +05:30
Kovid Goyal
441e4edfb2 Also ensure kitty-tool bootstrap is executable 2022-11-14 15:41:53 +05:30
Kovid Goyal
ef71b071db Automap a bunch of json fields from identically named options 2022-11-14 15:41:53 +05:30
Kovid Goyal
b33a684357 ... 2022-11-14 15:41:53 +05:30
Kovid Goyal
43b35f6f4e Move GoOption migration code to cli.py for re-use 2022-11-14 15:41:53 +05:30
Kovid Goyal
3b2c4561c2 Dont change the env for go tests
This prevents got test caching from working greatly increasing the time
for running a test
2022-11-14 15:41:53 +05:30
Kovid Goyal
e69b02ad46 ... 2022-11-14 15:41:53 +05:30
Kovid Goyal
85b6053380 Run go tests in parallel 2022-11-14 15:41:53 +05:30
Kovid Goyal
249df69ac9 Use the new styling API for CLI infra 2022-11-14 15:41:53 +05:30
Kovid Goyal
4a4500d56b Dont make urls part of styling, instead have a dedicated UrlFunc API
Since urls can potentially change a lot, caching them makes no sense
2022-11-14 15:41:53 +05:30
Kovid Goyal
be22f49012 Fix usage of numbered colors for underlines 2022-11-14 15:41:53 +05:30
Kovid Goyal
f9695a7947 Add url support to styling 2022-11-14 15:41:53 +05:30
Kovid Goyal
29d9b70f0c More ansi styling tests 2022-11-14 15:41:53 +05:30
Kovid Goyal
42a8ca0842 Write some tests for the style wrapper 2022-11-14 15:41:53 +05:30
Kovid Goyal
91c61478dd Start work on easily generating ANSI formatted strings 2022-11-14 15:41:53 +05:30
Kovid Goyal
fb482e28f6 ... 2022-11-14 15:41:53 +05:30
Kovid Goyal
387333492b Generate color names and table for Go
Also exclude generated files from gofmt checking
2022-11-14 15:41:53 +05:30
Kovid Goyal
9c58cb3f41 ... 2022-11-14 15:41:52 +05:30
Kovid Goyal
b2e610f9b1 Implement socket I/O 2022-11-14 15:41:52 +05:30
Kovid Goyal
a960937095 Simplify serialization code and avoid extra copy 2022-11-14 15:41:52 +05:30
Kovid Goyal
0cda5d43a6 Fix final write detection 2022-11-14 15:41:52 +05:30
Kovid Goyal
a75d59643c Use one less channel 2022-11-14 15:41:52 +05:30
Kovid Goyal
bf35817d73 No need to store most channels on self 2022-11-14 15:41:52 +05:30
Kovid Goyal
f103f8d5db Create a in src symlink for kitty-tool as well 2022-11-14 15:41:52 +05:30
Kovid Goyal
b382587776 another attempt 2022-11-14 15:41:52 +05:30
Kovid Goyal
6fe0c8ba2f dump tree 2022-11-14 15:41:52 +05:30
Kovid Goyal
7b2991de02 ... 2022-11-14 15:41:52 +05:30
Kovid Goyal
1b90c03304 Refactor loop code into its own package 2022-11-14 15:41:52 +05:30
Kovid Goyal
0aa05b02e8 Cleanup 2022-11-14 15:41:52 +05:30
Kovid Goyal
5412a0126c we generate more than just rc commands 2022-11-14 15:41:52 +05:30
Kovid Goyal
841b368021 DRYer 2022-11-14 15:41:52 +05:30
Kovid Goyal
b1f9139ca5 Use a fully random async_id rather than a uuid 2022-11-14 15:41:52 +05:30
Kovid Goyal
4a49c3940a Switch to using goroutines rather than a select()
More complex code since now we have to synchronize between threads,
but a good way to teach myself more about goroutines.
2022-11-14 15:41:52 +05:30
Kovid Goyal
ee12349a50 Use Go's os.File this allows us to implement WriteString without using unsafe 2022-11-14 15:41:52 +05:30
Kovid Goyal
69c847a48f Fix failing test 2022-11-14 15:41:51 +05:30
Kovid Goyal
03705cbec0 Fix transmission of async rc commands 2022-11-14 15:41:51 +05:30
Kovid Goyal
ff2ff9c04f Port short uuid code to Go 2022-11-14 15:41:51 +05:30
Kovid Goyal
a22ba9f739 Fix failing test 2022-11-14 15:41:51 +05:30
Kovid Goyal
c86f8a698c @ ls works phew 2022-11-14 15:41:51 +05:30
Kovid Goyal
fa4711bd04 Give the kill signal time to be delivered 2022-11-14 15:41:51 +05:30
Kovid Goyal
a939bbb3ec ... 2022-11-14 15:41:51 +05:30
Kovid Goyal
174bc25afb Make timeout checking more efficient 2022-11-14 15:41:51 +05:30
Kovid Goyal
2ffba1c422 Work on implementing ttyio via TUI 2022-11-14 15:41:51 +05:30
Kovid Goyal
0913b64c6b Dont vendor base85 2022-11-14 15:41:51 +05:30
Kovid Goyal
32e59257d2 Refactor io in preparation for using tui 2022-11-14 15:41:51 +05:30
Kovid Goyal
6f8c884bb5 Also handle SIGPIPE as the Go runtime does funky things with this signal 2022-11-14 15:41:51 +05:30
Kovid Goyal
80c5ac891d Add license info to Go files 2022-11-14 15:41:51 +05:30
Kovid Goyal
ccb60687b6 Prefix names of cmd files 2022-11-14 15:41:51 +05:30
Kovid Goyal
6a2393299b Add a write completed callback 2022-11-14 15:41:51 +05:30
Kovid Goyal
ab66b3f4c0 Add timer infra to the loop 2022-11-14 15:41:51 +05:30
Kovid Goyal
c8292d77f1 Re-use the escape code parser for wcswidth calculation 2022-11-14 15:41:51 +05:30
Kovid Goyal
7280c712d6 Move escape code parser into wcswidth package 2022-11-14 15:41:50 +05:30
Kovid Goyal
9be2247081 Dont use the syscall package 2022-11-14 15:41:50 +05:30
Kovid Goyal
e68b5fa504 Add callback for screen resize handling 2022-11-14 15:41:50 +05:30
Kovid Goyal
c2ef6c986b Password input now works 2022-11-14 15:41:50 +05:30
Kovid Goyal
619fcb0681 Allow debug printing 2022-11-14 15:41:50 +05:30
Kovid Goyal
10a39d3757 Fix reset mode incorrectly setting mode instead 2022-11-14 15:41:50 +05:30
Kovid Goyal
d2a15a2009 Make using alternate screen the default 2022-11-14 15:41:50 +05:30
Kovid Goyal
235eb868b2 More misc fixes for TUI 2022-11-14 15:41:50 +05:30
Kovid Goyal
5703a3370e Move wcswidth into its own package as it is very slow to build 2022-11-14 15:41:50 +05:30
Kovid Goyal
5dca2a1a25 Fix stringifying mods 2022-11-14 15:41:50 +05:30
Kovid Goyal
4b18b575cd Misc fixes for TUI 2022-11-14 15:41:50 +05:30
Kovid Goyal
818f68ec53 Initialize various maps 2022-11-14 15:41:50 +05:30
Kovid Goyal
cd54fefa99 Ignore more types of temporary errors 2022-11-14 15:41:50 +05:30
Kovid Goyal
4ab5456ead Less layering 2022-11-14 15:41:49 +05:30
Kovid Goyal
10d11bc749 Drop another dependency 2022-11-14 15:41:49 +05:30
Kovid Goyal
19ffbc6f3d Implement wcswidth() for Go 2022-11-14 15:41:49 +05:30
Kovid Goyal
79b1af28b4 Fix errors reported by compiler 2022-11-14 15:41:49 +05:30
Kovid Goyal
05d768d8df Generate a wcwidth for Go as well 2022-11-14 15:41:49 +05:30
Kovid Goyal
7bb310d3af Port recent changes from cli.py to Go 2022-11-14 15:41:49 +05:30
Kovid Goyal
9d56f8eed2 Use TUI to build a nice password read control 2022-11-14 15:41:49 +05:30
Kovid Goyal
42a5129553 Wire up key handling 2022-11-14 15:41:49 +05:30
Kovid Goyal
d6ed20323b Implement key event parsing and matching 2022-11-14 15:41:49 +05:30
Kovid Goyal
63fdbd3fa0 Start work on decoding key events in Go 2022-11-14 15:41:49 +05:30
Kovid Goyal
99fde8723a Wire up the signal handlers 2022-11-14 15:41:49 +05:30
Kovid Goyal
526a331f47 Wire up a bunch of callbacks 2022-11-14 15:41:49 +05:30
Kovid Goyal
e18b6638bb Allow propagating errors from the escape code handlers 2022-11-14 15:41:49 +05:30
Kovid Goyal
3c3e7b7f70 Start work on proper TUI support 2022-11-14 15:41:49 +05:30
Kovid Goyal
67f03621ae Handle EINTR in IsTerminal 2022-11-14 15:41:49 +05:30
Kovid Goyal
10cef16210 DRYer 2022-11-14 15:41:49 +05:30
Kovid Goyal
6a79b450f7 Drop another dependency and get a better read password function 2022-11-14 15:41:48 +05:30
Kovid Goyal
eb4ee13f73 Drop another dependency 2022-11-14 15:41:48 +05:30
Kovid Goyal
cf287015de ... 2022-11-14 15:41:48 +05:30
Kovid Goyal
246277e7af Refactor tty code into its own package 2022-11-14 15:41:48 +05:30
Kovid Goyal
13758e9600 Drop one dependency 2022-11-14 15:41:48 +05:30
Kovid Goyal
73e4deb1c2 Show suggestions based on levenshtein distance 2022-11-14 15:41:48 +05:30
Kovid Goyal
68d589826a ... 2022-11-14 15:41:48 +05:30
Kovid Goyal
7457746d65 Fix @command form not supporting global options 2022-11-14 15:41:48 +05:30
Kovid Goyal
eec8f04e93 fix reading from tty 2022-11-14 15:41:48 +05:30
Kovid Goyal
3a7d26a3ef Work on reading command responses 2022-11-14 15:41:48 +05:30
Kovid Goyal
91b15d1a90 Fix incorrect err handling 2022-11-14 15:41:48 +05:30
Kovid Goyal
12b0f632bd Allow OSC to be terminated by BEL
Also prevent changing streaming state unless in reset state
2022-11-14 15:41:48 +05:30
Kovid Goyal
84cb2638d6 Work on an escape code parser 2022-11-14 15:41:48 +05:30
Kovid Goyal
7eb6cb2407 Update script that counts lines of code 2022-11-14 15:41:48 +05:30
Kovid Goyal
ce3062cbde UTF-8 decode/encode for Go
The builtin utf-8 package has semantics not suitable for us
2022-11-14 15:41:48 +05:30
Kovid Goyal
e599a2c87f The stupid term package is not EINTR safe 2022-11-14 15:41:48 +05:30
Kovid Goyal
15e1f376a4 EINTR safe function to get tty size 2022-11-14 15:41:48 +05:30
Kovid Goyal
82d0bd9364 Use the term package to get tty size since it has a function for it 2022-11-14 15:41:47 +05:30
Kovid Goyal
6a9f3feba2 ... 2022-11-14 15:41:47 +05:30
Kovid Goyal
2e31178980 Workaround for go unix package not wrapping pselect() on darwin 2022-11-14 15:41:47 +05:30
Kovid Goyal
141b9c8f08 Adjust select() timeout on EINTR 2022-11-14 15:41:47 +05:30
Kovid Goyal
17629add66 Handle EINTR 2022-11-14 15:41:47 +05:30
Kovid Goyal
352a78f056 Add a debug print method to tty and use pselect rather than select for greater timeout precision 2022-11-14 15:41:47 +05:30
Kovid Goyal
2ef5d0a140 ... 2022-11-14 15:41:47 +05:30
Kovid Goyal
08b4741024 Get rid of a couple of unneeded dependencies 2022-11-14 15:41:47 +05:30
Kovid Goyal
11ffa961bc Use local hyperlinks for :doc: 2022-11-14 15:41:47 +05:30
Kovid Goyal
ad6d928c12 Port various recent changes to CLI help output 2022-11-14 15:41:47 +05:30
Kovid Goyal
74b768bfc2 ... 2022-11-14 15:41:47 +05:30
Kovid Goyal
9b703078dd See if at least the field names are the same 2022-11-14 15:41:47 +05:30
Kovid Goyal
43e93414ea Some work on implementing TTYIO 2022-11-14 15:41:47 +05:30
Kovid Goyal
6c3a439455 Use the io.Reader interface 2022-11-14 15:41:47 +05:30
Kovid Goyal
a7bc2fcba8 Code to parse socket addresses 2022-11-14 15:41:47 +05:30
Kovid Goyal
417c8887b9 Start on testing infra for command to JSON serialization 2022-11-14 15:41:47 +05:30
Kovid Goyal
47feb73cdf Code to generate structs for JSON marshalling 2022-11-14 15:41:47 +05:30
Kovid Goyal
0aa1bacbe7 ... 2022-11-14 15:41:47 +05:30
Kovid Goyal
63512f0512 Implement setting of option values into a struct 2022-11-14 15:41:46 +05:30
Kovid Goyal
a32251cab4 Handle aliased flags 2022-11-14 15:41:46 +05:30
Kovid Goyal
2ca8ae8e5f normalize flag names so that underscores are interchangeable with hyphens 2022-11-14 15:41:46 +05:30
Kovid Goyal
2d466f343d Finish mapping of python cli opt to go cli opt 2022-11-14 15:41:46 +05:30
Kovid Goyal
4596dc39ce Fix formatting of lines with only spaces 2022-11-14 15:41:46 +05:30
Kovid Goyal
605882582e Transfer response_timeout 2022-11-14 15:41:46 +05:30
Kovid Goyal
a5876e5231 Refactor conversion of py opt to go opt 2022-11-14 15:41:46 +05:30
Kovid Goyal
e127579ae6 DRYer 2022-11-14 15:41:46 +05:30
Kovid Goyal
b3be6792fd General cleanup 2022-11-14 15:41:46 +05:30
Kovid Goyal
6c25f0cf4b Use cobra's builtin machinery for creating new types 2022-11-14 15:41:46 +05:30
Kovid Goyal
a0bff4abab Let kitty-tool know if it was built for a frozen kitty 2022-11-14 15:41:46 +05:30
Kovid Goyal
82410c58ed Hide the default completion command 2022-11-14 15:41:46 +05:30
Kovid Goyal
3a87cfce3e Get bool set flags ported 2022-11-14 15:41:46 +05:30
Kovid Goyal
15ffd8e6d8 Support older Go 2022-11-14 15:41:46 +05:30
Kovid Goyal
33e16df586 Add some basic RC serialization tests 2022-11-14 15:41:46 +05:30
Kovid Goyal
4432c1a2ea Move the command types into a separate package 2022-11-14 15:41:46 +05:30
Kovid Goyal
45540561cc More debug info about PATH in CI 2022-11-14 15:41:46 +05:30
Kovid Goyal
f90753c69b Use whatever version of go is available on CI 2022-11-14 15:41:46 +05:30
Kovid Goyal
bab914c497 Create hidden alias commands so kitty-tool @ls also works 2022-11-14 15:41:45 +05:30
Kovid Goyal
d3bb69a0ac strip whitespace from long descriptions just to be safe 2022-11-14 15:41:45 +05:30
Kovid Goyal
e356af2dc4 Build kitty-tool as a universal binary for freeze builds on macOS 2022-11-14 15:41:45 +05:30
Kovid Goyal
e9e7b97c48 And we have frozen builds working with kitty-tool 2022-11-14 15:41:45 +05:30
Kovid Goyal
1c7d6f8bc6 Dont sync kitty-tool to build vms 2022-11-14 15:41:45 +05:30
Kovid Goyal
82a0e56eb2 Fix go tests not being excluded correctly 2022-11-14 15:41:45 +05:30
Kovid Goyal
54fd2c6773 Get linux freeze working 2022-11-14 15:41:45 +05:30
Kovid Goyal
fb4c7db25e Add a test for existence of kitty-tool 2022-11-14 15:41:45 +05:30
Kovid Goyal
c85af36116 Simplify cleanup and ignoring of generated go files 2022-11-14 15:41:45 +05:30
Kovid Goyal
780b5ca8bd misc fixes 2022-11-14 15:41:45 +05:30
Kovid Goyal
20ad7ca437 Output VCSRevision with --version 2022-11-14 15:41:45 +05:30
Kovid Goyal
d39036de2a Add vcs revision to version string 2022-11-14 15:41:45 +05:30
Kovid Goyal
4ac4ee643e Have the rc command wrapper sauto-generated on build 2022-11-14 15:41:45 +05:30
Kovid Goyal
47f35a06e6 Start work on generating rc cmd wrappers 2022-11-14 15:41:45 +05:30
Kovid Goyal
77f7ce82c0 Parse global options 2022-11-14 15:41:45 +05:30
Kovid Goyal
10b74d0703 Update documentation of --to 2022-11-14 15:41:45 +05:30
Kovid Goyal
393820e77a Dont sort flags by default 2022-11-14 15:41:45 +05:30
Kovid Goyal
1b8805bc6f document we need go >= 1.19 2022-11-14 15:41:44 +05:30
Kovid Goyal
07dc83670b Fix go in home dir getting removed from PATH on CI 2022-11-14 15:41:44 +05:30
Kovid Goyal
1429be3a19 Run gofmt via python, easier to debug 2022-11-14 15:41:44 +05:30
Kovid Goyal
4b69a600e5 Nicer error when go is not found during build 2022-11-14 15:41:44 +05:30
Kovid Goyal
ce9a5528bc Pass verbose to go build 2022-11-14 15:41:44 +05:30
Kovid Goyal
2ea3fa36d2 ... 2022-11-14 15:41:44 +05:30
Kovid Goyal
14262b158d Log which go exe is being used to run the tests 2022-11-14 15:41:44 +05:30
Kovid Goyal
2fd013b593 Add source code linting for go to CI 2022-11-14 15:41:44 +05:30
Kovid Goyal
1325844539 Add some go testing infrastructure 2022-11-14 15:41:44 +05:30
Kovid Goyal
3a21605b05 ... 2022-11-14 15:41:44 +05:30
Kovid Goyal
cea9ff30dc Add the go dependency to CI and Brewfile 2022-11-14 15:41:44 +05:30
Kovid Goyal
63da2e1ec6 gofmt 2022-11-14 15:41:44 +05:30
Kovid Goyal
083deec663 Build kitty-tool via the build system 2022-11-14 15:41:44 +05:30
Kovid Goyal
8b91c227f6 ... 2022-11-14 15:41:44 +05:30
Kovid Goyal
06bd1f5d48 DRYer 2022-11-14 15:41:44 +05:30
Kovid Goyal
a7f0a471ed Dont fail to output usage when less is not present 2022-11-14 15:41:44 +05:30
Kovid Goyal
2a7aa46b77 Use pager even for usage + error 2022-11-14 15:41:44 +05:30
Kovid Goyal
c04b002d4e Use a pager for displaying usage, matches kitty behavior
Also dont tell less to squeeze lines
2022-11-14 15:41:44 +05:30
Kovid Goyal
46840df1ad CLI help output make kitty.conf a clickable URL 2022-11-14 15:41:43 +05:30
Kovid Goyal
aaf0dea8dc Use a single wrapper binary for all command line tools
This is because Go has a multi megabyte overhead for its binaries
2022-11-14 15:41:43 +05:30
Kovid Goyal
abaafc2d68 Parse roles in the help strings 2022-11-14 15:41:43 +05:30
Kovid Goyal
c97556de65 Show help when command is specified 2022-11-14 15:41:43 +05:30
Kovid Goyal
bbf7504303 Start work on implementing kitty @ as a static binary using Go 2022-11-14 15:41:43 +05:30
Kovid Goyal
126468a5dd Fix #5668 2022-11-14 15:40:24 +05:30
Kovid Goyal
8280899ce1 IBUS: When creating the connection mark as focused if any top level window has focus. Fixes #5655 2022-11-10 07:21:34 +05:30
Kovid Goyal
b15c9f7419 Function should be static 2022-11-10 07:18:17 +05:30
Kovid Goyal
2e8ef66496 Another mypy update another round of spurious errors 2022-11-08 17:17:40 +05:30
418 changed files with 30792 additions and 5173 deletions

2
.gitattributes vendored
View File

@@ -15,6 +15,8 @@ kittens/diff/options/parse.py linguist-generated=true
glfw/*.c linguist-vendored=true
glfw/*.h linguist-vendored=true
kittens/unicode_input/names.h linguist-generated=true
tools/wcswidth/std.go linguist-generated=true
*.py text diff=python
*.m text diff=objc
*.go text diff=go

View File

@@ -30,8 +30,9 @@ def install_deps():
print('Installing kitty dependencies...')
sys.stdout.flush()
if is_macos:
items = (x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew '))
items = [x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew ')]
openssl = 'openssl'
items.remove('go') # already installed by ci.yml
import ssl
if ssl.OPENSSL_VERSION_INFO[0] == 1:
openssl += '@1.1'
@@ -129,6 +130,12 @@ def main():
package_kitty()
elif action == 'test':
test_kitty()
elif action == 'gofmt':
q = subprocess.check_output('gofmt -s -l tools'.split())
if q.strip():
q = '\n'.join(filter(lambda x: not x.rstrip().endswith('_generated.go'), q.decode().strip().splitlines())).strip()
if q:
raise SystemExit(q)
else:
raise SystemExit(f'Unknown action: {action}')

View File

@@ -5,6 +5,7 @@ env:
ASAN_OPTIONS: leak_check_at_exit=0
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
GO_INSTALL_VERSION: ">=1.20.0"
permissions:
contents: read # to fetch code (actions/checkout)
@@ -44,20 +45,26 @@ jobs:
cc: gcc
steps:
- name: Checkout source code
uses: actions/checkout@v3
with:
fetch-depth: 10
- name: Set up Python ${{ matrix.pyver }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.pyver }}
- name: Checkout source code
uses: actions/checkout@v3
with:
fetch-depth: 10
- name: Build kitty
run: python .github/workflows/ci.py build
- name: Set up Python ${{ matrix.pyver }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.pyver }}
- name: Test kitty
run: python .github/workflows/ci.py test
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_INSTALL_VERSION }}
- name: Build kitty
run: python .github/workflows/ci.py build
- name: Test kitty
run: python .github/workflows/ci.py test
linux-package:
name: Linux package
@@ -65,39 +72,53 @@ jobs:
env:
CFLAGS: -funsigned-char
steps:
- name: Checkout source code
uses: actions/checkout@v3
with:
fetch-depth: 0 # needed for :commit: docs role
- name: Checkout source code
uses: actions/checkout@v3
with:
fetch-depth: 0 # needed for :commit: docs role
- name: Test for trailing whitespace
run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
- name: Test for trailing whitespace
run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst *.go .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install build-only deps
run: pip install -r docs/requirements.txt flake8 mypy types-requests types-docutils
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_INSTALL_VERSION }}
- name: Run pyflakes
run: python -m flake8 --count .
- name: Install build-only deps
run: python -m pip install -r docs/requirements.txt ruff mypy types-requests types-docutils
- name: Build kitty package
run: python .github/workflows/ci.py package
- name: Run ruff
run: ruff .
- name: Build kitty
run: python setup.py build --debug
- name: Run gofmt
run: go version && python .github/workflows/ci.py gofmt
- name: Run mypy
run: ./test.py mypy
- name: Build kitty package
run: python .github/workflows/ci.py package
- name: Build man page
run: make FAIL_WARN=1 man
- name: Build kitty
run: python setup.py build --debug
- name: Build HTML docs
run: make FAIL_WARN=1 html
- name: Build static kitty-tool
run: python setup.py build-static-binaries
- name: Run mypy
run: which python && python -m mypy --version && ./test.py mypy
- name: Run go vet
run: go version && go vet ./...
- name: Build man page
run: make FAIL_WARN=1 man
- name: Build HTML docs
run: make FAIL_WARN=1 html
bundle:
name: Bundle test (${{ matrix.os }})
@@ -108,42 +129,52 @@ jobs:
env:
KITTY_BUNDLE: 1
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 10
- name: Build kitty
run: which python3 && python3 .github/workflows/ci.py build
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_INSTALL_VERSION }}
- name: Test kitty
run: python3 .github/workflows/ci.py test
- name: Build kitty
run: which python3 && python3 .github/workflows/ci.py build
- name: Test kitty
run: python3 .github/workflows/ci.py test
brew:
name: macOS Brew
runs-on: macos-latest
steps:
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 0 # needed for :commit: docs role
- name: Checkout source code
uses: actions/checkout@master
with:
fetch-depth: 0 # needed for :commit: docs role
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Build kitty
run: python3 .github/workflows/ci.py build
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_INSTALL_VERSION }}
- name: Test kitty
run: python3 .github/workflows/ci.py test
- name: Build kitty
run: python3 .github/workflows/ci.py build
- name: Install deps for docs
run: python3 -m pip install -r docs/requirements.txt
- name: Test kitty
run: python3 .github/workflows/ci.py test
- name: Builds docs
run: make FAIL_WARN=1 docs
- name: Install deps for docs
run: python3 -m pip install -r docs/requirements.txt
- name: Build kitty package
run: python3 .github/workflows/ci.py package
- name: Builds docs
run: make FAIL_WARN=1 docs
- name: Build kitty package
run: python3 .github/workflows/ci.py package

View File

@@ -22,6 +22,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ">=1.20.0"
- name: Checkout repository
uses: actions/checkout@v3
with:
@@ -31,7 +37,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: python, c
setup-python-dependencies: false

7
.gitignore vendored
View File

@@ -9,10 +9,10 @@
/build/
/linux-package/
/kitty.app/
/compile_commands.json
/link_commands.json
/glad/out/
/kitty/launcher/kitty*
/kitty/launcher/kitt*
/tools/cmd/at/*_generated.go
*_generated.go
/*.dSYM/
__pycache__/
/glfw/wayland-*-client-protocol.[ch]
@@ -20,5 +20,6 @@ __pycache__/
/docs/generated/
/.mypy_cache
.DS_Store
.cache
bypy/b
bypy/virtual-machines.conf

View File

@@ -5,3 +5,4 @@ brew "python"
brew "imagemagick"
brew "harfbuzz"
brew "sphinx-doc"
brew "go"

View File

@@ -7,6 +7,11 @@ When reporting a bug, provide full details of your environment, that means, at
a minimum, kitty version, OS and OS version, kitty config (ideally a minimal
config to reproduce the issue with).
Note that bugs and feature requests are often closed quickly as they are either
fixed or deemed wontfix/invalid. In my experience, this is the only scaleable way to
manage a bug tracker. Feel free to continue to post to a closed bug report
if you would like to discuss the issue further. Being closed does not mean you
will not get any more responses.
### Contributing code

View File

@@ -11,9 +11,8 @@ import sys
import tempfile
from contextlib import suppress
from bypy.constants import (
LIBDIR, PREFIX, PYTHON, SRC as KITTY_DIR, ismacos, worker_env
)
from bypy.constants import LIBDIR, PREFIX, PYTHON, ismacos, worker_env
from bypy.constants import SRC as KITTY_DIR
from bypy.utils import run_shell, walk
@@ -63,20 +62,31 @@ def build_frozen_launcher(extra_include_dirs):
def run_tests(kitty_exe):
with tempfile.TemporaryDirectory() as tdir:
env = {
uenv = {
'KITTY_CONFIG_DIRECTORY': os.path.join(tdir, 'conf'),
'KITTY_CACHE_DIRECTORY': os.path.join(tdir, 'cache')
}
[os.mkdir(x) for x in env.values()]
cmd = [kitty_exe, '+runpy', 'from kitty_tests.main import run_tests; run_tests()']
[os.mkdir(x) for x in uenv.values()]
env = os.environ.copy()
env.update(uenv)
cmd = [kitty_exe, '+runpy', 'from kitty_tests.main import run_tests; run_tests(report_env=True)']
print(*map(shlex.quote, cmd), flush=True)
if subprocess.call(cmd, env=env) != 0:
print('Checking of kitty build failed', file=sys.stderr)
if subprocess.call(cmd, env=env, cwd=build_frozen_launcher.writeable_src_dir) != 0:
print('Checking of kitty build failed, in directory:', build_frozen_launcher.writeable_src_dir, file=sys.stderr)
os.chdir(os.path.dirname(kitty_exe))
run_shell()
raise SystemExit('Checking of kitty build failed')
def build_frozen_tools(kitty_exe):
cmd = SETUP_CMD + ['--prefix', os.path.dirname(kitty_exe)] + ['build-frozen-tools']
if run(*cmd, cwd=build_frozen_launcher.writeable_src_dir) != 0:
print('Building of frozen kitten failed', file=sys.stderr)
os.chdir(KITTY_DIR)
run_shell()
raise SystemExit('Building of kitten launcher failed')
def sanitize_source_folder(path: str) -> None:
for q in walk(path):
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf'):

View File

@@ -1,3 +1,3 @@
image 'https://cloud-images.ubuntu.com/releases/bionic/release/ubuntu-18.04-server-cloudimg-{}.img'
deps 'bison flex libxcursor-dev libxrandr-dev libxi-dev libxinerama-dev libgl1-mesa-dev libxcb-xkb-dev libfontconfig1-dev libdbus-1-dev'
deps 'bison flex libxcursor-dev libxrandr-dev libxi-dev libxinerama-dev libgl1-mesa-dev libx11-xcb-dev libxcb-xkb-dev libfontconfig1-dev libdbus-1-dev'

View File

@@ -10,12 +10,8 @@ import subprocess
import tarfile
import time
from bypy.constants import (
OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
)
from bypy.freeze import (
extract_extension_modules, freeze_python, path_to_freeze_dir
)
from bypy.constants import OUTPUT_DIR, PREFIX, is64bit, python_major_minor_version
from bypy.freeze import extract_extension_modules, freeze_python, path_to_freeze_dir
from bypy.utils import get_dll_path, mkdtemp, py_compile, walk
j = os.path.join
@@ -238,10 +234,12 @@ def main():
files = find_binaries(env)
fix_permissions(files)
add_ca_certs(env)
kitty_exe = os.path.join(env.base, 'bin', 'kitty')
iv['build_frozen_tools'](kitty_exe)
if not args.dont_strip:
strip_binaries(files)
if not args.skip_tests:
iv['run_tests'](os.path.join(env.base, 'bin', 'kitty'))
iv['run_tests'](kitty_exe)
create_tarfile(env, args.compression_level)

View File

@@ -1,4 +1,4 @@
# Requires installation of XCode 10.3 and Python 3 and
# Requires installation of XCode 10.3 and go 1.19 and Python 3 and
# python3 -m pip install certifi
vm_name 'macos-kitty'

View File

@@ -13,16 +13,9 @@ import tempfile
import zipfile
from bypy.constants import PREFIX, PYTHON, SW, python_major_minor_version
from bypy.freeze import (
extract_extension_modules, freeze_python, path_to_freeze_dir
)
from bypy.macos_sign import (
codesign, create_entitlements_file, make_certificate_useable, notarize_app,
verify_signature
)
from bypy.utils import (
current_dir, mkdtemp, py_compile, run_shell, timeit, walk
)
from bypy.freeze import extract_extension_modules, freeze_python, path_to_freeze_dir
from bypy.macos_sign import codesign, create_entitlements_file, make_certificate_useable, notarize_app, verify_signature
from bypy.utils import current_dir, mkdtemp, py_compile, run_shell, timeit, walk
iv = globals()['init_env']
kitty_constants = iv['kitty_constants']
@@ -113,6 +106,9 @@ def do_sign(app_dir):
codesign(fw)
items = set(os.listdir('.')) - fw
codesign(expand_dirs(items))
# Sign kitten
with current_dir('MacOS'):
codesign('kitten')
# Now sign the main app
codesign(app_dir)
@@ -171,6 +167,7 @@ class Freeze(object):
self.add_misc_libraries()
self.freeze_python()
self.add_ca_certs()
self.build_frozen_tools()
if not self.dont_strip:
self.strip_files()
if not self.skip_tests:
@@ -378,6 +375,10 @@ class Freeze(object):
if f.endswith('.so') or f.endswith('.dylib'):
self.fix_dependencies_in_lib(f)
@flush
def build_frozen_tools(self):
iv['build_frozen_tools'](join(self.contents_dir, 'MacOS', 'kitty'))
@flush
def add_site_packages(self):
print('\nAdding site-packages')

View File

@@ -1 +1 @@
to_vm_excludes '/build /dist /kitty/launcher/kitty /.build-cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc'
to_vm_excludes '/build /dist /kitty/launcher/kitty* /.build-cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc *_generated.go'

View File

@@ -2,8 +2,8 @@
{
"name": "zlib",
"unix": {
"filename": "zlib-1.2.11.tar.xz",
"hash": "sha256:4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066",
"filename": "zlib-1.2.13.tar.xz",
"hash": "sha256:d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98",
"urls": ["https://zlib.net/{filename}"]
}
},

View File

@@ -21,10 +21,17 @@ kitty/options/parse.py
kitty/options/to-c-generated.h
kittens/diff/options/types.py
kittens/diff/options/parse.py
tools/wcswidth/std.go
'''
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)
p = subprocess.Popen([
'cloc', '--exclude-list-file', '/dev/stdin', 'kitty', 'kittens'
'cloc', '--exclude-list-file', '/dev/stdin', 'kitty', 'kittens', 'tools',
], stdin=subprocess.PIPE)
p.communicate(files_to_exclude.encode('utf-8'))
raise SystemExit(p.wait())

View File

@@ -27,6 +27,11 @@ Browse scrollback in less :sc:`show_scrollback`
Browse last cmd output :sc:`show_last_command_output` (see :ref:`shell_integration`)
========================= =======================
The scroll actions only take effect when the terminal is in the main screen.
When the alternate screen is active (for example when using a full screen
program like an editor) the key events are instead passed to program running in the
terminal.
Tabs
~~~~~~~~~~~

View File

@@ -22,7 +22,8 @@ simply re-run the command.
.. warning::
**Do not** copy the kitty binary out of the installation folder. If you want
to add it to your :envvar:`PATH`, create a symlink in :file:`~/.local/bin` or
:file:`/usr/bin` or wherever.
:file:`/usr/bin` or wherever. You should create a symlink for the :file:`kitten`
binary as well.
Manually installing
@@ -46,9 +47,9 @@ particular desktop, but it should work for most major desktop environments.
.. code-block:: sh
# Create a symbolic link to add kitty to PATH (assuming ~/.local/bin is in
# Create symbolic links to add kitty and kitten to PATH (assuming ~/.local/bin is in
# your system-wide PATH)
ln -s ~/.local/kitty.app/bin/kitty ~/.local/bin/
ln -sf ~/.local/kitty.app/bin/kitty ~/.local/kitty.app/bin/kitten ~/.local/bin/
# Place the kitty.desktop file somewhere it can be found by the OS
cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/
# If you want to open text files and images in kitty via your file manager also add the kitty-open.desktop file

View File

@@ -39,13 +39,14 @@ Run-time dependencies:
* ``freetype`` (not needed on macOS)
* ``fontconfig`` (not needed on macOS)
* ``libcanberra`` (not needed on macOS)
* ``ImageMagick`` (optional, needed to use the ``kitty +kitten icat`` tool to display images in the terminal)
* ``ImageMagick`` (optional, needed to display uncommon image formats in the terminal)
* ``pygments`` (optional, needed for syntax highlighting in ``kitty +kitten diff``)
Build-time dependencies:
* ``gcc`` or ``clang``
* ``go >= 1.20`` (see :file:`go.mod` for go packages used during building)
* ``pkg-config``
* For building on Linux in addition to the above dependencies you might also
need to install the following packages, if they are not already installed by

View File

@@ -35,6 +35,90 @@ mouse anywhere in the current command to move the cursor there. See
Detailed list of changes
-------------------------------------
0.27.1 [2023-02-07]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix :opt:`modify_font` not working for strikethrough position (:iss:`5946`)
- Fix a regression causing the ``edit-in-kitty`` command not working if :file:`kitten` is not added
to PATH (:iss:`5956`)
- icat kitten: Fix a regression that broke display of animated GIFs over SSH (:iss:`5958`)
- Wayland GNOME: Fix for ibus not working when using XWayland (:iss:`5967`)
- Fix regression in previous release that caused incorrect entries in terminfo for modifier+F3 key combinations (:pull:`5970`)
- Bring back the deprecated and removed ``kitty +complete`` and delegate it to :program:`kitten` for backward compatibility (:pull:`5977`)
- Bump the version of Go needed to build kitty to ``1.20`` so we can use the Go stdlib ecdh package for crypto.
0.27.0 [2023-01-31]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A new statically compiled, standalone executable, ``kitten`` (written in Go)
that can be used on all UNIX-like servers for remote control (``kitten @``),
viewing images (``kitten icat``), manipulating the clipboard (``kitten clipboard``), etc.
- :doc:`clipboard kitten </kittens/clipboard>`: Allow copying arbitrary data types to/from the clipboard, not just plain text
- Speed up the ``kitty @`` executable by ~10x reducing the time for typical
remote control commands from ~50ms to ~5ms
- icat kitten: Speed up by using POSIX shared memory when possible to transfer
image data to the terminal. Also support common image formats
GIF/PNG/JPEG/WEBP/TIFF/BMP out of the box without needing ImageMagick.
- Option :opt:`show_hyperlink_targets` to show the target of terminal hyperlinks when hovering over them with the mouse (:pull:`5830`)
- Keyboard protocol: Remove ``CSI R`` from the allowed encodings of the :kbd:`F3` key as it conflicts with the *Cursor Position Report* escape code (:disc:`5813`)
- Allow using the cwd of the original process for :option:`launch --cwd` (:iss:`5672`)
- Session files: Expand environment variables (:disc:`5917`)
- Pass key events mapped to scroll actions to the program running in the terminal when the terminal is in alternate screen mode (:iss:`5839`)
- Implement :ref:`edit-in-kitty <edit_file>` using the new ``kitten`` static executable (:iss:`5546`, :iss:`5630`)
- Add an option :opt:`background_tint_gaps` to control background image tinting for window gaps (:iss:`5596`)
- A new option :opt:`undercurl_style` to control the rendering of undercurls (:pull:`5883`)
- Bash integration: Fix ``clone-in-kitty`` not working on bash >= 5.2 if environment variable values contain newlines or other special characters (:iss:`5629`)
- A new :ac:`sleep` action useful in combine based mappings to make kitty sleep before executing the next action
- Wayland GNOME: Workaround for latest mutter release breaking full screen for semi-transparent kitty windows (:iss:`5677`)
- A new option :opt:`tab_title_max_length` to limit the length of tab (:iss:`5718`)
- When drawing the tab bar have the default left and right margins drawn in a color matching the neighboring tab (:iss:`5719`)
- When using the :code:`include` directive in :file:`kitty.conf` make the environment variable :envvar:`KITTY_OS` available for OS specific config
- Wayland: Fix signal handling not working with some GPU drivers (:iss:`4636`)
- Remote control: When matching windows allow using negative id numbers to match recently created windows (:iss:`5753`)
- ZSH Integration: Bind :kbd:`alt+left` and :kbd:`alt+right` to move by word if not already bound. This mimics the default bindings in Terminal.app (:iss:`5793`)
- macOS: Allow to customize :sc:`Hide <hide_macos_app>`, :sc:`Hide Others <hide_macos_other_apps>`, :sc:`Minimize <minimize_macos_window>`, and :sc:`Quit <quit>` global menu shortcuts. Note that :opt:`clear_all_shortcuts` will remove these shortcuts now (:iss:`948`)
- When a multi-key sequence does not match any action, send all key events to the child program (:pull:`5841`)
- broadcast kitten: Allow pressing a key to stop echoing of input into the broadcast window itself (:disc:`5868`)
- When reporting unused activity in a window, ignore activity that occurs soon after a window resize (:iss:`5881`)
- Fix using :opt:`cursor` = ``none`` not working on text that has reverse video (:iss:`5897`)
- Fix ssh kitten not working on FreeBSD (:iss:`5928`)
- macOS: Export kitty selected text to the system for use with services that accept it (patch by Sertaç Ö. Yıldız)
0.26.5 [2022-11-07]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -56,6 +140,7 @@ Detailed list of changes
- Remote control: When matching window by `state:focused` and no window currently has keyboard focus, match the window belonging to the OS window that was last focused (:iss:`5602`)
0.26.4 [2022-10-17]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -128,6 +213,7 @@ Detailed list of changes
code execution if the user clicked on a notification popup from a malicious
source. Thanks to Carter Sande for discovering this vulnerability.
0.26.1 [2022-08-30]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -137,6 +223,7 @@ Detailed list of changes
- Allow specifying a title when using the :ac:`set_tab_title` action (:iss:`5441`)
0.26.0 [2022-08-29]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1623,6 +1710,7 @@ Detailed list of changes
- Fix :option:`--title` not being applied at window creation time (:iss:`2570`)
0.17.2 [2020-03-29]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1807,6 +1895,7 @@ Detailed list of changes
- When windows are semi-transparent and all contain graphics, correctly render
them. (:iss:`2310`)
0.15.1 [2019-12-21]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1915,6 +2004,7 @@ Detailed list of changes
- Use selection foreground color for underlines as well (:iss:`1982`)
0.14.4 [2019-08-31]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2221,6 +2311,7 @@ Detailed list of changes
- Mouse selection: When extending by word, fix extending selection to non-word
characters not working well (:iss:`1616`)
0.13.3 [2019-01-19]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2314,6 +2405,7 @@ Detailed list of changes
- Fix resizing window smaller and then restoring causing some wrapped lines to not
be properly unwrapped (:iss:`1206`)
0.13.0 [2018-12-05]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2411,6 +2503,7 @@ Detailed list of changes
- Fix hover detection of URLs not working when hovering over the first colon
and slash characters in short URLs (:iss:`1201`)
0.12.3 [2018-09-29]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2487,6 +2580,7 @@ Detailed list of changes
- Fix using :opt:`focus_follows_mouse` causing text selection with the
mouse to malfunction when using multiple kitty windows (:iss:`1002`)
0.12.1 [2018-09-08]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2530,6 +2624,7 @@ Detailed list of changes
- macOS: Diff kitten: Fix syntax highlighting not working because of
a bug in the 0.12.0 macOS package
0.12.0 [2018-09-01]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3040,6 +3135,7 @@ Detailed list of changes
- Fix a crash when getting the contents of the scrollback buffer as text
0.8.1 [2018-03-09]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3117,6 +3213,7 @@ Detailed list of changes
- Browsing the scrollback buffer now happens in an overlay window instead of a
new window/tab.
0.7.1 [2018-01-31]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

160
docs/clipboard.rst Normal file
View File

@@ -0,0 +1,160 @@
Copying all data types to the clipboard
==============================================
There already exists an escape code to allow terminal programs to
read/write plain text data from the system clipboard, *OSC 52*.
kitty introduces a more advanced protocol that supports:
* Copy arbitrary data including images, rich text documents, etc.
* Allow terminals to ask the user for permission to access the clipboard and
report permission denied
The escape code is *OSC 5522*, an extension of *OSC 52*. The basic format
of the escape code is::
<OSC>5522;metadata;payload<ST>
Here, *metadata* is a colon separated list of key-value pairs and payload is
base64 encoded data. :code:`OSC` is :code:`<ESC>[`.
:code:`ST` is the string terminator, :code:`<ESC>\\`.
Reading data from the system clipboard
----------------------------------------
To read data from the system clipboard, the escape code is::
<OSC>5522;type=read;<base 64 encoded space separated list of mime types to read><ST>
For example, to read plain text and PNG data, the payload would be::
text/plain image/png
encoded as base64. To read from the primary selection instead of the
clipboard, add the key ``loc=primary`` to the metadata section.
To get the list of MIME types available on the clipboard the payload must be
just a period (``.``), encoded as base64.
The terminal emulator will reply with a sequence of escape codes of the form::
<OSC>5522;type=read:status=OK<ST>
<OSC>5522;type=read:status=DATA:mime=<base 64 encoded mime type>;<base64 encoded data><ST>
<OSC>5522;type=read:status=DATA:mime=<base 64 encoded mime type>;<base64 encoded data><ST>
.
.
.
<OSC>5522;type=read:status=DONE<ST>
Here, the ``status=DATA`` packets deliver the data (as base64 encoded bytes)
associated with each MIME type. The terminal emulator should chunk up the data
for an individual type. A recommended size for each chunk is 4096 bytes. All
the chunks for a given type must be transmitted sequentially and only once they
are done the chunks for the next type, if any, should be sent. The end of data
is indicated by a ``status=DONE`` packet.
If an error occurs, instead of the opening ``status=OK`` packet the terminal
must send a ``status=ERRORCODE`` packet. The error code must be one of:
``status=ENOSYS``
Sent if the requested clipboard type is not available. For example, primary
selection is not available on all systems and ``loc=primary`` was used.
``status=EPERM``
Sent if permission to read from the clipboard was denied by the system or
the user.
``status=EBUSY``
Sent if there is some temporary problem, such as multiple clients in a
multiplexer trying to access the clipboard simultaneously.
Terminals should ask the user for permission before allowing a read request.
However, if a read request only wishes to list the available data types on the
clipboard, it should be allowed without a permission prompt. This is so that
the user is not presented with a double permission prompt for reading the
available MIME types and then reading the actual data.
Writing data to the system clipboard
----------------------------------------
To write data to the system clipboard, the terminal programs sends the
following sequence of packets::
<OSC>5522;type=write<ST>
<OSC>5522;type=wdata:mime=<base64 encoded mime type>;<base 64 encoded chunk of data for this type><ST>
<OSC>5522;type=wdata:mime=<base64 encoded mime type>;<base 64 encoded chunk of data for this type><ST>
.
.
.
<OSC>5522;type=wdata<ST>
The final packet with no mime and no data indicates end of transmission. The
data for every MIME type should be split into chunks of no more than 4096
bytes. All the chunks for a given MIME type must be sent sequentially, before
sending chunks for the next MIME type. After the transmission is complete, the
terminal replies with a single packet indicating success::
<OSC>5522;type=write:status=DONE<ST>
If an error occurs the terminal can, at any time, send an error packet of the
form::
<OSC>5522;type=write:status=ERRORCODE<ST>
Here ``ERRORCODE`` must be one of:
``status=EIO``
An I/O error occurred while processing the data
``status=EINVAL``
One of the packets was invalid, usually because of invalid base64 encoding.
``status=ENOSYS``
The client asked to write to the primary selection with (``loc=primary``) and that is not
available on the system
``status=EPERM``
Sent if permission to write to the clipboard was denied by the system or
the user.
``status=EBUSY``
Sent if there is some temporary problem, such as multiple clients in a
multiplexer trying to access the clipboard simultaneously.
Once an error occurs, the terminal must ignore all further OSC 5522 write related packets until it
sees the start of a new write with a ``type=write`` packet.
The client can send to the primary selection instead of the clipboard by adding
``loc=primary`` to the initial ``type=write`` packet.
Finally, clients have the ability to *alias* MIME types when sending data to
the clipboard. To do that, the client must send a ``type=walias`` packet of the
form::
<OSC>5522;type=walias;mime=<base64 encoded target MIME type>;<base64 encoded, space separated list of aliases><ST>
The effect of an alias is that the system clipboard will make available all the
aliased MIME types, with the same data as was transmitted for the target MIME
type. This saves bandwidth, allowing the client to only transmit one copy of
the data, but create multiple references to it in the system clipboard. Alias
packets can be sent anytime after the initial write packet and before the end
of data packet.
Support for terminal multiplexers
------------------------------------
Since this protocol involves two way communication between the terminal
emulator and the client program, multiplexers need a way to know which window
to send responses from the terminal to. In order to make this possible, the
metadata portion of this escape code includes an optional ``id`` field. If
present the terminal emulator must send it back unchanged with every response.
Valid ids must include only characters from the set: ``[a-zA-Z0-9-_+.]``. Any
other characters must be stripped out from the id by the terminal emulator
before retransmitting it.
Note that when using a terminal multiplexer it is possible for two different
programs to tread on each others clipboard requests. This is fundamentally
unavoidable since the system clipboard is a single global shared resource.
However, there is an additional complication where responses form this protocol
could get lost if, for instance, multiple write requests are received
simultaneously. It is up to well designed multiplexers to ensure that only a
single request is in flight at a time. The multiplexer can abort requests by
sending back the ``EBUSY`` error code indicating some other window is trying
to access the clipboard.

View File

@@ -18,9 +18,7 @@ from typing import Any, Callable, Dict, Iterable, List, Tuple
from docutils import nodes
from docutils.parsers.rst.roles import set_classes
from pygments.lexer import RegexLexer, bygroups # type: ignore
from pygments.token import ( # type: ignore
Comment, Keyword, Literal, Name, Number, String, Whitespace
)
from pygments.token import Comment, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
from sphinx import addnodes, version_info
from sphinx.util.logging import getLogger
@@ -215,10 +213,10 @@ def commit_role(
# CLI docs {{{
def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
from kitty.cli import option_spec_as_rst
from kitty.launch import options_spec as launch_options_spec
from kittens.ssh.copy import option_text
from kittens.ssh.options.definition import copy_message
from kitty.cli import option_spec_as_rst
from kitty.launch import options_spec as launch_options_spec
with open('generated/ssh-copy.rst', 'w') as f:
f.write(option_spec_as_rst(
appname='copy', ospec=option_text, heading_char='^',
@@ -255,6 +253,8 @@ if you specify a program-to-run you can use the special placeholder
p('.. program::', 'kitty @', func.name)
p('\n\n' + as_rst(*cli_params_for(func)))
from kittens.runner import get_kitten_cli_docs
from kitty.fast_data_types import wrapped_kitten_names
for kitten in all_kitten_names:
data = get_kitten_cli_docs(kitten)
if data:
@@ -263,7 +263,11 @@ if you specify a program-to-run you can use the special placeholder
p('.. program::', 'kitty +kitten', kitten)
p('\nSource code for', kitten)
p('-' * 72)
p(f'\nThe source code for this kitten is `available on GitHub <https://github.com/kovidgoyal/kitty/tree/master/kittens/{kitten}>`_.')
if kitten in wrapped_kitten_names():
scurl = f'https://github.com/kovidgoyal/kitty/tree/master/tools/cmd/{kitten}'
else:
scurl = f'https://github.com/kovidgoyal/kitty/tree/master/kittens/{kitten}'
p(f'\nThe source code for this kitten is `available on GitHub <{scurl}>`_.')
p('\nCommand Line Interface')
p('-' * 72)
p('\n\n' + option_spec_as_rst(
@@ -274,9 +278,7 @@ if you specify a program-to-run you can use the special placeholder
def write_remote_control_protocol_docs() -> None: # {{{
from kitty.rc.base import (
RemoteCommand, all_command_names, command_for_name
)
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
field_pat = re.compile(r'\s*([^:]+?)\s*:\s*(.+)')
def format_cmd(p: Callable[..., None], name: str, cmd: RemoteCommand) -> None:

View File

@@ -27,11 +27,13 @@ line.
.. _include:
You can include secondary config files via the :code:`include` directive. If
You can include secondary config files via the :code:`include` directive. If
you use a relative path for :code:`include`, it is resolved with respect to the
location of the current config file. Note that environment variables are
expanded, so :code:`${USER}.conf` becomes :file:`name.conf` if
:code:`USER=name`. Also, you can use :code:`globinclude` to include files
:code:`USER=name`. A special environment variable :envvar:`KITTY_OS` is available,
to detect the operating system. It is ``linux``, ``macos`` or ``bsd``.
Also, you can use :code:`globinclude` to include files
matching a shell glob pattern and :code:`envinclude` to include configuration
from environment variables. For example::
@@ -66,6 +68,11 @@ Sample kitty.conf
pre-existing :file:`kitty.conf`, then that will be used instead, delete it to
see the sample file.
A default configuration file can also be generated by running::
kitty +runpy 'from kitty.config import *; print(commented_out_default_config())'
This will print the commented out default config file to :file:`STDOUT`.
All mappable actions
------------------------

View File

@@ -50,7 +50,8 @@ and the terminal emulator should hold off displaying it. A value of ``1`` means
the notification is done, and should be displayed. You can specify the title or
body multiple times and the terminal emulator will concatenate them, thereby
allowing arbitrarily long text (terminal emulators are free to impose a sensible
limit to avoid Denial-of-Service attacks).
limit to avoid Denial-of-Service attacks). The size of the payload must be no
longer than ``2048`` bytes, *before being encoded*.
Both the ``title`` and ``body`` payloads must be either UTF-8 encoded plain
text with no embedded escape codes, or UTF-8 text that is Base64 encoded, in

View File

@@ -27,96 +27,145 @@ turned off for specific symbols using :opt:`narrow_symbols`.
Using a color theme with a background color does not work well in vim?
-----------------------------------------------------------------------
First make sure you have not changed the :envvar:`TERM` environment variable, it
should be ``xterm-kitty``. vim uses *background color erase* even if the
terminfo file does not contain the ``bce`` capability. This is a bug in vim. You
can work around it by adding the following to your vimrc::
Sadly, vim has very poor out-of-the-box detection for modern terminal features.
Furthermore, it `recently broke detection even more <https://github.com/vim/vim/issues/11729>`__.
It kind of, but not really, supports terminfo, except it overrides it with its own hard-coded
values when it feels like it. Worst of all, it has no ability to detect modern
features not present in terminfo, at all, even security sensitive ones like
bracketed paste.
Thankfully, probably as a consequence of this lack of detection, vim allows users to
configure these low level details. So, to make vim work well with any modern
terminal, including kitty, add the following to your :file:`~/.vimrc`.
.. code-block:: vim
" Mouse support
set mouse=a
set ttymouse=sgr
set balloonevalterm
" Styled and colored underline support
let &t_AU = "\e[58:5:%dm"
let &t_8u = "\e[58:2:%lu:%lu:%lum"
let &t_Us = "\e[4:2m"
let &t_Cs = "\e[4:3m"
let &t_ds = "\e[4:4m"
let &t_Ds = "\e[4:5m"
let &t_Ce = "\e[4:0m"
" Strikethrough
let &t_Ts = "\e[9m"
let &t_Te = "\e[29m"
" Truecolor support
let &t_8f = "\e[38:2:%lu:%lu:%lum"
let &t_8b = "\e[48:2:%lu:%lu:%lum"
let &t_RF = "\e]10;?\e\\"
let &t_RB = "\e]11;?\e\\"
" Bracketed paste
let &t_BE = "\e[?2004h"
let &t_BD = "\e[?2004l"
let &t_PS = "\e[200~"
let &t_PE = "\e[201~"
" Cursor control
let &t_RC = "\e[?12$p"
let &t_SH = "\e[%d q"
let &t_RS = "\eP$q q\e\\"
let &t_SI = "\e[5 q"
let &t_SR = "\e[3 q"
let &t_EI = "\e[1 q"
let &t_VS = "\e[?12l"
" Focus tracking
let &t_fe = "\e[?1004h"
let &t_fd = "\e[?1004l"
execute "set <FocusGained>=\<Esc>[I"
execute "set <FocusLost>=\<Esc>[O"
" Window title
let &t_ST = "\e[22;2t"
let &t_RT = "\e[23;2t"
" vim hardcodes background color erase even if the terminfo file does
" not contain bce. This causes incorrect background rendering when
" using a color theme with a background color in terminals such as
" kitty that do not support background color erase.
let &t_ut=''
See :doc:`here <deccara>` for why |kitty| does not support background color
erase.
These settings must be placed **before** setting the ``colorscheme``. It is
also important that the value of the vim ``term`` variable is not changed
after these settings.
I get errors about the terminal being unknown or opening the terminal failing or functional keys like arrow keys don't work?
-------------------------------------------------------------------------------------------------------------------------------
I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer?
-----------------------------------------------------------------------------------------------------------------------
This happens because the |kitty| terminfo files are not available on the server.
You can ssh in using the following command which will automatically copy the
terminfo files to the server::
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
It will automatically copy over the terminfo files and also magically enable
:doc:`shell integration </shell-integration>` on the remote machine.
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"
If the ssh kitten fails, use the following one-liner instead (it is slower as it
needs to ssh into the server twice, but will work with most servers)::
If this does not work, see :ref:`manual_terminfo_copy` for alternative ways to
get the kitty terminfo files onto a remote computer.
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
The next most common reason for this is if you are running commands as root
using :program:`sudo` or :program:`su`. These programs often filter the
:envvar:`TERMINFO` environment variable which is what points to the kitty
terminfo files.
If you are behind a proxy (like Balabit) that prevents this, or :program:`tic`
comes with macOS that does not support reading from STDIN, you must redirect the
first command to a file, copy that to the server and run :program:`tic`
manually. If you connect to a server, embedded or Android system that doesn't
have :program:`tic`, copy over your local file terminfo to the other system as
:file:`~/.terminfo/x/xterm-kitty`.
First, make sure the :envvar:`TERM` is set to ``xterm-kitty`` in the sudo
environment. By default, it should be automatically copied over.
Really, the correct solution for this is to convince the OpenSSH maintainers to
have :program:`ssh` do this automatically, if possible, when connecting to a
server, so that all terminals work transparently.
If you are using a well maintained Linux distribution, it will have a
``kitty-terminfo`` package that you can simply install to make the kitty
terminfo files available system-wide. Then the problem will no longer occur.
If the server is running FreeBSD, or another system that relies on termcap
rather than terminfo, you will need to convert the terminfo file on your local
machine by running (on local machine with |kitty|)::
infocmp -CrT0 xterm-kitty
The output of this command is the termcap description, which should be appended
to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
command to apply your change (on the server)::
cap_mkdb /usr/share/misc/termcap
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
-------------------------------------------------------------------------------------------------
Make sure the :envvar:`TERM` environment variable, is ``xterm-kitty``. And
either the :envvar:`TERMINFO` environment variable points to a directory
containing :file:`x/xterm-kitty` or that file is under :file:`~/.terminfo/x/`.
For macOS, you may also need to put that file under :file:`~/.terminfo/78/`::
mkdir -p ~/.terminfo/{78,x}
ln -snf ../x/xterm-kitty ~/.terminfo/78/xterm-kitty
tic -x -o ~/.terminfo "$KITTY_INSTALLATION_DIR/terminfo/kitty.terminfo"
Note that :program:`sudo` might remove :envvar:`TERMINFO`. Then setting it at
the shell prompt can be too late, because command line editing may not be
reinitialized. In that case you can either ask :program:`sudo` to set it or if
that is not supported, insert an :program:`env` command before starting the
shell, or, if not possible, after sudo start another shell providing the right
terminfo path::
sudo … TERMINFO=$HOME/.terminfo bash -i
sudo … env TERMINFO=$HOME/.terminfo bash -i
TERMINFO=/home/ORIGINALUSER/.terminfo exec bash -i
You can configure :program:`sudo` to preserve :envvar:`TERMINFO` by running
``sudo visudo`` and adding the following line::
Alternately, you can configure :program:`sudo` to preserve :envvar:`TERMINFO`
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::
sudo TERMINFO="$TERMINFO" -s -H
This will start a new root shell with the correct :envvar:`TERMINFO` value from your
current environment copied over.
If you have double width characters in your prompt, you may also need to
explicitly set a UTF-8 locale, like::
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
I cannot use the key combination X in program Y?
-------------------------------------------------------
First, run::
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.
You need to report the issue to the developer of the terminal program. Most
likely they have not added support for :doc:`/keyboard-protocol`.
If the kitten does not report it, it means that the key is bound to some action
in kitty. You can unbind it in :file:`kitty.conf` with:
.. code-block:: conf
map X no_op
Here X is the keys you press on the keyboard. So for example
:kbd:`ctrl+shift+1`.
How do I change the colors in a running kitty instance?
------------------------------------------------------------

View File

@@ -212,3 +212,8 @@ Variables that kitty sets when running child programs
Set when enabling :ref:`shell_integration` with :program:`bash`, allowing
:program:`bash` to automatically load the integration script.
.. envvar:: KITTY_OS
Set when using the include directive in kitty.conf. Can take values:
``linux``, ``macos``, ``bsd``.

View File

@@ -28,15 +28,14 @@ alpha-blending and text over graphics.
Some programs and libraries that use the kitty graphics protocol:
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with image previews
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
* `tpix <https://github.com/jesvedberg/tpix>`_ - a statically compiled binary that can be used to display images and easily installed on remote servers without root access
* `mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_ - A video player that can play videos in the terminal
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
information tool
* `viu <https://github.com/atanunq/viu>`_ - a terminal image viewer
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
* `ctx.graphics <https://ctx.graphics/>`_ - Library for drawing graphics
* `timg <https://github.com/hzeller/timg>`_ - a terminal image and video viewer
* `notcurses <https://github.com/dankamongmen/notcurses>`_ - C library for terminal graphics with bindings for C++, Rust and Python
@@ -44,6 +43,7 @@ Some programs and libraries that use the kitty graphics protocol:
* `chafa <https://github.com/hpjansson/chafa>`_ - a terminal image viewer
* `hologram.nvim <https://github.com/edluffy/hologram.nvim>`_ - view images inside nvim
* `term-image <https://github.com/AnonymouX47/term-image>`_ - A Python library, CLI and TUI to display and browse images in the terminal
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
Other terminals that have implemented the graphics protocol:
@@ -88,6 +88,17 @@ code to demonstrate its use
'number of rows: {} number of columns: {}'
'screen width: {} screen height: {}').format(*buf))
.. tab:: Go
.. code-block:: go
import "golang.org/x/sys/unix"
fd, err := unix.Open(fd, unix.O_NOCTTY|unix.O_CLOEXEC|unix.O_NDELAY|unix.O_RDWR, 0666)
sz, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
fmt.Println("rows: %v columns: %v width: %v height %v", sz.Row, sz.Col, sz.Xpixel, sz.Ypixel)
Note that some terminals return ``0`` for the width and height values. Such
terminals should be modified to return the correct values. Examples of
terminals that return correct values: ``kitty, xterm``
@@ -101,47 +112,71 @@ kitty.
A minimal example
------------------
Some minimal python code to display PNG images in kitty, using the most basic
Some minimal code to display PNG images in kitty, using the most basic
features of the graphics protocol:
.. code-block:: python
.. tab:: Bash
import sys
from base64 import standard_b64encode
.. code-block:: sh
#!/bin/bash
transmit_png() {
data=$(base64 "$1")
data="${data//[[:space:]]}"
builtin local pos=0
builtin local chunk_size=4096
while [ $pos -lt ${#data} ]; do
builtin printf "\e_G"
[ $pos = "0" ] && printf "a=T,f=100,"
builtin local chunk="${data:$pos:$chunk_size}"
pos=$(($pos+$chunk_size))
[ $pos -lt ${#data} ] && builtin printf "m=1"
[ ${#chunk} -gt 0 ] && builtin printf ";%s" "${chunk}"
builtin printf "\e\\"
done
}
transmit_png "$1"
.. tab:: Python
.. code-block:: python
#!/usr/bin/python
import sys
from base64 import standard_b64encode
def serialize_gr_command(**cmd):
payload = cmd.pop('payload', None)
cmd = ','.join(f'{k}={v}' for k, v in cmd.items())
ans = []
w = ans.append
w(b'\033_G'), w(cmd.encode('ascii'))
if payload:
w(b';')
w(payload)
w(b'\033\\')
return b''.join(ans)
def write_chunked(**cmd):
data = standard_b64encode(cmd.pop('data'))
while data:
chunk, data = data[:4096], data[4096:]
m = 1 if data else 0
sys.stdout.buffer.write(serialize_gr_command(payload=chunk, m=m,
**cmd))
sys.stdout.flush()
cmd.clear()
with open(sys.argv[-1], 'rb') as f:
write_chunked(a='T', f=100, data=f.read())
def serialize_gr_command(**cmd):
payload = cmd.pop('payload', None)
cmd = ','.join(f'{k}={v}' for k, v in cmd.items())
ans = []
w = ans.append
w(b'\033_G'), w(cmd.encode('ascii'))
if payload:
w(b';')
w(payload)
w(b'\033\\')
return b''.join(ans)
def write_chunked(**cmd):
data = standard_b64encode(cmd.pop('data'))
while data:
chunk, data = data[:4096], data[4096:]
m = 1 if data else 0
sys.stdout.buffer.write(serialize_gr_command(payload=chunk, m=m,
**cmd))
sys.stdout.flush()
cmd.clear()
with open(sys.argv[-1], 'rb') as f:
write_chunked(a='T', f=100, data=f.read())
Save this script as :file:`png.py`, then you can use it to display any PNG
Save this script as :file:`send-png`, then you can use it to display any PNG
file in kitty as::
python png.py file.png
chmod +x send-png
./send-png file.png
The graphics escape code
@@ -295,12 +330,13 @@ sequence of escape codes to the terminal emulator::
<ESC>_Gm=0;<encoded pixel data last chunk><ESC>\
Note that only the first escape code needs to have the full set of control
codes such as width, height, format etc. Subsequent chunks **must** have
only the ``m`` key. The client **must** finish sending all chunks for a single image
before sending any other graphics related escape codes. Note that the cursor
position used to display the image **must** be the position when the final chunk is
received. Finally, terminals must not display anything, until the entire sequence is
received and validated.
codes such as width, height, format, etc. Subsequent chunks **must** have only
the ``m`` and optionally ``q`` keys. When sending animation frame data, subsequent
chunks **must** also specify the ``a=f`` key. The client **must** finish sending
all chunks for a single image before sending any other graphics related escape
codes. Note that the cursor position used to display the image **must** be the
position when the final chunk is received. Finally, terminals must not display
anything, until the entire sequence is received and validated.
Querying support and available transmission mediums

View File

@@ -80,6 +80,12 @@ base application that uses kitty's graphics protocol for images.
A text mode WWW browser that supports kitty's graphics protocol to display
images.
.. _tool_mpv:
`mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A video player that can play videos in the terminal.
.. _tool_timg:
`timg <https://github.com/hzeller/timg>`_

View File

@@ -40,7 +40,8 @@ In addition to kitty, this protocol is also implemented in:
<https://github.com/dankamongmen/notcurses/issues/2131>`__
* The `crossterm library
<https://github.com/crossterm-rs/crossterm/pull/688>`__
* The `neovim text editor <https://github.com/neovim/neovim/pull/18181>`__
* The `Vim text editor <https://github.com/vim/vim/commit/63a2e360cca2c70ab0a85d14771d3259d4b3aafa>`__
* The `Neovim text editor <https://github.com/neovim/neovim/pull/18181>`__
* The `kakoune text editor <https://github.com/mawww/kakoune/issues/4103>`__
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
@@ -60,14 +61,14 @@ without too many changes, do the following:
that are easy to parse unambiguously.
#. Emit the escape sequence ``CSI < u`` at application exit if using the main
screen or just before leaving alternate screen mode if using the alternate screen,
to restore the previously used keyboard mode.
to restore whatever the keyboard mode was before step 1.
Key events will all be delivered to your application either as plain UTF-8
text, or using the following escape codes, for those keys that do not produce
text (``CSI`` is the bytes ``0x1b 0x5b``)::
CSI number ; modifiers [u~]
CSI 1; modifiers [ABCDEFHPQRS]
CSI 1; modifiers [ABCDEFHPQS]
0x0d - for the Enter key
0x7f or 0x08 - for Backspace
0x09 - for Tab
@@ -82,7 +83,7 @@ The second form is used for a few functional keys, such as the :kbd:`Home`,
:kbd:`End`, :kbd:`Arrow` keys and :kbd:`F1` ... :kbd:`F4`, they are enumerated in
the :ref:`functional` table below. Note that if no modifiers are present the
parameters are omitted entirely giving an escape code of the form ``CSI
[ABCDEFHPQRS]``.
[ABCDEFHPQS]``.
If you want support for more advanced features such as repeat and release
events, alternate keys for shortcut matching et cetera, these can be turned on
@@ -313,7 +314,7 @@ With this flag turned on, all key events that do not generate text are
represented in one of the following two forms::
CSI number; modifier u
CSI 1; modifier [~ABCDEFHPQRS]
CSI 1; modifier [~ABCDEFHPQS]
This makes it very easy to parse key events in an application. In particular,
:kbd:`ctrl+c` will no longer generate the ``SIGINT`` signal, but instead be
@@ -404,7 +405,7 @@ Legacy functional keys
These keys are encoded using three schemes::
CSI number ; modifier ~
CSI 1 ; modifier {ABCDEFHPQRS}
CSI 1 ; modifier {ABCDEFHPQS}
SS3 {ABCDEFHPQRS}
In the above, if there are no modifiers, the modifier parameter is omitted.
@@ -532,7 +533,7 @@ compatibility reasons.
"NUM_LOCK", "``57360 u``", "PRINT_SCREEN", "``57361 u``"
"PAUSE", "``57362 u``", "MENU", "``57363 u``"
"F1", "``1 P or 11 ~``", "F2", "``1 Q or 12 ~``"
"F3", "``1 R or 13 ~``", "F4", "``1 S or 14 ~``"
"F3", "``13 ~``", "F4", "``1 S or 14 ~``"
"F5", "``15 ~``", "F6", "``17 ~``"
"F7", "``18 ~``", "F8", "``19 ~``"
"F9", "``20 ~``", "F10", "``21 ~``"
@@ -581,8 +582,14 @@ compatibility reasons.
.. end functional key table
.. }}}
Note that the escape codes above of the form ``CSI 1 letter`` will omit the
``1`` if there are no modifiers, since ``1`` is the default value.
.. note::
The escape codes above of the form ``CSI 1 letter`` will omit the
``1`` if there are no modifiers, since ``1`` is the default value.
.. note::
The original version of this specification allowed F3 to be encoded as both
CSI R and CSI ~. However, CSI R conflicts with the Cursor Position Report,
so it was removed.
.. _ctrl_mapping:
@@ -675,3 +682,31 @@ specification.
* Handwaves that :kbd:`ctrl` *tends to* mask with ``0x1f``. In actual fact it
does this only for some keys. The action of :kbd:`ctrl` is not specified and
varies between terminals, historically because of different keyboard layouts.
Why xterm's modifyOtherKeys should not be used
---------------------------------------------------
* Does not support release events
* Does not fix the issue of :kbd:`Esc` key presses not being distinguishable from
escape codes.
* Does not fix the issue of some keypresses generating identical bytes and thus
being indistinguishable
* There is no robust way to query it or manage its state from a program running
in the terminal.
* No support for shifted keys.
* No support for alternate keyboard layouts.
* No support for modifiers beyond the basic four.
* No support for lock keys like Num lock and Caps lock.
* Is completely unspecified. The most discussion of it available anywhere is
`here <https://invisible-island.net/xterm/modified-keys.html>`__
And it contains no specification of what numbers to assign to what function
keys beyond running a Perl script on an X11 system!!

View File

@@ -11,14 +11,46 @@ from the shell. It even works over SSH. Using it is as simple as::
echo hooray | kitty +kitten clipboard
All text received on :file:`stdin` is copied to the clipboard.
All text received on :file:`STDIN` is copied to the clipboard.
To get text from the clipboard you have to enable reading of the clipboard
in :opt:`clipboard_control` in :file:`kitty.conf`. Once you do that, you can
use::
To get text from the clipboard::
kitty +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
controlled via :opt:`clipboard_control`.
.. versionadded:: 0.27.0
Support for copying arbitrary data types
The clipboard kitten can be used to send/receive
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
# Copy an image and some text to the clipboard:
kitty +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
# Copy any raster image available on the clipboard to a PNG file:
kitty +kitten clipboard -g picture.png
# Copy an image to a file and text to STDOUT:
kitty +kitten clipboard -g picture.png /dev/stdout
# List the formats available on the system clipboard
kitty +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.
This kitten uses a new protocol developed by kitty to function, for details,
see :doc:`/clipboard`.
.. program:: kitty +kitten clipboard

View File

@@ -43,46 +43,18 @@ You can now run searches with::
hg some-search-term
If you want to enable completion, for the kitten, you can delegate completion
to :program:`rg`. How to do that varies based on the shell:
.. tab:: zsh
Instead of using an alias, create a simple wrapper script named
:program:`hg` somewhere in your :envvar:`PATH`:
.. code-block:: sh
#!/bin/sh
exec kitty +kitten hyperlinked_grep "$@"
Then, add the following to :file:`.zshrc`::
compdef _rg hg
.. tab:: fish
You can combine both the aliasing/wrapping and pointing fish to ripgrep's
autocompletion with a fish wrapper function in your :file:`config.fish`
or :file:`~/.config/fish/functions/hg.fish`:
.. code-block:: fish
function hg --wraps rg; kitty +kitten hyperlinked_grep $argv; end
To learn more about kitty's powerful framework for customizing URL click
actions, see :doc:`here </open_actions>`.
By default, this kitten adds hyperlinks for several parts of ripgrep output:
the per-file header, match context lines, and match lines. You can control
which items are linked with a :command:`--kitten hyperlink` flag. For example,
:command:`--kitten hyperlink=matching_lines` will only add hyperlinks to the
match lines. :command:`--kitten hyperlink=file_headers,context_lines` will link
file headers and context lines but not match lines. :command:`--kitten
which items are linked with a :code:`--kitten hyperlink` flag. For example,
:code:`--kitten hyperlink=matching_lines` will only add hyperlinks to the
match lines. :code:`--kitten hyperlink=file_headers,context_lines` will link
file headers and context lines but not match lines. :code:`--kitten
hyperlink=none` will cause the command line to be passed to directly to
:command:`rg` so no hyperlinking will be performed. :command:`--kitten
hyperlink` may be specified multiple times.
:command:`rg` so no hyperlinking will be performed. :code:`--kitten hyperlink`
may be specified multiple times.
Hopefully, someday this functionality will make it into some `upstream grep
<https://github.com/BurntSushi/ripgrep/issues/665>`__ program directly removing
@@ -93,3 +65,9 @@ the need for this kitten.
While you can pass any of ripgrep's comand line options to the kitten and
they will be forwarded to :program:`rg`, do not use options that change the
output formatting as the kitten works by parsing the output from ripgrep.
The unsupported options are: :code:`--context-separator`,
:code:`--field-context-separator`, :code:`--field-match-separator`,
:code:`--json`, :code:`-I --no-filename`, :code:`-0 --null`,
:code:`--null-data`, :code:`--path-separator`. If you specify options via
configuration file, then any changes to the default output format will not be
supported, not just the ones listed.

View File

@@ -7,6 +7,7 @@ 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
It supports all image types supported by `ImageMagick
<https://www.imagemagick.org>`__. It even works over SSH. For details, see the
@@ -20,8 +21,9 @@ Then you can simply use ``icat image.png`` to view images.
.. note::
`ImageMagick <https://www.imagemagick.org>`__ must be installed for icat
kitten to work.
`ImageMagick <https://www.imagemagick.org>`__ must be installed for the
full range of image types. Without it only PNG/JPG/GIF/BMP/TIFF/WEBP are
supported.
.. note::
@@ -35,16 +37,15 @@ Then you can simply use ``icat image.png`` to view images.
The ``icat`` kitten has various command line arguments to allow it to be used
from inside other programs to display images. In particular, :option:`--place`,
:option:`--detect-support`, :option:`--silent` and
:option:`--print-window-size`.
:option:`--detect-support` and :option:`--print-window-size`.
If you are trying to integrate icat into a complex program like a file manager
or editor, there are a few things to keep in mind. icat works by communicating
over the TTY device, it both writes to and reads from the TTY. So it is
imperative that while it is running the host program does not do any TTY I/O.
Any key presses or other input from the user on the TTY device will be
discarded. At a minimum, you should use the :option:`--silent` and
:option:`--transfer-mode` command line arguments. To be really robust you should
discarded. At a minimum, you should use the :option:`--transfer-mode`
command line arguments. To be really robust you should
consider writing proper support for the :doc:`kitty graphics protocol
</graphics-protocol>` in the program instead. Nowadays there are many libraries
that have support for it.

View File

@@ -162,3 +162,42 @@ The copy command
--------------------
.. include:: /generated/ssh-copy.rst
.. _manual_terminfo_copy:
Copying terminfo files manually
-------------------------------------
Sometimes, the ssh kitten can fail, or maybe you dont like to use it. In such
cases, the terminfo files can be copied over manually to a server with the
following one liner::
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
If you are behind a proxy (like Balabit) that prevents this, or you are SSHing
into macOS where the :program:`tic` does not support reading from :file:`STDIN`,
you must redirect the first command to a file, copy that to the server and run :program:`tic`
manually. If you connect to a server, embedded, or Android system that doesn't
have :program:`tic`, copy over your local file terminfo to the other system as
:file:`~/.terminfo/x/xterm-kitty`.
If the server is running a relatively modern Linux distribution and you have
root access to it, you could simply install the ``kitty-terminfo`` package on
the server to make the terminfo files available.
Really, the correct solution for this is to convince the OpenSSH maintainers to
have :program:`ssh` do this automatically, if possible, when connecting to a
server, so that all terminals work transparently.
If the server is running FreeBSD, or another system that relies on termcap
rather than terminfo, you will need to convert the terminfo file on your local
machine by running (on local machine with |kitty|)::
infocmp -CrT0 xterm-kitty
The output of this command is the termcap description, which should be appended
to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
command to apply your change (on the server)::
cap_mkdb /usr/share/misc/termcap

View File

@@ -1,295 +0,0 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import argparse
import base64
import hashlib
import json
import os
import sys
import termios
import time
import tty
from contextlib import contextmanager
from ctypes import (
CDLL, POINTER, byref, c_char_p, c_int, c_size_t, c_void_p,
create_string_buffer
)
from ctypes.util import find_library
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat
def build_crypto_tools(): # {{{
class EVP_PKEY_POINTER(c_void_p):
algorithm = 0
def __del__(self):
EVP_PKEY_free(self)
@property
def public(self):
sz = c_size_t(0)
EVP_PKEY_get_raw_public_key(self, None, byref(sz))
buf = create_string_buffer(sz.value)
EVP_PKEY_get_raw_public_key(self, buf, byref(sz))
return buf.raw
def derive_secret(self, pubkey):
pubkey = EVP_PKEY_new_raw_public_key(self.algorithm, None, pubkey, len(pubkey))
ctx = EVP_PKEY_CTX_new(self, None)
EVP_PKEY_derive_init(ctx)
EVP_PKEY_derive_set_peer(ctx, pubkey)
sz = c_size_t(0)
EVP_PKEY_derive(ctx, None, byref(sz))
buf = create_string_buffer(sz.value)
EVP_PKEY_derive(ctx, buf, byref(sz))
return hashlib.sha256(buf.raw).digest()
class EVP_PKEY_CTX_POINTER(c_void_p):
def __del__(self):
EVP_PKEY_CTX_free(self)
class EVP_CIPHER_CTX_POINTER(c_void_p):
def __del__(self):
EVP_CIPHER_CTX_free(self)
class EVP_CIPHER_POINTER(c_void_p):
pass
cl = find_library('crypto')
if not cl:
raise SystemExit('Failed to find libcrypto on your system, make sure OpenSSL is installed')
crypto = CDLL(cl)
libc = CDLL(None)
def create_crypto_func(name, *argtypes, restype=c_int, int_return_ok=lambda x: x == 1):
impl = getattr(crypto, name)
impl.restype = restype
impl.argtypes = argtypes
def func(*a):
res = impl(*a)
if restype is c_int:
if not int_return_ok(res):
print('Call to', name, 'failed with return code:', res, file=sys.stderr)
abort_on_openssl_error()
elif restype is not None and issubclass(restype, c_void_p):
if res.value is None:
print('Call to', name, 'failed with NULL return', file=sys.stderr)
abort_on_openssl_error()
return res
return func
OBJ_txt2nid = create_crypto_func('OBJ_txt2nid', c_char_p, int_return_ok=bool)
EVP_PKEY_CTX_new_id = create_crypto_func('EVP_PKEY_CTX_new_id', c_int, c_void_p, restype=EVP_PKEY_CTX_POINTER)
EVP_PKEY_CTX_new = create_crypto_func('EVP_PKEY_CTX_new', EVP_PKEY_POINTER, c_void_p, restype=EVP_PKEY_CTX_POINTER)
EVP_PKEY_keygen_init = create_crypto_func('EVP_PKEY_keygen_init', EVP_PKEY_CTX_POINTER)
EVP_PKEY_keygen = create_crypto_func('EVP_PKEY_keygen', EVP_PKEY_CTX_POINTER, POINTER(EVP_PKEY_POINTER))
ERR_print_errors_fp = create_crypto_func('ERR_print_errors_fp', c_void_p, restype=None)
EVP_PKEY_free = create_crypto_func('EVP_PKEY_free', EVP_PKEY_POINTER, restype=None)
EVP_PKEY_CTX_free = create_crypto_func('EVP_PKEY_CTX_free', EVP_PKEY_CTX_POINTER, restype=None)
EVP_PKEY_get_raw_public_key = create_crypto_func('EVP_PKEY_get_raw_public_key', EVP_PKEY_POINTER, c_char_p, POINTER(c_size_t))
EVP_PKEY_new_raw_public_key = create_crypto_func('EVP_PKEY_new_raw_public_key', c_int, c_void_p, c_char_p, c_size_t, restype=EVP_PKEY_POINTER)
EVP_PKEY_derive_init = create_crypto_func('EVP_PKEY_derive_init', EVP_PKEY_CTX_POINTER)
EVP_PKEY_derive_set_peer = create_crypto_func('EVP_PKEY_derive_set_peer', EVP_PKEY_CTX_POINTER, EVP_PKEY_POINTER)
EVP_PKEY_derive = create_crypto_func('EVP_PKEY_derive', EVP_PKEY_CTX_POINTER, c_char_p, POINTER(c_size_t))
EVP_CIPHER_CTX_free = create_crypto_func('EVP_CIPHER_CTX_free', EVP_CIPHER_CTX_POINTER, restype=None)
EVP_get_cipherbyname = create_crypto_func('EVP_get_cipherbyname', c_char_p, restype=EVP_CIPHER_POINTER)
EVP_CIPHER_key_length = create_crypto_func('EVP_CIPHER_key_length', EVP_CIPHER_POINTER, int_return_ok=bool)
EVP_CIPHER_iv_length = create_crypto_func('EVP_CIPHER_iv_length', EVP_CIPHER_POINTER, int_return_ok=bool)
EVP_CIPHER_CTX_block_size = create_crypto_func('EVP_CIPHER_CTX_block_size', EVP_CIPHER_CTX_POINTER, int_return_ok=bool)
EVP_CIPHER_CTX_new = create_crypto_func('EVP_CIPHER_CTX_new', restype=EVP_CIPHER_CTX_POINTER)
EVP_EncryptInit_ex = create_crypto_func('EVP_EncryptInit_ex', EVP_CIPHER_CTX_POINTER, EVP_CIPHER_POINTER, c_void_p, c_char_p, c_char_p)
EVP_EncryptUpdate = create_crypto_func('EVP_EncryptUpdate', EVP_CIPHER_CTX_POINTER, c_char_p, POINTER(c_int), c_char_p, c_int)
EVP_EncryptFinal_ex = create_crypto_func('EVP_EncryptFinal_ex', EVP_CIPHER_CTX_POINTER, c_char_p, POINTER(c_int))
EVP_CIPHER_CTX_ctrl = create_crypto_func('EVP_CIPHER_CTX_ctrl', EVP_CIPHER_CTX_POINTER, c_int, c_int, c_char_p)
try:
EVP_CIPHER_CTX_tag_length = create_crypto_func('EVP_CIPHER_CTX_tag_length', EVP_CIPHER_CTX_POINTER, int_return_ok=bool)
except AttributeError: # need openssl >= 3
def EVP_CIPHER_CTX_tag_length(cipher):
return 16
EVP_CTRL_AEAD_GET_TAG, EVP_CTRL_AEAD_SET_TAG = 0x10, 0x11 # these are defines in the header dont know how to get them programmatically
EVP_CTRL_AEAD_SET_TAG
def abort_on_openssl_error():
stderr = c_void_p.in_dll(libc, 'stderr')
ERR_print_errors_fp(stderr)
raise SystemExit(1)
def elliptic_curve_keypair(algorithm='X25519'):
nid = OBJ_txt2nid(algorithm.encode())
pctx = EVP_PKEY_CTX_new_id(nid, None)
EVP_PKEY_keygen_init(pctx)
key = EVP_PKEY_POINTER()
EVP_PKEY_keygen(pctx, byref(key))
key.algorithm = nid
return key
def encrypt(plaintext, symmetric_key, algorithm='aes-256-gcm'):
cipher = EVP_get_cipherbyname(algorithm.encode())
if len(symmetric_key) != EVP_CIPHER_key_length(cipher):
raise KeyError(f'The symmetric key has length {len(symmetric_key)} != {EVP_CIPHER_key_length(cipher)} needed for {algorithm}')
ctx = EVP_CIPHER_CTX_new()
iv = os.urandom(EVP_CIPHER_iv_length(cipher))
EVP_EncryptInit_ex(ctx, cipher, None, symmetric_key, iv)
bs = EVP_CIPHER_CTX_block_size(ctx)
ciphertext = create_string_buffer(len(plaintext) + 2 * bs)
outlen = c_int(len(ciphertext))
EVP_EncryptUpdate(ctx, ciphertext, byref(outlen), plaintext, len(plaintext))
ans = ciphertext[:outlen.value]
outlen = c_int(len(ciphertext))
EVP_EncryptFinal_ex(ctx, ciphertext, byref(outlen))
if outlen.value:
ans += ciphertext[:outlen.value]
tag = create_string_buffer(EVP_CIPHER_CTX_tag_length(cipher))
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, len(tag), tag)
return iv, ans, tag.raw
return elliptic_curve_keypair, encrypt
# }}}
# utils {{{
def encrypt_cmd(cmd, password, pubkey=None):
elliptic_curve_keypair, encrypt = build_crypto_tools()
if pubkey is None:
pubkey = os.environ['KITTY_PUBLIC_KEY']
v, d = pubkey.split(':', 1)
if v != '1':
raise SystemExit(f'Unsupported encryption protocol: {v}')
pubkey = base64.b85decode(d)
k = elliptic_curve_keypair()
sk = k.derive_secret(pubkey)
cmd['timestamp'] = time.time_ns()
cmd['password'] = password
data = json.dumps(cmd).encode()
iv, encrypted, tag = encrypt(data, sk)
def e(x):
return base64.b85encode(x).decode('ascii')
return {
'encrypted': e(encrypted), 'iv': e(iv), 'tag': e(tag), 'pubkey': e(k.public), 'version': cmd['version']
}
@contextmanager
def raw_mode(fd):
old = termios.tcgetattr(fd)
try:
tty.setraw(fd)
yield
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)
def config_dir():
if 'KITTY_CONFIG_DIRECTORY' in os.environ:
return os.path.abspath(os.path.expanduser(os.environ['KITTY_CONFIG_DIRECTORY']))
locations = []
if 'XDG_CONFIG_HOME' in os.environ:
locations.append(os.path.abspath(os.path.expanduser(os.environ['XDG_CONFIG_HOME'])))
locations.append(os.path.expanduser('~/.config'))
if is_macos:
locations.append(os.path.expanduser('~/Library/Preferences'))
for loc in filter(None, os.environ.get('XDG_CONFIG_DIRS', '').split(os.pathsep)):
locations.append(os.path.abspath(os.path.expanduser(loc)))
for loc in locations:
if loc:
q = os.path.join(loc, 'kitty')
if os.access(q, os.W_OK) and os.path.exists(os.path.join(q, 'kitty.conf')):
return q
for loc in locations:
if loc:
q = os.path.join(loc, 'kitty')
if os.path.isdir(q) and os.access(q, os.W_OK):
return q
return ''
def resolve_custom_file(path):
path = os.path.expanduser(path)
path = os.path.expandvars(path)
if not os.path.isabs(path):
cdir = config_dir()
if cdir:
path = os.path.join(cdir, path)
return path
def get_password(opts):
if opts.use_password == 'never':
return ''
ans = ''
if opts.password:
ans = opts.password
if not ans and opts.password_file:
if opts.password_file == '-':
if sys.stdin.isatty():
from getpass import getpass
ans = getpass()
else:
ans = sys.stdin.read().rstrip()
try:
tty_fd = os.open(os.ctermid(), os.O_RDONLY | os.O_CLOEXEC)
except OSError:
pass
else:
with open(tty_fd, closefd=True):
os.dup2(tty_fd, sys.stdin.fileno())
else:
try:
with open(resolve_custom_file(opts.password_file)) as f:
ans = f.read().rstrip()
except OSError:
pass
if not ans and opts.password_env:
ans = os.environ.get(opts.password_env, '')
if not ans and opts.use_password == 'always':
raise SystemExit('No password was found')
if ans and len(ans) > 1024:
raise SystemExit('Specified password is too long')
return ans
# }}}
arg_parser = argparse.ArgumentParser(prog='kitty@', description='Control kitty remotely.')
arg_parser.add_argument('--password', default='', help='''\
A password to use when contacting kitty. This will cause kitty to ask the user
for permission to perform the specified action, unless the password has been
accepted before or is pre-configured in kitty.conf''')
arg_parser.add_argument('--password-file', default='rc-pass', help='''\
A file from which to read the password. Trailing whitespace is ignored. Relative
paths are resolved from the kitty configuration directory. Use - to read from STDIN.
Used if no --password is supplied. Defaults to checking for the
rc-pass file in the kitty configuration directory.''')
arg_parser.add_argument('--password-env', default='KITTY_RC_PASSWORD', help='''\
The name of an environment variable to read the password from.
Used if no --password-file is supplied. Defaults to checking the KITTY_RC_PASSWORD.''')
arg_parser.add_argument('--use-password', default='if-available', choices=('if-available', 'always', 'never'), help='''\
If no password is available, kitty will usually just send the remote control command
without a password. This option can be used to force it to always or never use
the supplied password.''')
args = arg_parser.parse_args()
def populate_cmd(cmd):
raise NotImplementedError()
password = get_password(args)
cmd = {'version': [0, 20, 0]} # use a random version that's fairly old
populate_cmd(cmd)
if password:
encrypt_cmd(cmd, password)
# cmd = {'version': [0, 14, 2], 'cmd': 'ls'}
# cmd = encrypt_cmd(cmd, 'test')
# with open(os.open(os.ctermid(), os.O_RDWR | os.O_CLOEXEC), 'w') as tty_file, raw_mode(tty_file.fileno()):
# print(end=f'\x1bP@kitty-cmd{json.dumps(cmd)}\x1b\\', flush=True, file=tty_file)
# os.read(tty_file.fileno(), 4096)

View File

@@ -68,6 +68,13 @@ some special variables, documented below:
The path, query and fragment portions of the URL, without any
unquoting.
``EDITOR``
The terminal based text editor. The configured :opt:`editor` in
:file:`kitty.conf` is preferred.
``SHELL``
The path to the shell. The configured :opt:`shell` in :file:`kitty.conf` is
preferred, without arguments.
.. note::
You can use the :opt:`action_alias` option just as in :file:`kitty.conf` to
@@ -103,7 +110,8 @@ lines. The various available criteria are:
Useful if your system MIME database does not have definitions you need. This
file is in the standard format of one definition per line, like:
``text/plain rst md``. Note that the MIME type for directories is
``inode/directory``.
``inode/directory``. MIME types are detected based on file extension, not
file contents.
``ext``
A comma separated list of file extensions, for example: ``jpeg, tar.gz``

View File

@@ -85,7 +85,7 @@ Extending kitty
------------------
kitty has a powerful framework for scripting. You can create small terminal
programs called :doc:`kittens <kittens_intro>`. These can used to add features
programs called :doc:`kittens <kittens_intro>`. These can be used to add features
to kitty, for example, :doc:`editing remote files <kittens/remote_file>` or
:doc:`inputting Unicode characters <kittens/unicode_input>`. They can also be
used to create programs that leverage kitty's powerful features, for example,
@@ -127,7 +127,7 @@ Startup Sessions
You can control the :term:`tabs <tab>`, :term:`kitty window <window>` layout,
working directory, startup programs, etc. by creating a *session* file and using
the :option:`kitty --session` command line flag or the :opt:`startup_session`
option in :file:`kitty.conf`. For example:
option in :file:`kitty.conf`. An example, showing all available commands:
.. code-block:: session
@@ -154,7 +154,7 @@ option in :file:`kitty.conf`. For example:
launch zsh
# Create a new OS window
# Any definitions specifed before the first new_os_window will apply to first OS window.
# Any definitions specified before the first new_os_window will apply to first OS window.
new_os_window
# Set new window size to 80x24 cells
os_window_size 80c 24c
@@ -173,6 +173,11 @@ option in :file:`kitty.conf`. For example:
The :doc:`launch <launch>` command when used in a session file cannot create
new OS windows, or tabs.
.. note::
Environment variables of the for :code:`${NAME}` or :code:`$NAME` are
expanded in the session file, except in the *arguments* (not options) to the
launch command.
Creating tabs/windows
-------------------------------

View File

@@ -32,3 +32,4 @@ please do so by opening issues in the `GitHub bug tracker
unscroll
color-stack
deccara
clipboard

View File

@@ -15,6 +15,7 @@ Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form:
"cmd": "command name",
"version": "<kitty version>",
"no_response": "<Optional Boolean>",
"kitty_window_id": "<Optional value of the KITTY_WINDOW_ID env var>",
"payload": "<Optional JSON object>"
}
@@ -40,6 +41,12 @@ with the following command line::
echo -en '\eP@kitty-cmd{"cmd":"ls","version":[0,14,2]}\e\\' | socat - unix:/tmp/test | awk '{ print substr($0, 13, length($0) - 14) }' | jq -c '.data | fromjson' | jq .
There is also the statically compiled stand-alone executable ``kitten``
that can be used for this, available from the `kitty releases
<https://github.com/kovidgoyal/kitty/releases>`__ page::
kitten @ --help
.. _rc_crypto:
Encrypted communication

View File

@@ -304,7 +304,13 @@ The remote control protocol
-----------------------------------------------
If you wish to develop your own client to talk to |kitty|, you can use the
:doc:`remote control protocol specification <rc_protocol>`.
:doc:`remote control protocol specification <rc_protocol>`. Note that there
is a statically compiled, standalone executable, ``kitten`` available that
can be used as a remote control client on any UNIX like computer. This can be
downloaded and used directly from the `kitty releases
<https://github.com/kovidgoyal/kitty/releases>`__ page::
kitten @ --help
.. _search_syntax:

View File

@@ -3,6 +3,7 @@
import re
import subprocess
from typing import List
from kitty.conf.generate import write_output
@@ -11,14 +12,25 @@ from kitty.conf.generate import write_output
def patch_color_list(path: str, colors: List[str], name: str, spc: str = ' ') -> None:
with open(path, 'r+') as f:
raw = f.read()
nraw = re.sub(
fr'(# {name}_COLORS_START).+?(\s+# {name}_COLORS_END)',
r'\1' + f'\n{spc}' + f'\n{spc}'.join(map(lambda x: f'{x!r},', sorted(colors))) + r'\2',
raw, flags=re.DOTALL | re.MULTILINE)
colors = sorted(colors)
if path.endswith('.go'):
spc = '\t'
nraw = re.sub(
fr'(// {name}_COLORS_START).+?(\s+// {name}_COLORS_END)',
r'\1' + f'\n{spc}' + f'\n{spc}'.join(map(lambda x: f'"{x}":true,', colors)) + r'\2',
raw, flags=re.DOTALL | re.MULTILINE)
else:
nraw = re.sub(
fr'(# {name}_COLORS_START).+?(\s+# {name}_COLORS_END)',
r'\1' + f'\n{spc}' + f'\n{spc}'.join(map(lambda x: f'{x!r},', colors)) + r'\2',
raw, flags=re.DOTALL | re.MULTILINE)
if nraw != raw:
f.seek(0)
f.truncate()
f.write(nraw)
f.flush()
if path.endswith('.go'):
subprocess.check_call(['gofmt', '-w', path])
def main() -> None:
@@ -34,6 +46,7 @@ def main() -> None:
elif opt.parser_func.__name__ in ('to_color', 'titlebar_color', 'macos_titlebar_color'):
all_colors.append(opt.name)
patch_color_list('kitty/rc/set_colors.py', nullable_colors, 'NULLABLE')
patch_color_list('tools/cmd/at/set_colors.go', nullable_colors, 'NULLABLE')
patch_color_list('kittens/themes/collection.py', all_colors, 'ALL', ' ' * 8)
from kittens.diff.options.definition import definition as kd

607
gen-go-code.py Executable file
View File

@@ -0,0 +1,607 @@
#!./kitty/launcher/kitty +launch
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import io
import json
import os
import subprocess
import sys
from contextlib import contextmanager, suppress
from functools import lru_cache
from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Union
import kitty.constants as kc
from kittens.tui.operations import Mode
from kittens.tui.spinners import spinners
from kitty.cli import (
CompletionSpec,
GoOption,
go_options_for_seq,
parse_option_spec,
serialize_as_go_string,
)
from kitty.guess_mime_type import text_mimes
from kitty.key_encoding import config_mod_map
from kitty.key_names import character_key_name_aliases, functional_key_name_aliases
from kitty.options.types import Options
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
from kitty.remote_control import global_options_spec
from kitty.rgb import color_names
changed: List[str] = []
# Utils {{{
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int], Dict[str, str]]) -> str:
ans = []
def s(x: Union[int, str]) -> str:
if isinstance(x, int):
return str(x)
return f'"{serialize_as_go_string(x)}"'
for k, v in x.items():
ans.append(f'{s(k)}: {s(v)}')
return '{' + ', '.join(ans) + '}'
def replace(template: str, **kw: str) -> str:
for k, v in kw.items():
template = template.replace(k, v)
return template
# }}}
# Completions {{{
@lru_cache
def kitten_cli_docs(kitten: str) -> Any:
from kittens.runner import get_kitten_cli_docs
return get_kitten_cli_docs(kitten)
@lru_cache
def go_options_for_kitten(kitten: str) -> Tuple[Sequence[GoOption], Optional[CompletionSpec]]:
kcd = kitten_cli_docs(kitten)
if kcd:
ospec = kcd['options']
return (tuple(go_options_for_seq(parse_option_spec(ospec())[0])), kcd.get('args_completion'))
return (), None
def generate_kittens_completion() -> None:
from kittens.runner import all_kitten_names, get_kitten_wrapper_of
for kitten in sorted(all_kitten_names()):
kn = 'kitten_' + kitten
print(f'{kn} := plus_kitten.AddSubCommand(&cli.Command{{Name:"{kitten}", Group: "Kittens"}})')
wof = get_kitten_wrapper_of(kitten)
if wof:
print(f'{kn}.ArgCompleter = cli.CompletionForWrapper("{serialize_as_go_string(wof)}")')
print(f'{kn}.OnlyArgsAllowed = true')
continue
gopts, ac = go_options_for_kitten(kitten)
if gopts or ac:
for opt in gopts:
print(opt.as_option(kn))
if ac is not None:
print(''.join(ac.as_go_code(kn + '.ArgCompleter', ' = ')))
else:
print(f'{kn}.HelpText = ""')
@lru_cache
def clone_safe_launch_opts() -> Sequence[GoOption]:
from kitty.launch import clone_safe_opts, options_spec
ans = []
allowed = clone_safe_opts()
for o in go_options_for_seq(parse_option_spec(options_spec())[0]):
if o.obj_dict['name'] in allowed:
ans.append(o)
return tuple(ans)
def completion_for_launch_wrappers(*names: str) -> None:
for o in clone_safe_launch_opts():
for name in names:
print(o.as_option(name))
def generate_completions_for_kitty() -> None:
from kitty.config import option_names_for_completion
print('package completion\n')
print('import "kitty/tools/cli"')
print('import "kitty/tools/cmd/tool"')
print('import "kitty/tools/cmd/at"')
conf_names = ', '.join((f'"{serialize_as_go_string(x)}"' for x in option_names_for_completion()))
print('var kitty_option_names_for_completion = []string{' + conf_names + '}')
print('func kitty(root *cli.Command) {')
# The kitty exe
print('k := root.AddSubCommand(&cli.Command{'
'Name:"kitty", SubCommandIsOptional: true, ArgCompleter: cli.CompleteExecutableFirstArg, SubCommandMustBeFirst: true })')
print('kt := root.AddSubCommand(&cli.Command{Name:"kitten", SubCommandMustBeFirst: true })')
print('tool.KittyToolEntryPoints(kt)')
for opt in go_options_for_seq(parse_option_spec()[0]):
print(opt.as_option('k'))
# kitty +
print('plus := k.AddSubCommand(&cli.Command{Name:"+", Group:"Entry points", ShortDescription: "Various special purpose tools and kittens"})')
# kitty +launch
print('plus_launch := plus.AddSubCommand(&cli.Command{'
'Name:"launch", Group:"Entry points", ShortDescription: "Launch Python scripts", ArgCompleter: complete_plus_launch})')
print('k.AddClone("", plus_launch).Name = "+launch"')
# kitty +list-fonts
print('plus_list_fonts := plus.AddSubCommand(&cli.Command{'
'Name:"list-fonts", Group:"Entry points", ShortDescription: "List all available monospaced fonts"})')
print('k.AddClone("", plus_list_fonts).Name = "+list-fonts"')
# kitty +runpy
print('plus_runpy := plus.AddSubCommand(&cli.Command{'
'Name: "runpy", Group:"Entry points", ArgCompleter: complete_plus_runpy, ShortDescription: "Run Python code"})')
print('k.AddClone("", plus_runpy).Name = "+runpy"')
# kitty +open
print('plus_open := plus.AddSubCommand(&cli.Command{'
'Name:"open", Group:"Entry points", ArgCompleter: complete_plus_open, ShortDescription: "Open files and URLs"})')
print('for _, og := range k.OptionGroups { plus_open.OptionGroups = append(plus_open.OptionGroups, og.Clone(plus_open)) }')
print('k.AddClone("", plus_open).Name = "+open"')
# kitty +kitten
print('plus_kitten := plus.AddSubCommand(&cli.Command{Name:"kitten", Group:"Kittens", SubCommandMustBeFirst: true})')
generate_kittens_completion()
print('k.AddClone("", plus_kitten).Name = "+kitten"')
# @
print('at.EntryPoint(k)')
# clone-in-kitty, edit-in-kitty
print('cik := root.AddSubCommand(&cli.Command{Name:"clone-in-kitty"})')
completion_for_launch_wrappers('cik')
print('}')
print('func init() {')
print('cli.RegisterExeForCompletion(kitty)')
print('}')
# }}}
# rc command wrappers {{{
json_field_types: Dict[str, str] = {
'bool': 'bool', 'str': 'escaped_string', 'list.str': '[]escaped_string', 'dict.str': 'map[escaped_string]escaped_string', 'float': 'float64', 'int': 'int',
'scroll_amount': 'any', 'spacing': 'any', 'colors': 'any',
}
def go_field_type(json_field_type: str) -> str:
q = json_field_types.get(json_field_type)
if q:
return q
if json_field_type.startswith('choices.'):
return 'string'
if '.' in json_field_type:
p, r = json_field_type.split('.', 1)
p = {'list': '[]', 'dict': 'map[string]'}[p]
return p + go_field_type(r)
raise TypeError(f'Unknown JSON field type: {json_field_type}')
class JSONField:
def __init__(self, line: str) -> None:
field_def = line.split(':', 1)[0]
self.required = False
self.field, self.field_type = field_def.split('/', 1)
if self.field.endswith('+'):
self.required = True
self.field = self.field[:-1]
self.struct_field_name = self.field[0].upper() + self.field[1:]
def go_declaration(self) -> str:
return self.struct_field_name + ' ' + go_field_type(self.field_type) + f'`json:"{self.field},omitempty"`'
def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) -> str:
template = '\n' + template[len('//go:build exclude'):]
NO_RESPONSE_BASE = 'false'
af: List[str] = []
a = af.append
af.extend(cmd.args.as_go_completion_code('ans'))
od: List[str] = []
option_map: Dict[str, GoOption] = {}
for o in rc_command_options(name):
option_map[o.go_var_name] = o
a(o.as_option('ans'))
if o.go_var_name in ('NoResponse', 'ResponseTimeout'):
continue
od.append(o.struct_declaration())
jd: List[str] = []
json_fields = []
field_types: Dict[str, str] = {}
for line in cmd.protocol_spec.splitlines():
line = line.strip()
if ':' not in line:
continue
f = JSONField(line)
json_fields.append(f)
field_types[f.field] = f.field_type
jd.append(f.go_declaration())
jc: List[str] = []
handled_fields: Set[str] = set()
jc.extend(cmd.args.as_go_code(name, field_types, handled_fields))
unhandled = {}
used_options = set()
for field in json_fields:
oq = (cmd.field_to_option_map or {}).get(field.field, field.field)
oq = ''.join(x.capitalize() for x in oq.split('_'))
if oq in option_map:
o = option_map[oq]
used_options.add(oq)
if field.field_type == 'str':
jc.append(f'payload.{field.struct_field_name} = escaped_string(options_{name}.{o.go_var_name})')
elif field.field_type == 'list.str':
jc.append(f'payload.{field.struct_field_name} = escape_list_of_strings(options_{name}.{o.go_var_name})')
elif field.field_type == 'dict.str':
jc.append(f'payload.{field.struct_field_name} = escape_dict_of_strings(options_{name}.{o.go_var_name})')
else:
jc.append(f'payload.{field.struct_field_name} = options_{name}.{o.go_var_name}')
elif field.field in handled_fields:
pass
else:
unhandled[field.field] = field
for x in tuple(unhandled):
if x == 'match_window' and 'Match' in option_map and 'Match' not in used_options:
used_options.add('Match')
o = option_map['Match']
field = unhandled[x]
if field.field_type == 'str':
jc.append(f'payload.{field.struct_field_name} = escaped_string(options_{name}.{o.go_var_name})')
else:
jc.append(f'payload.{field.struct_field_name} = options_{name}.{o.go_var_name}')
del unhandled[x]
if unhandled:
raise SystemExit(f'Cant map fields: {", ".join(unhandled)} for cmd: {name}')
if name != 'send_text':
unused_options = set(option_map) - used_options - {'NoResponse', 'ResponseTimeout'}
if unused_options:
raise SystemExit(f'Unused options: {", ".join(unused_options)} for command: {name}')
argspec = cmd.args.spec
if argspec:
argspec = ' ' + argspec
ans = replace(
template,
CMD_NAME=name, __FILE__=__file__, CLI_NAME=name.replace('_', '-'),
SHORT_DESC=serialize_as_go_string(cmd.short_desc),
LONG_DESC=serialize_as_go_string(cmd.desc.strip()),
IS_ASYNC='true' if cmd.is_asynchronous else 'false',
NO_RESPONSE_BASE=NO_RESPONSE_BASE, ADD_FLAGS_CODE='\n'.join(af),
WAIT_TIMEOUT=str(cmd.response_timeout),
OPTIONS_DECLARATION_CODE='\n'.join(od),
JSON_DECLARATION_CODE='\n'.join(jd),
JSON_INIT_CODE='\n'.join(jc), ARGSPEC=argspec,
STRING_RESPONSE_IS_ERROR='true' if cmd.string_return_is_error else 'false',
STREAM_WANTED='true' if cmd.reads_streaming_data else 'false',
)
return ans
# }}}
# kittens {{{
@lru_cache
def wrapped_kittens() -> Sequence[str]:
with open('shell-integration/ssh/kitty') as f:
for line in f:
if line.startswith(' wrapped_kittens="'):
val = line.strip().partition('"')[2][:-1]
return tuple(sorted(filter(None, val.split())))
raise Exception('Failed to read wrapped kittens from kitty wrapper script')
def kitten_clis() -> None:
for kitten in wrapped_kittens():
with replace_if_needed(f'tools/cmd/{kitten}/cli_generated.go'):
od = []
kcd = kitten_cli_docs(kitten)
has_underscore = '_' in kitten
print(f'package {kitten}')
print('import "kitty/tools/cli"')
print('func create_cmd(root *cli.Command, run_func func(*cli.Command, *Options, []string)(int, error)) {')
print('ans := root.AddSubCommand(&cli.Command{')
print(f'Name: "{kitten}",')
print(f'ShortDescription: "{serialize_as_go_string(kcd["short_desc"])}",')
if kcd['usage']:
print(f'Usage: "[options] {serialize_as_go_string(kcd["usage"])}",')
print(f'HelpText: "{serialize_as_go_string(kcd["help_text"])}",')
print('Run: func(cmd *cli.Command, args []string) (int, error) {')
print('opts := Options{}')
print('err := cmd.GetOptionValues(&opts)')
print('if err != nil { return 1, err }')
print('return run_func(cmd, &opts, args)},')
if has_underscore:
print('Hidden: true,')
print('})')
gopts, ac = go_options_for_kitten(kitten)
for opt in gopts:
print(opt.as_option('ans'))
od.append(opt.struct_declaration())
if ac is not None:
print(''.join(ac.as_go_code('ans.ArgCompleter', ' = ')))
if has_underscore:
print("clone := root.AddClone(ans.Group, ans)")
print('clone.Hidden = false')
print(f'clone.Name = "{serialize_as_go_string(kitten.replace("_", "-"))}"')
print('}')
print('type Options struct {')
print('\n'.join(od))
print('}')
# }}}
# Constants {{{
def generate_spinners() -> str:
ans = ['package tui', 'import "time"', 'func NewSpinner(name string) *Spinner {', 'var ans *Spinner', 'switch name {']
a = ans.append
for name, spinner in spinners.items():
a(f'case "{serialize_as_go_string(name)}":')
a('ans = &Spinner{')
a(f'Name: "{serialize_as_go_string(name)}",')
a(f'interval: {spinner["interval"]},')
frames = ', '.join(f'"{serialize_as_go_string(x)}"' for x in spinner['frames'])
a(f'frames: []string{{{frames}}},')
a('}')
a('}')
a('if ans != nil {')
a('ans.interval *= time.Millisecond')
a('ans.current_frame = -1')
a('ans.last_change_at = time.Now().Add(-ans.interval)')
a('}')
a('return ans}')
return '\n'.join(ans)
def generate_color_names() -> str:
return 'package style\n\nvar ColorNames = map[string]RGBA{' + '\n'.join(
f'\t"{name}": RGBA{{ Red:{val.red}, Green:{val.green}, Blue:{val.blue} }},'
for name, val in color_names.items()
) + '\n}' + '\n\nvar ColorTable = [256]uint32{' + ', '.join(
f'{x}' for x in Options.color_table) + '}\n'
def load_ref_map() -> Dict[str, Dict[str, str]]:
with open('kitty/docs_ref_map_generated.h') as f:
raw = f.read()
raw = raw.split('{', 1)[1].split('}', 1)[0]
data = json.loads(bytes(bytearray(json.loads(f'[{raw}]'))))
return data # type: ignore
def generate_constants() -> str:
ref_map = load_ref_map()
dp = ", ".join(map(lambda x: f'"{serialize_as_go_string(x)}"', kc.default_pager_for_help))
return f'''\
package kitty
type VersionType struct {{
Major, Minor, Patch int
}}
const VersionString string = "{kc.str_version}"
const WebsiteBaseURL string = "{kc.website_base_url}"
const VCSRevision string = ""
const RC_ENCRYPTION_PROTOCOL_VERSION string = "{kc.RC_ENCRYPTION_PROTOCOL_VERSION}"
const IsFrozenBuild bool = false
const IsStandaloneBuild bool = false
const HandleTermiosSignals = {Mode.HANDLE_TERMIOS_SIGNALS.value[0]}
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
var DefaultPager []string = []string{{ {dp} }}
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
var CharacterKeyNameAliases = map[string]string{serialize_go_dict(character_key_name_aliases)}
var ConfigModMap = map[string]uint16{serialize_go_dict(config_mod_map)}
var RefMap = map[string]string{serialize_go_dict(ref_map['ref'])}
var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
''' # }}}
# Boilerplate {{{
@contextmanager
def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringIO]:
buf = io.StringIO()
origb = sys.stdout
sys.stdout = buf
try:
yield buf
finally:
sys.stdout = origb
orig = ''
with suppress(FileNotFoundError), open(path, 'r') as f:
orig = f.read()
new = buf.getvalue()
new = f'// Code generated by {os.path.basename(__file__)}; DO NOT EDIT.\n\n' + new
if orig != new:
changed.append(path)
if show_diff:
with open(path + '.new', 'w') as f:
f.write(new)
subprocess.run(['diff', '-Naurp', path, f.name], stdout=open('/dev/tty', 'w'))
os.remove(f.name)
with open(path, 'w') as f:
f.write(new)
@lru_cache(maxsize=256)
def rc_command_options(name: str) -> Tuple[GoOption, ...]:
cmd = command_for_name(name)
return tuple(go_options_for_seq(parse_option_spec(cmd.options_spec or '\n\n')[0]))
def update_at_commands() -> None:
with open('tools/cmd/at/template.go') as f:
template = f.read()
for name in all_command_names():
cmd = command_for_name(name)
code = go_code_for_remote_command(name, cmd, template)
dest = f'tools/cmd/at/cmd_{name}_generated.go'
with replace_if_needed(dest) as f:
f.write(code)
struct_def = []
opt_def = []
for o in go_options_for_seq(parse_option_spec(global_options_spec())[0]):
struct_def.append(o.struct_declaration())
opt_def.append(o.as_option(depth=1, group="Global options"))
sdef = '\n'.join(struct_def)
odef = '\n'.join(opt_def)
code = f'''
package at
import "kitty/tools/cli"
type rc_global_options struct {{
{sdef}
}}
var rc_global_opts rc_global_options
func add_rc_global_opts(cmd *cli.Command) {{
{odef}
}}
'''
with replace_if_needed('tools/cmd/at/global_opts_generated.go') as f:
f.write(code)
def update_completion() -> None:
with replace_if_needed('tools/cmd/completion/kitty_generated.go'):
generate_completions_for_kitty()
with replace_if_needed('tools/cmd/edit_in_kitty/launch_generated.go'):
print('package edit_in_kitty')
print('import "kitty/tools/cli"')
print('func AddCloneSafeOpts(cmd *cli.Command) {')
completion_for_launch_wrappers('cmd')
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
print('}')
def define_enum(package_name: str, type_name: str, items: str, underlying_type: str = 'uint') -> str:
actions = []
for x in items.splitlines():
x = x.strip()
if x:
actions.append(x)
ans = [f'package {package_name}', 'import "strconv"', f'type {type_name} {underlying_type}', 'const (']
stringer = [f'func (ac {type_name}) String() string ''{', 'switch(ac) {']
for i, ac in enumerate(actions):
stringer.append(f'case {ac}: return "{ac}"')
if i == 0:
ac = ac + f' {type_name} = iota'
ans.append(ac)
ans.append(')')
stringer.append('}\nreturn strconv.Itoa(int(ac)) }')
return '\n'.join(ans + stringer)
def generate_readline_actions() -> str:
return define_enum('readline', 'Action', '''\
ActionNil
ActionBackspace
ActionDelete
ActionMoveToStartOfLine
ActionMoveToEndOfLine
ActionMoveToStartOfDocument
ActionMoveToEndOfDocument
ActionMoveToEndOfWord
ActionMoveToStartOfWord
ActionCursorLeft
ActionCursorRight
ActionEndInput
ActionAcceptInput
ActionCursorUp
ActionHistoryPreviousOrCursorUp
ActionCursorDown
ActionHistoryNextOrCursorDown
ActionHistoryNext
ActionHistoryPrevious
ActionHistoryFirst
ActionHistoryLast
ActionHistoryIncrementalSearchBackwards
ActionHistoryIncrementalSearchForwards
ActionTerminateHistorySearchAndApply
ActionTerminateHistorySearchAndRestore
ActionClearScreen
ActionAddText
ActionAbortCurrentLine
ActionStartKillActions
ActionKillToEndOfLine
ActionKillToStartOfLine
ActionKillNextWord
ActionKillPreviousWord
ActionKillPreviousSpaceDelimitedWord
ActionEndKillActions
ActionYank
ActionPopYank
ActionNumericArgumentDigit0
ActionNumericArgumentDigit1
ActionNumericArgumentDigit2
ActionNumericArgumentDigit3
ActionNumericArgumentDigit4
ActionNumericArgumentDigit5
ActionNumericArgumentDigit6
ActionNumericArgumentDigit7
ActionNumericArgumentDigit8
ActionNumericArgumentDigit9
ActionNumericArgumentDigitMinus
ActionCompleteForward
ActionCompleteBackward
''')
def generate_mimetypes() -> str:
import mimetypes
if not mimetypes.inited:
mimetypes.init()
ans = ['package utils', 'import "sync"', 'var only_once sync.Once', 'var builtin_types_map map[string]string',
'func set_builtins() {', 'builtin_types_map = map[string]string{',]
for k, v in mimetypes.types_map.items():
ans.append(f' "{serialize_as_go_string(k)}": "{serialize_as_go_string(v)}",')
ans.append('}}')
return '\n'.join(ans)
def generate_textual_mimetypes() -> str:
ans = ['package utils', 'var KnownTextualMimes = map[string]bool{',]
for k in text_mimes:
ans.append(f' "{serialize_as_go_string(k)}": true,')
ans.append('}')
return '\n'.join(ans)
def main() -> None:
with replace_if_needed('constants_generated.go') as f:
f.write(generate_constants())
with replace_if_needed('tools/utils/style/color-names_generated.go') as f:
f.write(generate_color_names())
with replace_if_needed('tools/tui/readline/actions_generated.go') as f:
f.write(generate_readline_actions())
with replace_if_needed('tools/tui/spinners_generated.go') as f:
f.write(generate_spinners())
with replace_if_needed('tools/utils/mimetypes_generated.go') as f:
f.write(generate_mimetypes())
with replace_if_needed('tools/utils/mimetypes_textual_generated.go') as f:
f.write(generate_textual_mimetypes())
update_completion()
update_at_commands()
kitten_clis()
print(json.dumps(changed, indent=2))
if __name__ == '__main__':
main() # }}}

View File

@@ -2,8 +2,8 @@
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import string
from typing import Dict, List, Any
from pprint import pformat
from typing import Any, Dict, List, Union
functional_key_defs = '''# {{{
# kitty XKB macVK macU
@@ -130,7 +130,7 @@ functional_encoding_overrides = {
}
different_trailer_functionals = {
'up': 'A', 'down': 'B', 'right': 'C', 'left': 'D', 'kp_begin': 'E', 'end': 'F', 'home': 'H',
'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S', 'enter': 'u', 'tab': 'u',
'f1': 'P', 'f2': 'Q', 'f3': '~', 'f4': 'S', 'enter': 'u', 'tab': 'u',
'backspace': 'u', 'escape': 'u'
}
@@ -248,6 +248,19 @@ def serialize_dict(x: Dict[Any, Any]) -> str:
return pformat(x, indent=4).replace('{', '{\n ', 1)
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int]]) -> str:
ans = []
def s(x: Union[int, str]) -> str:
if isinstance(x, int):
return str(x)
return f'"{x}"'
for k, v in x.items():
ans.append(f'{s(k)}: {s(v)}')
return '{' + ', '.join(ans) + '}'
def generate_glfw_header() -> None:
lines = [
'typedef enum {',
@@ -309,14 +322,20 @@ def generate_functional_table() -> None:
patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines))
code_to_name = {v: k.upper() for k, v in name_to_code.items()}
csi_map = {v: name_to_code[k] for k, v in functional_encoding_overrides.items()}
letter_trailer_codes = {
v: functional_encoding_overrides.get(k, name_to_code.get(k))
letter_trailer_codes: Dict[str, int] = {
v: functional_encoding_overrides.get(k, name_to_code.get(k, 0))
for k, v in different_trailer_functionals.items() if v in 'ABCDEHFPQRSZ'}
text = f'functional_key_number_to_name_map = {serialize_dict(code_to_name)}'
text += f'\ncsi_number_to_functional_number_map = {serialize_dict(csi_map)}'
text += f'\nletter_trailer_to_csi_number_map = {letter_trailer_codes!r}'
text += f'\ntilde_trailers = {tilde_trailers!r}'
patch_file('kitty/key_encoding.py', 'csi mapping', text, start_marker='# ', end_marker='')
text = f'var functional_key_number_to_name_map = map[int]string{serialize_go_dict(code_to_name)}\n'
text += f'\nvar csi_number_to_functional_number_map = map[int]int{serialize_go_dict(csi_map)}\n'
text += f'\nvar letter_trailer_to_csi_number_map = map[string]int{serialize_go_dict(letter_trailer_codes)}\n'
tt = ', '.join(f'{x}: true' for x in tilde_trailers)
text += '\nvar tilde_trailers = map[int]bool{' + f'{tt}' + '}\n'
patch_file('tools/tui/loop/key-encoding.go', 'csi mapping', text, start_marker='// ', end_marker='')
def generate_legacy_text_key_maps() -> None:

View File

@@ -3,17 +3,26 @@
import os
import re
import subprocess
import sys
from collections import defaultdict
from contextlib import contextmanager
from datetime import date
from functools import partial
from functools import lru_cache, partial
from html.entities import html5
from itertools import groupby
from operator import itemgetter
from typing import (
Callable, DefaultDict, Dict, FrozenSet, Generator, Iterable, List,
Optional, Set, Tuple, Union
Callable,
DefaultDict,
Dict,
FrozenSet,
Generator,
Iterable,
List,
Optional,
Set,
Tuple,
Union,
)
from urllib.request import urlopen
@@ -44,6 +53,15 @@ def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
yield line
@lru_cache(maxsize=2)
def unicode_version() -> Tuple[int, int, int]:
for line in get_data("ReadMe.txt"):
m = re.search(r'Version\s+(\d+)\.(\d+)\.(\d+)', line)
if m is not None:
return int(m.group(1)), int(m.group(2)), int(m.group(3))
raise ValueError('Could not find Unicode Version')
# Map of class names to set of codepoints in class
class_maps: Dict[str, Set[int]] = {}
all_symbols: Set[int] = set()
@@ -254,9 +272,13 @@ def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None,
yield a, b
def write_case(spec: Union[Tuple[int, ...], int], p: Callable[..., None]) -> None:
def write_case(spec: Union[Tuple[int, ...], int], p: Callable[..., None], for_go: bool = False) -> None:
if isinstance(spec, tuple):
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
if for_go:
v = ', '.join(f'0x{x:x}' for x in range(spec[0], spec[1] + 1))
p(f'\t\tcase {v}:')
else:
p('\t\tcase 0x{:x} ... 0x{:x}:'.format(*spec))
else:
p(f'\t\tcase 0x{spec:x}:')
@@ -265,8 +287,8 @@ def write_case(spec: Union[Tuple[int, ...], int], p: Callable[..., None]) -> Non
def create_header(path: str, include_data_types: bool = True) -> Generator[Callable[..., None], None, None]:
with open(path, 'w') as f:
p = partial(print, file=f)
p('// unicode data, built from the unicode standard on:', date.today())
p('// see gen-wcwidth.py')
p('// Unicode data, built from the Unicode Standard', '.'.join(map(str, unicode_version())))
p(f'// Code generated by {os.path.basename(__file__)}, DO NOT EDIT.', end='\n\n')
if path.endswith('.h'):
p('#pragma once')
if include_data_types:
@@ -476,7 +498,7 @@ def gen_names() -> None:
# The trie
p('typedef struct { uint32_t children_offset; uint32_t match_offset; } word_trie;\n')
all_trie_nodes: List['TrieNode'] = [] # noqa
all_trie_nodes: List['TrieNode'] = []
class TrieNode:
@@ -524,45 +546,69 @@ def gen_names() -> None:
def gen_wcwidth() -> None:
seen: Set[int] = set()
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
def add(p: Callable[..., None], comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int) -> None:
def add(p: Callable[..., None], comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int, for_go: bool = False) -> None:
chars = chars_ - seen
seen.update(chars)
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
for spec in get_ranges(list(chars)):
write_case(spec, p)
write_case(spec, p, for_go)
p(f'\t\t\treturn {ret};')
p('\t\t// }}}\n')
with create_header('kitty/wcwidth-std.h') as p:
p('static inline int\nwcwidth_std(int32_t code) {')
p('\tif (LIKELY(0x20 <= code && code <= 0x7e)) return 1;')
p('\tswitch(code) {')
def add_all(p: Callable[..., None], for_go: bool = False) -> None:
seen.clear()
add(p, 'Flags', flag_codepoints, 2, for_go)
add(p, 'Marks', marks | {0}, 0, for_go)
add(p, 'Non-printing characters', non_printing, -1, for_go)
add(p, 'Private use', class_maps['Co'], -3, for_go)
add(p, 'Text Presentation', narrow_emoji, 1, for_go)
add(p, 'East Asian ambiguous width', ambiguous, -2, for_go)
add(p, 'East Asian double width', doublewidth, 2, for_go)
add(p, 'Emoji Presentation', wide_emoji, 2, for_go)
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
add(p, 'Flags', flag_codepoints, 2)
add(p, 'Marks', marks | {0}, 0)
add(p, 'Non-printing characters', non_printing, -1)
add(p, 'Private use', class_maps['Co'], -3)
add(p, 'Text Presentation', narrow_emoji, 1)
add(p, 'East Asian ambiguous width', ambiguous, -2)
add(p, 'East Asian double width', doublewidth, 2)
add(p, 'Emoji Presentation', wide_emoji, 2)
add(p, 'Not assigned in the unicode character database', not_assigned, -4, for_go)
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
p('\t\tdefault: return 1;')
p('\t\tdefault:\n\t\t\treturn 1;')
p('\t}')
p('\treturn 1;\n}')
if for_go:
p('\t}')
else:
p('\treturn 1;\n}')
with create_header('kitty/wcwidth-std.h') as p, open('tools/wcswidth/std.go', 'w') as gof:
gop = partial(print, file=gof)
gop('package wcswidth\n\n')
gop('func Runewidth(code rune) int {')
p('static inline int\nwcwidth_std(int32_t code) {')
p('\tif (LIKELY(0x20 <= code && code <= 0x7e)) { return 1; }')
p('\tswitch(code) {')
gop('\tswitch(code) {')
add_all(p)
add_all(gop, True)
p('static inline bool\nis_emoji_presentation_base(uint32_t code) {')
gop('func IsEmojiPresentationBase(code rune) bool {')
p('\tswitch(code) {')
gop('\tswitch(code) {')
for spec in get_ranges(list(emoji_presentation_bases)):
write_case(spec, p)
write_case(spec, gop, for_go=True)
p('\t\t\treturn true;')
gop('\t\t\treturn true;')
p('\t\tdefault: return false;')
p('\t}')
p('\treturn 1;\n}')
gop('\t\tdefault:\n\t\t\treturn false')
gop('\t}')
p('\treturn true;\n}')
gop('\n}')
uv = unicode_version()
p(f'#define UNICODE_MAJOR_VERSION {uv[0]}')
p(f'#define UNICODE_MINOR_VERSION {uv[1]}')
p(f'#define UNICODE_PATCH_VERSION {uv[2]}')
gop('var UnicodeDatabaseVersion [3]int = [3]int{' f'{uv[0]}, {uv[1]}, {uv[2]}' + '}')
subprocess.check_call(['gofmt', '-w', '-s', gof.name])
parse_ucd()

View File

@@ -8,7 +8,6 @@ import shlex
import shutil
import subprocess
cmdline = (
'glad --out-path {dest} --api gl:core=3.3 '
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_KHR_debug '

View File

@@ -1576,6 +1576,69 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev) {
return text;
}
// <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/SysServices/Articles/using.html>
// Support services receiving "public.utf8-plain-text" and "NSStringPboardType"
- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
{
if (
(!sendType || [sendType isEqual:NSPasteboardTypeString] || [sendType isEqual:@"NSStringPboardType"]) &&
(!returnType || [returnType isEqual:NSPasteboardTypeString] || [returnType isEqual:@"NSStringPboardType"])
) {
if (_glfw.callbacks.has_current_selection && _glfw.callbacks.has_current_selection()) return self;
}
return [super validRequestorForSendType:sendType returnType:returnType];
}
// Selected text as input to be sent to Services
- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard types:(NSArray *)types
{
if (!_glfw.callbacks.get_current_selection) return NO;
char *text = _glfw.callbacks.get_current_selection();
if (!text) return NO;
BOOL ans = NO;
if (text[0]) {
if ([types containsObject:NSPasteboardTypeString] == YES) {
[pboard declareTypes:@[NSPasteboardTypeString] owner:self];
ans = [pboard setString:@(text) forType:NSPasteboardTypeString];
} else if ([types containsObject:@"NSStringPboardType"] == YES) {
[pboard declareTypes:@[@"NSStringPboardType"] owner:self];
ans = [pboard setString:@(text) forType:@"NSStringPboardType"];
}
free(text);
}
return ans;
}
// Service output to be handled
- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard
{
NSString* text = nil;
NSArray *types = [pboard types];
if ([types containsObject:NSPasteboardTypeString] == YES) {
text = [pboard stringForType:NSPasteboardTypeString]; // public.utf8-plain-text
} else if ([types containsObject:@"NSStringPboardType"] == YES) {
text = [pboard stringForType:@"NSStringPboardType"]; // for older services (need re-encode?)
} else {
return NO;
}
if (text && [text length] > 0) {
// Terminal.app inserts the output, do the same
const char *utf8 = polymorphic_string_as_utf8(text);
if ([self hasMarkedText]) {
[self unmarkText];
debug_key("Clearing pre-edit because insertText called from readSelectionFromPasteboard\n");
GLFWkeyevent glfw_keyevent = {.ime_state = GLFW_IME_PREEDIT_CHANGED};
_glfwInputKeyboard(window, &glfw_keyevent);
}
debug_key("Sending text received in readSelectionFromPasteboard as key event\n");
GLFWkeyevent glfw_keyevent = {.text=utf8, .ime_state=GLFW_IME_COMMIT_TEXT};
_glfwInputKeyboard(window, &glfw_keyevent);
return YES;
}
return NO;
}
@end
// }}}

View File

@@ -14,6 +14,10 @@ is_openbsd = 'openbsd' in _plat
base = os.path.dirname(os.path.abspath(__file__))
def null_func() -> None:
return None
class CompileKey(NamedTuple):
src: str
dest: str
@@ -23,7 +27,7 @@ class Command(NamedTuple):
desc: str
cmd: Sequence[str]
is_newer_func: Callable[[], bool]
on_success: Callable[[], None] = lambda: None
on_success: Callable[[], None] = null_func
key: Optional[CompileKey] = None
keyfile: Optional[str] = None

2
glfw/glfw3.h vendored
View File

@@ -1719,6 +1719,7 @@ typedef void (* GLFWtickcallback)(void*);
typedef void (* GLFWactivationcallback)(GLFWwindow *window, const char *token, void *data);
typedef bool (* GLFWdrawtextfun)(GLFWwindow *window, const char *text, uint32_t fg, uint32_t bg, uint8_t *output_buf, size_t width, size_t height, float x_offset, float y_offset, size_t right_margin);
typedef char* (* GLFWcurrentselectionfun)(void);
typedef bool (* GLFWhascurrentselectionfun)(void);
typedef void (* GLFWclipboarddatafreefun)(void* data);
typedef struct GLFWDataChunk {
const char *data;
@@ -1889,6 +1890,7 @@ GLFWAPI void glfwUpdateTimer(unsigned long long timer_id, monotonic_t interval,
GLFWAPI void glfwRemoveTimer(unsigned long long);
GLFWAPI GLFWdrawtextfun glfwSetDrawTextFunction(GLFWdrawtextfun function);
GLFWAPI GLFWcurrentselectionfun glfwSetCurrentSelectionCallback(GLFWcurrentselectionfun callback);
GLFWAPI GLFWhascurrentselectionfun glfwSetHasCurrentSelectionCallback(GLFWhascurrentselectionfun callback);
/*! @brief Terminates the GLFW library.
*

44
glfw/ibus_glfw.c vendored
View File

@@ -283,29 +283,35 @@ static const char*
get_ibus_address_file_name(void) {
const char *addr;
static char ans[PATH_MAX];
static char display[64] = {0};
addr = getenv("IBUS_ADDRESS");
int offset = 0;
if (addr && addr[0]) {
memcpy(ans, addr, GLFW_MIN(strlen(addr), sizeof(ans)));
return ans;
}
const char *de = getenv("DISPLAY");
if (!de || !de[0]) de = ":0.0";
char *display = _glfw_strdup(de);
const char *host = display;
char *disp_num = strrchr(display, ':');
char *screen_num = strrchr(display, '.');
if (!disp_num) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as DISPLAY env var has no colon");
free(display);
return NULL;
const char* disp_num = NULL;
const char *host = "unix";
// See https://github.com/ibus/ibus/commit/8ce25208c3f4adfd290a032c6aa739d2b7580eb1 for why we need this dance.
const char *de = getenv("WAYLAND_DISPLAY");
if (de) {
disp_num = de;
} else {
const char *de = getenv("DISPLAY");
if (!de || !de[0]) de = ":0.0";
strncpy(display, de, sizeof(display) - 1);
char *dnum = strrchr(display, ':');
if (!dnum) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as DISPLAY env var has no colon");
return NULL;
}
char *screen_num = strrchr(display, '.');
*dnum = 0;
dnum++;
if (screen_num) *screen_num = 0;
if (*display) host = display;
disp_num = dnum;
}
*disp_num = 0;
disp_num++;
if (screen_num) *screen_num = 0;
if (!*host) host = "unix";
memset(ans, 0, sizeof(ans));
const char *conf_env = getenv("XDG_CONFIG_HOME");
@@ -315,7 +321,6 @@ get_ibus_address_file_name(void) {
conf_env = getenv("HOME");
if (!conf_env || !conf_env[0]) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Could not get IBUS address file name as no HOME env var is set");
free(display);
return NULL;
}
offset = snprintf(ans, sizeof(ans), "%s/.config", conf_env);
@@ -323,7 +328,6 @@ get_ibus_address_file_name(void) {
char *key = dbus_get_local_machine_id();
snprintf(ans + offset, sizeof(ans) - offset, "/ibus/bus/%s-%s-%s", key, host, disp_num);
dbus_free(key);
free(display);
return ans;
}
@@ -383,12 +387,12 @@ input_context_created(DBusMessage *msg, const char* errmsg, void *data) {
enum Capabilities caps = IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT;
if (!glfw_dbus_call_method_no_reply(ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID)) return;
ibus->ok = true;
glfw_ibus_set_focused(ibus, false);
glfw_ibus_set_focused(ibus, _glfwFocusedWindow() != NULL);
glfw_ibus_set_cursor_geometry(ibus, 0, 0, 0, 0);
debug("Connected to IBUS daemon for IME input management\n");
}
bool
static bool
setup_connection(_GLFWIBUSData *ibus) {
const char *client_name = "GLFW_Application";
const char *address_file_name = get_ibus_address_file_name();

7
glfw/init.c vendored
View File

@@ -395,3 +395,10 @@ GLFWAPI GLFWcurrentselectionfun glfwSetCurrentSelectionCallback(GLFWcurrentselec
_GLFW_SWAP_POINTERS(_glfw.callbacks.get_current_selection, cbfun);
return cbfun;
}
GLFWAPI GLFWhascurrentselectionfun glfwSetHasCurrentSelectionCallback(GLFWhascurrentselectionfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.has_current_selection, cbfun);
return cbfun;
}

1
glfw/internal.h vendored
View File

@@ -634,6 +634,7 @@ struct _GLFWlibrary
GLFWapplicationclosefun application_close;
GLFWdrawtextfun draw_text;
GLFWcurrentselectionfun get_current_selection;
GLFWhascurrentselectionfun has_current_selection;
} callbacks;

24
glfw/wl_window.c vendored
View File

@@ -75,7 +75,7 @@ get_activation_token(
if (token == NULL) fail("Wayland: failed to create activation request token");
if (_glfw.wl.activation_requests.capacity < _glfw.wl.activation_requests.sz + 1) {
_glfw.wl.activation_requests.capacity = MAX(64u, _glfw.wl.activation_requests.capacity * 2);
_glfw.wl.activation_requests.array = realloc(_glfw.wl.activation_requests.array, _glfw.wl.activation_requests.capacity);
_glfw.wl.activation_requests.array = realloc(_glfw.wl.activation_requests.array, _glfw.wl.activation_requests.capacity * sizeof(_glfw.wl.activation_requests.array[0]));
if (!_glfw.wl.activation_requests.array) {
_glfw.wl.activation_requests.capacity = 0;
fail("Wayland: Out of memory while allocation activation request");
@@ -275,18 +275,6 @@ static void setOpaqueRegion(_GLFWwindow* window, bool commit_surface)
wl_region_destroy(region);
}
static void
swap_buffers(_GLFWwindow *window) {
// this will attach the buffer to the surface,
// the client is responsible for clearing the buffer to an appropriate blank
window->swaps_disallowed = false;
GLFWwindow *current = glfwGetCurrentContext();
bool context_is_current = ((_GLFWwindow*)current)->id == window->id;
if (!context_is_current) glfwMakeContextCurrent((GLFWwindow*)window);
window->context.swapBuffers(window);
if (!context_is_current) glfwMakeContextCurrent(current);
}
static void
resizeFramebuffer(_GLFWwindow* window) {
@@ -604,8 +592,9 @@ static void xdgSurfaceHandleConfigure(void* data,
int width = window->wl.pending.width;
int height = window->wl.pending.height;
if (!window->wl.surface_configured_once) {
window->swaps_disallowed = false;
window->wl.waiting_for_swap_to_commit = true;
window->wl.surface_configured_once = true;
swap_buffers(window);
}
if (new_states != window->wl.current.toplevel_states ||
@@ -628,12 +617,11 @@ static void xdgSurfaceHandleConfigure(void* data,
window->wl.current.decoration_mode = mode;
}
bool resized = false;
if (window->wl.pending_state) {
int width = window->wl.pending.width, height = window->wl.pending.height;
set_csd_window_geometry(window, &width, &height);
resized = dispatchChangesAfterConfigure(window, width, height);
if (window->wl.decorations.serverSide) {
bool resized = dispatchChangesAfterConfigure(window, width, height);
if (window->wl.decorations.serverSide || window->monitor || window->wl.current.toplevel_states & TOPLEVEL_STATE_FULLSCREEN) {
free_csd_surfaces(window);
} else {
ensure_csd_resources(window);
@@ -1650,7 +1638,7 @@ write_chunk(void *object, const char *data, size_t sz) {
chunked_writer *cw = object;
if (cw->cap < cw->sz + sz) {
cw->cap = MAX(cw->cap * 2, cw->sz + 8*sz);
cw->buf = realloc(cw->buf, cw->cap);
cw->buf = realloc(cw->buf, cw->cap * sizeof(cw->buf[0]));
}
memcpy(cw->buf + cw->sz, data, sz);
cw->sz += sz;

32
glfw/x11_window.c vendored
View File

@@ -729,7 +729,7 @@ get_clipboard_data(const _GLFWClipboardData *cd, const char *mime, char **data)
if (!chunk.sz) break;
if (cap < sz + chunk.sz) {
cap = MAX(cap * 2, sz + 4 * chunk.sz);
buf = realloc(buf, cap);
buf = realloc(buf, cap * sizeof(buf[0]));
}
memcpy(buf + sz, chunk.data, chunk.sz);
sz += chunk.sz;
@@ -1033,7 +1033,7 @@ getSelectionString(Atom selection, Atom *targets, size_t num_targets, GLFWclipbo
}
else if (actualType == XA_ATOM && targets[i] == _glfw.x11.TARGETS) {
found = true;
write_data(object, data, itemCount);
write_data(object, data, sizeof(Atom) * itemCount);
}
XFREE(data);
@@ -2861,7 +2861,7 @@ static MimeAtom atom_for_mime(const char *mime) {
MimeAtom ma = {.mime=_glfw_strdup(mime), .atom=XInternAtom(_glfw.x11.display, mime, 0)};
if (_glfw.x11.mime_atoms.capacity < _glfw.x11.mime_atoms.sz + 1) {
_glfw.x11.mime_atoms.capacity += 32;
_glfw.x11.mime_atoms.array = realloc(_glfw.x11.mime_atoms.array, _glfw.x11.mime_atoms.capacity);
_glfw.x11.mime_atoms.array = realloc(_glfw.x11.mime_atoms.array, _glfw.x11.mime_atoms.capacity * sizeof(_glfw.x11.mime_atoms.array[0]));
}
_glfw.x11.mime_atoms.array[_glfw.x11.mime_atoms.sz++] = ma;
return ma;
@@ -2897,17 +2897,20 @@ void _glfwPlatformSetClipboard(GLFWClipboardType t) {
typedef struct chunked_writer {
char *buf; size_t sz, cap;
bool is_self_offer;
} chunked_writer;
static bool
write_chunk(void *object, const char *data, size_t sz) {
chunked_writer *cw = object;
if (cw->cap < cw->sz + sz) {
cw->cap = MAX(cw->cap * 2, cw->sz + 8*sz);
cw->buf = realloc(cw->buf, cw->cap);
}
memcpy(cw->buf + cw->sz, data, sz);
cw->sz += sz;
if (data) {
if (cw->cap < cw->sz + sz) {
cw->cap = MAX(cw->cap * 2, cw->sz + 8*sz);
cw->buf = realloc(cw->buf, cw->cap * sizeof(cw->buf[0]));
}
memcpy(cw->buf + cw->sz, data, sz);
cw->sz += sz;
} else if (sz == 1) cw->is_self_offer = true;
return true;
}
@@ -2915,6 +2918,10 @@ static void
get_available_mime_types(Atom which_clipboard, GLFWclipboardwritedatafun write_data, void *object) {
chunked_writer cw = {0};
getSelectionString(which_clipboard, &_glfw.x11.TARGETS, 1, write_chunk, &cw, false);
if (cw.is_self_offer) {
write_data(object, NULL, 1);
return;
}
size_t count = 0;
bool ok = true;
if (cw.buf) {
@@ -2946,11 +2953,12 @@ _glfwPlatformGetClipboard(GLFWClipboardType clipboard_type, const char* mime_typ
}
size_t count = 0;
if (strcmp(mime_type, "text/plain") == 0) {
// we need to do this because GTK/GNOME is developed by morons
// they convert text/plain to DOS line endings
// UTF8_STRING is what xclip uses by default, and there are people out there that expect to be able to paste from it with a single read operation. See https://github.com/kovidgoyal/kitty/issues/5842
// Also ancient versions of GNOME use DOS line endings even for text/plain;charset=utf-8. See https://github.com/kovidgoyal/kitty/issues/5528#issuecomment-1325348218
atoms[count++] = _glfw.x11.UTF8_STRING;
// we need to do this because GTK/GNOME is moronic they convert text/plain to DOS line endings, see
// https://gitlab.gnome.org/GNOME/gtk/-/issues/2307
atoms[count++] = atom_for_mime("text/plain;charset=utf-8").atom;
atoms[count++] = _glfw.x11.UTF8_STRING;
atoms[count++] = atom_for_mime("text/plain").atom;
atoms[count++] = XA_STRING;
} else {

17
go.mod Normal file
View File

@@ -0,0 +1,17 @@
module kitty
go 1.20
require (
github.com/ALTree/bigfloat v0.0.0-20220102081255-38c8b72a9924
github.com/disintegration/imaging v1.6.2
github.com/google/go-cmp v0.5.8
github.com/google/uuid v1.3.0
github.com/jamesruan/go-rfc1924 v0.0.0-20170108144916-2767ca7c638f
github.com/seancfoley/ipaddress-go v1.5.3
golang.org/x/exp v0.0.0-20230202163644-54bba9f4231b
golang.org/x/image v0.3.0
golang.org/x/sys v0.4.0
)
require github.com/seancfoley/bintree v1.2.1 // indirect

45
go.sum Normal file
View File

@@ -0,0 +1,45 @@
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/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/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/jamesruan/go-rfc1924 v0.0.0-20170108144916-2767ca7c638f h1:Ko4+g6K16vSyUrtd/pPXuQnWsiHe5BYptEtTxfwYwCc=
github.com/jamesruan/go-rfc1924 v0.0.0-20170108144916-2767ca7c638f/go.mod h1:eHzfhOKbTGJEGPSdMHzU6jft192tHHt2Bu2vIZArvC0=
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.3 h1:fLnn4nsatd2rp3IJsVWriXv5gXn2Qiy8uxjxe4iZtTg=
github.com/seancfoley/ipaddress-go v1.5.3/go.mod h1:fpvVPC+Jso+YEhNcNiww8HQmBgKP8T4T6BTp1SLxxIo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20230202163644-54bba9f4231b h1:EqBVA+nNsObCwQoBEHy4wLU0pi7i8a4AL3pbItPdPkE=
golang.org/x/exp v0.0.0-20230202163644-54bba9f4231b/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg=
golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.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/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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -6,13 +6,21 @@ import re
import sys
from contextlib import suppress
from typing import (
TYPE_CHECKING, Callable, Dict, Iterator, List, NamedTuple, Optional, Tuple
TYPE_CHECKING,
Callable,
Dict,
Iterator,
List,
NamedTuple,
Optional,
Tuple,
)
from kitty.cli import parse_args
from kitty.cli_stub import AskCLIOptions
from kitty.constants import cache_dir
from kitty.fast_data_types import truncate_point_for_length, wcswidth
from kitty.types import run_once
from kitty.typing import BossType, KeyEventType, TypedDict
from kitty.utils import ScreenSize
@@ -447,6 +455,17 @@ class Choose(Handler): # {{{
# }}}
@run_once
def init_readline() -> None:
import readline
with suppress(OSError):
readline.read_init_file()
if 'libedit' in readline.__doc__:
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind('tab: complete')
def main(args: List[str]) -> Response:
# For some reason importing readline in a key handler in the main kitty process
# causes a crash of the python interpreter, probably because of some global
@@ -454,7 +473,7 @@ def main(args: List[str]) -> Response:
global readline
msg = 'Ask the user for input'
try:
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty ask', result_class=AskCLIOptions)
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty +kitten ask', result_class=AskCLIOptions)
except SystemExit as e:
if e.code != 0:
print(e.args[0])
@@ -476,17 +495,22 @@ def main(args: List[str]) -> Response:
loop.loop(phandler)
return {'items': items, 'response': phandler.response}
import readline as rl
readline = rl
from kitty.shell import init_readline
init_readline()
response = None
# we do this file descriptor dance to get readline to work even when STDOUT
# is redirected
orig_stdout = os.dup(sys.stdout.fileno())
try:
with open(os.ctermid(), 'r') as tty:
os.dup2(tty.fileno(), sys.stdin.fileno())
with open(os.ctermid(), 'w') as tty:
os.dup2(tty.fileno(), sys.stdout.fileno())
import readline as rl
readline = rl
init_readline()
response = None
with alternate_screen(), HistoryCompleter(cli_opts.name):
if cli_opts.message:
print(styled(cli_opts.message, bold=True))
with suppress(KeyboardInterrupt, EOFError):
with alternate_screen(), HistoryCompleter(cli_opts.name), suppress(KeyboardInterrupt, EOFError):
if cli_opts.message:
print(styled(cli_opts.message, bold=True))
if cli_opts.default:
def prefill_text() -> None:
readline.insert_text(cli_opts.default or '')
@@ -496,6 +520,10 @@ def main(args: List[str]) -> Response:
readline.set_pre_input_hook()
else:
response = input(prompt)
sys.stdout.flush()
os.dup2(orig_stdout, sys.stdout.fileno())
finally:
os.close(orig_stdout)
return {'items': items, 'response': response}
@@ -509,4 +537,5 @@ def handle_result(args: List[str], data: Response, target_window_id: int, boss:
if __name__ == '__main__':
ans = main(sys.argv)
if ans:
print(ans)
import json
print(json.dumps(ans))

View File

@@ -31,6 +31,7 @@ class Broadcast(Handler):
def __init__(self, opts: BroadcastCLIOptions, initial_strings: List[str]) -> None:
self.opts = opts
self.hide_input = False
self.initial_strings = initial_strings
self.payload = {'exclude_active': True, 'data': '', 'match': opts.match, 'match_tab': opts.match_tab, 'session_id': uuid4()}
self.line_edit = LineEdit()
@@ -40,7 +41,7 @@ class Broadcast(Handler):
def initialize(self) -> None:
self.write_broadcast_session()
self.print('Type the text to broadcast below, press', styled('Ctrl+Esc', fg='yellow'), 'to quit:')
self.print('Type the text to broadcast below, press', styled(self.opts.end_session, fg='yellow'), 'to quit:')
for x in self.initial_strings:
self.write_broadcast_text(x)
self.write(SAVE_CURSOR)
@@ -56,7 +57,8 @@ class Broadcast(Handler):
def on_text(self, text: str, in_bracketed_paste: bool = False) -> None:
self.write_broadcast_text(text)
self.line_edit.on_text(text, in_bracketed_paste)
if not self.hide_input:
self.line_edit.on_text(text, in_bracketed_paste)
self.commit_line()
def on_interrupt(self) -> None:
@@ -68,22 +70,33 @@ class Broadcast(Handler):
self.write_broadcast_text('\x04')
def on_key(self, key_event: KeyEventType) -> None:
if self.line_edit.on_key(key_event):
if key_event.matches(self.opts.hide_input_toggle):
self.hide_input ^= True
self.cmd.set_cursor_visible(not self.hide_input)
if self.hide_input:
self.end_line()
self.print('Input hidden, press', styled(self.opts.hide_input_toggle, fg='yellow'), 'to unhide:')
self.end_line()
return
if key_event.matches(self.opts.end_session):
self.quit_loop(0)
return
if not self.hide_input and self.line_edit.on_key(key_event):
self.commit_line()
if key_event.matches('enter'):
self.write_broadcast_text('\r')
self.print('')
self.line_edit.clear()
self.write(SAVE_CURSOR)
return
if key_event.matches('ctrl+esc'):
self.quit_loop(0)
self.end_line()
return
ek = encode_key_event(key_event)
ek = standard_b64encode(ek.encode('utf-8')).decode('ascii')
self.write_broadcast_data('kitty-key:' + ek)
def end_line(self) -> None:
self.print('')
self.line_edit.clear()
self.write(SAVE_CURSOR)
def write_broadcast_text(self, text: str) -> None:
self.write_broadcast_data('base64:' + standard_b64encode(text.encode('utf-8')).decode('ascii'))
@@ -98,7 +111,19 @@ class Broadcast(Handler):
self.write(session_command(self.payload, start))
OPTIONS = (MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format
OPTIONS = ('''
--hide-input-toggle
default=Ctrl+Alt+Esc
Key to press that will toggle hiding of the input in the broadcast window itself.
Useful while typing a password, prevents the password from being visible on the screen.
--end-session
default=Ctrl+Esc
Key to press to end the broadcast session.
''' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format
help_text = 'Broadcast typed text to kitty windows. By default text is sent to all windows, unless one of the matching options is specified'
usage = '[initial text to send ...]'

View File

@@ -1,6 +1,5 @@
from typing import List, Optional, Tuple
def match(
lines: List[bytes], levels: Tuple[str, str, str], needle: str,
output_positions: bool, limit: int, num_threads: int, mark_before: str,

View File

@@ -1,152 +1,91 @@
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import codecs
import io
import os
import select
import sys
from typing import List, NoReturn, Optional
from kitty.cli import parse_args
from kitty.cli_stub import ClipboardCLIOptions
from kitty.fast_data_types import parse_input_from_terminal
from ..tui.operations import (
raw_mode, request_from_clipboard, write_to_clipboard
)
OPTIONS = r'''
--get-clipboard
default=False
--get-clipboard -g
type=bool-set
Output the current contents of the clipboard to STDOUT. Note that by default
kitty will prompt for permission to access the clipboard. Can be controlled
by :opt:`clipboard_control`.
--use-primary
default=False
--use-primary -p
type=bool-set
Use the primary selection rather than the clipboard on systems that support it,
such as X11.
such as Linux.
--mime -m
type=list
The mimetype of the specified file. Useful when the auto-detected mimetype is
likely to be incorrect or the filename has no extension and therefore no mimetype
can be detected. If more than one file is specified, this option should be specified multiple
times, once for each specified file. When copying data from the clipboard, you can use wildcards
to match MIME types. For example: :code:`--mime 'text/*'` will match any textual MIME type
available on the clipboard, usually the first matching MIME type is copied. The special MIME
type :code:`.` will return the list of available MIME types currently on the system clipboard.
--alias -a
type=list
Specify aliases for MIME types. Aliased MIME types are considered equivalent.
When copying to clipboard both the original and alias are made available on the
clipboard. When copying from clipboard if the original is not found, the alias
is used, as a fallback. Can be specified multiple times to create multiple
aliases. For example: :code:`--alias text/plain=text/x-rst` makes :code:`text/plain` an alias
of :code:`text/rst`. Aliases are not used in filter mode. An alias for
:code:`text/plain` is automatically created if :code:`text/plain` is not present in the input data, but some
other :code:`text/*` MIME is present.
--wait-for-completion
default=False
type=bool-set
Wait till the copy to clipboard is complete before exiting. Useful if running
the kitten in a dedicated, ephemeral window.
the kitten in a dedicated, ephemeral window. Only needed in filter mode.
'''.format
help_text = '''\
Read or write to the system clipboard.
To set the clipboard text, pipe in the new text on STDIN. Use the
:option:`--get-clipboard` option to output the current clipboard contents to
:file:`stdout`. Note that reading the clipboard will cause a permission
This kitten operates most simply in :italic:`filter mode`.
To set the clipboard text, pipe in the new text on :file:`STDIN`. Use the
:option:`--get-clipboard` option to output the current clipboard text content to
:file:`STDOUT`. Note that copying from the clipboard will cause a permission
popup, see :opt:`clipboard_control` for details.
For more control, specify filename arguments. Then, different MIME types can be copied to/from
the clipboard. Some examples:
.. code:: sh
# Copy an image to the clipboard:
kitty +kitten clipboard picture.png
# Copy an image and some text to the clipboard:
kitty +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
# Copy any raster image available on the clipboard to a PNG file:
kitty +kitten clipboard -g picture.png
# Copy an image to a file and text to STDOUT:
kitty +kitten clipboard -g picture.png /dev/stdout
# List the formats available on the system clipboard
kitty +kitten clipboard -g -m . /dev/stdout
'''
usage = ''
got_capability_response = False
got_clipboard_response = False
clipboard_contents = ''
clipboard_from_primary = False
def ignore(x: str) -> None:
pass
def on_text(x: str) -> None:
if '\x03' in x:
raise KeyboardInterrupt()
if '\x04' in x:
raise EOFError()
def on_dcs(dcs: str) -> None:
global got_capability_response
if dcs.startswith('1+r'):
got_capability_response = True
def on_osc(osc: str) -> None:
global clipboard_contents, clipboard_from_primary, got_clipboard_response
idx = osc.find(';')
if idx <= 0:
return
q = osc[:idx]
if q == '52':
got_clipboard_response = True
widx = osc.find(';', idx + 1)
if widx < idx:
clipboard_from_primary = osc.find('p', idx + 1) > -1
clipboard_contents = ''
else:
from base64 import standard_b64decode
clipboard_from_primary = osc.find('p', idx+1, widx) > -1
data = memoryview(osc.encode('ascii'))
clipboard_contents = standard_b64decode(data[widx+1:]).decode('utf-8')
def wait_loop(tty_fd: int) -> None:
os.set_blocking(tty_fd, False)
decoder = codecs.getincrementaldecoder('utf-8')('ignore')
with raw_mode(tty_fd):
buf = ''
while not got_capability_response and not got_clipboard_response:
rd = select.select([tty_fd], [], [])[0]
if rd:
raw = os.read(tty_fd, io.DEFAULT_BUFFER_SIZE)
if not raw:
raise EOFError()
data = decoder.decode(raw)
buf = (buf + data) if buf else data
buf = parse_input_from_terminal(on_text, on_dcs, ignore, on_osc, ignore, ignore, buf, False)
def main(args: List[str]) -> NoReturn:
cli_opts, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten clipboard', result_class=ClipboardCLIOptions)
if items:
raise SystemExit('Unrecognized extra command line arguments')
data: Optional[bytes] = None
if not sys.stdin.isatty():
data = sys.stdin.buffer.read()
wait_for_capability_response = False
data_to_write = []
if data:
data_to_write.append(write_to_clipboard(data, cli_opts.use_primary).encode('ascii'))
if not cli_opts.get_clipboard and cli_opts.wait_for_completion:
data_to_write.append(b'\x1bP+q544e\x1b\\')
wait_for_capability_response = True
if cli_opts.get_clipboard:
data_to_write.append(request_from_clipboard(cli_opts.use_primary).encode('ascii'))
wait_for_capability_response = True
tty_fd = os.open(os.ctermid(), os.O_RDWR | os.O_CLOEXEC)
retcode = 0
with open(tty_fd, 'wb', closefd=True) as ttyf:
for x in data_to_write:
ttyf.write(x)
ttyf.flush()
if wait_for_capability_response:
try:
wait_loop(tty_fd)
except KeyboardInterrupt:
sys.excepthook = lambda *a: None
raise
except EOFError:
retcode = 1
if clipboard_contents:
print(end=clipboard_contents)
raise SystemExit(retcode)
usage = '[files to copy to/from]'
if __name__ == '__main__':
main(sys.argv)
raise SystemExit('This should be run as kitten clipboard')
elif __name__ == '__doc__':
from kitty.cli import CompletionSpec
cd = sys.cli_docs # type: ignore
cd['usage'] = usage
cd['options'] = OPTIONS
cd['help_text'] = help_text
cd['short_desc'] = 'Copy/paste with the system clipboard, even over SSH'
cd['args_completion'] = CompletionSpec.from_string('type:file mime:* group:Files')

View File

@@ -6,15 +6,13 @@ from contextlib import suppress
from fnmatch import fnmatch
from functools import lru_cache
from hashlib import md5
from typing import (
TYPE_CHECKING, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Union
)
from typing import TYPE_CHECKING, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Union
from kitty.guess_mime_type import guess_type
from kitty.utils import control_codes_pat
if TYPE_CHECKING:
from .highlight import DiffHighlight # noqa
from .highlight import DiffHighlight
path_name_map: Dict[str, str] = {}

View File

@@ -5,13 +5,13 @@ import os
from typing import Any, Dict, Iterable, Optional
from kitty.cli_stub import DiffCLIOptions
from kitty.conf.utils import (
load_config as _load_config, parse_config_base, resolve_config
)
from kitty.conf.utils import load_config as _load_config
from kitty.conf.utils import parse_config_base, resolve_config
from kitty.constants import config_dir
from kitty.rgb import color_as_sgr
from .options.types import Options as DiffOptions, defaults
from .options.types import Options as DiffOptions
from .options.types import defaults
formats: Dict[str, str] = {
'title': '',
@@ -41,9 +41,7 @@ defconf = os.path.join(config_dir, 'diff.conf')
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> DiffOptions:
from .options.parse import (
create_result_dict, merge_result_dicts, parse_conf_item
)
from .options.parse import create_result_dict, merge_result_dicts, parse_conf_item
def parse_config(lines: Iterable[str]) -> Dict[str, Any]:
ans: Dict[str, Any] = create_result_dict()

View File

@@ -2,7 +2,6 @@ from typing import List, Optional, Tuple
from .collect import Segment
def split_with_highlights(
line: str, truncate_points: List[int], fg_highlights: List[Segment],
bg_highlight: Optional[Segment]

View File

@@ -5,9 +5,7 @@ import concurrent
import os
import re
from concurrent.futures import ProcessPoolExecutor
from typing import (
IO, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast
)
from typing import IO, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast
from pygments import highlight # type: ignore
from pygments.formatter import Formatter # type: ignore

View File

@@ -14,16 +14,24 @@ from enum import Enum, auto
from functools import partial
from gettext import gettext as _
from typing import (
Any, DefaultDict, Dict, Iterable, Iterator, List, Optional, Tuple, Union
Any,
DefaultDict,
Dict,
Iterable,
Iterator,
List,
Optional,
Tuple,
Union,
)
from kitty.cli import CONFIG_HELP, parse_args
from kitty.cli import CONFIG_HELP, CompletionSpec, parse_args
from kitty.cli_stub import DiffCLIOptions
from kitty.conf.utils import KeyAction
from kitty.constants import appname
from kitty.fast_data_types import wcswidth
from kitty.key_encoding import EventType, KeyEvent
from kitty.utils import ScreenSize
from kitty.utils import ScreenSize, extract_all_from_tarfile_safely
from ..tui.handler import Handler
from ..tui.images import ImageManager, Placement
@@ -32,21 +40,33 @@ from ..tui.loop import Loop
from ..tui.operations import styled
from . import global_data
from .collect import (
Collection, add_remote_dir, create_collection, data_for_path,
lines_for_path, sanitize, set_highlight_data
Collection,
add_remote_dir,
create_collection,
data_for_path,
lines_for_path,
sanitize,
set_highlight_data,
)
from .config import init_config
from .options.types import Options as DiffOptions
from .patch import Differ, Patch, set_diff_command, worker_processes
from .render import (
ImagePlacement, ImageSupportWarning, Line, LineRef, Reference, render_diff
ImagePlacement,
ImageSupportWarning,
Line,
LineRef,
Reference,
render_diff,
)
from .search import BadRegex, Search
try:
from .highlight import (
DiffHighlight, get_highlight_processes, highlight_collection,
initialize_highlighter
DiffHighlight,
get_highlight_processes,
highlight_collection,
initialize_highlighter,
)
has_highlighter = True
DiffHighlight
@@ -229,8 +249,8 @@ class DiffHandler(Handler):
self.diff_lines: Tuple[Line, ...] = tuple(render_diff(self.collection, self.diff_map, self.args, self.screen_size.cols, self.image_manager))
self.margin_size = render_diff.margin_size
self.ref_path_map: DefaultDict[str, List[Tuple[int, Reference]]] = defaultdict(list)
for i, l in enumerate(self.diff_lines):
self.ref_path_map[l.ref.path].append((i, l.ref))
for i, dl in enumerate(self.diff_lines):
self.ref_path_map[dl.ref.path].append((i, dl.ref))
self.max_scroll_pos = len(self.diff_lines) - self.num_lines
if self.current_search is not None:
self.current_search(self.diff_lines, self.margin_size, self.screen_size.cols)
@@ -319,7 +339,7 @@ class DiffHandler(Handler):
fg=self.opts.foreground, bg=self.opts.background,
cursor=self.opts.foreground, select_fg=self.opts.select_fg,
select_bg=self.opts.select_bg)
self.cmd.set_cursor_shape('bar')
self.cmd.set_cursor_shape('beam')
def finalize(self) -> None:
self.cmd.set_default_colors()
@@ -577,6 +597,7 @@ number set in :file:`diff.conf`.
--config
type=list
completion=type:file ext:conf group:"Config files" kwds:none,NONE
{config_help}
@@ -629,7 +650,7 @@ def get_ssh_file(hostname: str, rpath: str) -> str:
raise SystemExit(p.returncode)
with tarfile.open(fileobj=io.BytesIO(raw), mode='r:') as tf:
members = tf.getmembers()
tf.extractall(tdir)
extract_all_from_tarfile_safely(tf, tdir)
if len(members) == 1:
for root, dirs, files in os.walk(tdir):
if files:
@@ -687,6 +708,7 @@ elif __name__ == '__doc__':
cd['usage'] = usage
cd['options'] = OPTIONS
cd['help_text'] = help_text
cd['args_completion'] = CompletionSpec.from_string('type:file mime:text/* mime:image/* group:"Text and image files"')
elif __name__ == '__conf__':
from .options.definition import definition
sys.options_definition = definition # type: ignore

View File

@@ -6,7 +6,6 @@
from kitty.conf.types import Action, Definition
definition = Definition(
'kittens.diff',
Action('map', 'parse_map', {'key_definitions': 'kitty.conf.utils.KittensKeyMap'}, ['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']),

View File

@@ -1,5 +1,6 @@
# generated by gen-config.py DO NOT edit
# isort: skip_file
import typing
from kittens.diff.options.utils import parse_map, store_multiple, syntax_aliases
from kitty.conf.utils import merge_dicts, positive_int, python_string, to_color, to_color_or_none

View File

@@ -1,5 +1,6 @@
# generated by gen-config.py DO NOT edit
# isort: skip_file
import typing
from kitty.conf.utils import KeyAction, KittensKeyMap
import kitty.conf.utils
@@ -121,53 +122,53 @@ defaults = Options()
defaults.ignore_name = {}
defaults.map = [
# quit
(ParsedShortcut(mods=0, key_name='q'), KeyAction('quit')), # noqa
(ParsedShortcut(mods=0, key_name='q'), KeyAction('quit')),
# quit
(ParsedShortcut(mods=0, key_name='ESCAPE'), KeyAction('quit')), # noqa
(ParsedShortcut(mods=0, key_name='ESCAPE'), KeyAction('quit')),
# scroll_down
(ParsedShortcut(mods=0, key_name='j'), KeyAction('scroll_by', (1,))), # noqa
(ParsedShortcut(mods=0, key_name='j'), KeyAction('scroll_by', (1,))),
# scroll_down
(ParsedShortcut(mods=0, key_name='DOWN'), KeyAction('scroll_by', (1,))), # noqa
(ParsedShortcut(mods=0, key_name='DOWN'), KeyAction('scroll_by', (1,))),
# scroll_up
(ParsedShortcut(mods=0, key_name='k'), KeyAction('scroll_by', (-1,))), # noqa
(ParsedShortcut(mods=0, key_name='k'), KeyAction('scroll_by', (-1,))),
# scroll_up
(ParsedShortcut(mods=0, key_name='UP'), KeyAction('scroll_by', (-1,))), # noqa
(ParsedShortcut(mods=0, key_name='UP'), KeyAction('scroll_by', (-1,))),
# scroll_top
(ParsedShortcut(mods=0, key_name='HOME'), KeyAction('scroll_to', ('start',))), # noqa
(ParsedShortcut(mods=0, key_name='HOME'), KeyAction('scroll_to', ('start',))),
# scroll_bottom
(ParsedShortcut(mods=0, key_name='END'), KeyAction('scroll_to', ('end',))), # noqa
(ParsedShortcut(mods=0, key_name='END'), KeyAction('scroll_to', ('end',))),
# scroll_page_down
(ParsedShortcut(mods=0, key_name='PAGE_DOWN'), KeyAction('scroll_to', ('next-page',))), # noqa
(ParsedShortcut(mods=0, key_name='PAGE_DOWN'), KeyAction('scroll_to', ('next-page',))),
# scroll_page_down
(ParsedShortcut(mods=0, key_name=' '), KeyAction('scroll_to', ('next-page',))), # noqa
(ParsedShortcut(mods=0, key_name=' '), KeyAction('scroll_to', ('next-page',))),
# scroll_page_up
(ParsedShortcut(mods=0, key_name='PAGE_UP'), KeyAction('scroll_to', ('prev-page',))), # noqa
(ParsedShortcut(mods=0, key_name='PAGE_UP'), KeyAction('scroll_to', ('prev-page',))),
# next_change
(ParsedShortcut(mods=0, key_name='n'), KeyAction('scroll_to', ('next-change',))), # noqa
(ParsedShortcut(mods=0, key_name='n'), KeyAction('scroll_to', ('next-change',))),
# prev_change
(ParsedShortcut(mods=0, key_name='p'), KeyAction('scroll_to', ('prev-change',))), # noqa
(ParsedShortcut(mods=0, key_name='p'), KeyAction('scroll_to', ('prev-change',))),
# all_context
(ParsedShortcut(mods=0, key_name='a'), KeyAction('change_context', ('all',))), # noqa
(ParsedShortcut(mods=0, key_name='a'), KeyAction('change_context', ('all',))),
# default_context
(ParsedShortcut(mods=0, key_name='='), KeyAction('change_context', ('default',))), # noqa
(ParsedShortcut(mods=0, key_name='='), KeyAction('change_context', ('default',))),
# increase_context
(ParsedShortcut(mods=0, key_name='+'), KeyAction('change_context', (5,))), # noqa
(ParsedShortcut(mods=0, key_name='+'), KeyAction('change_context', (5,))),
# decrease_context
(ParsedShortcut(mods=0, key_name='-'), KeyAction('change_context', (-5,))), # noqa
(ParsedShortcut(mods=0, key_name='-'), KeyAction('change_context', (-5,))),
# search_forward
(ParsedShortcut(mods=0, key_name='/'), KeyAction('start_search', (True, False))), # noqa
(ParsedShortcut(mods=0, key_name='/'), KeyAction('start_search', (True, False))),
# search_backward
(ParsedShortcut(mods=0, key_name='?'), KeyAction('start_search', (True, True))), # noqa
(ParsedShortcut(mods=0, key_name='?'), KeyAction('start_search', (True, True))),
# next_match
(ParsedShortcut(mods=0, key_name='.'), KeyAction('scroll_to', ('next-match',))), # noqa
(ParsedShortcut(mods=0, key_name='.'), KeyAction('scroll_to', ('next-match',))),
# next_match
(ParsedShortcut(mods=0, key_name='>'), KeyAction('scroll_to', ('next-match',))), # noqa
(ParsedShortcut(mods=0, key_name='>'), KeyAction('scroll_to', ('next-match',))),
# prev_match
(ParsedShortcut(mods=0, key_name=','), KeyAction('scroll_to', ('prev-match',))), # noqa
(ParsedShortcut(mods=0, key_name=','), KeyAction('scroll_to', ('prev-match',))),
# prev_match
(ParsedShortcut(mods=0, key_name='<'), KeyAction('scroll_to', ('prev-match',))), # noqa
(ParsedShortcut(mods=0, key_name='<'), KeyAction('scroll_to', ('prev-match',))),
# search_forward_simple
(ParsedShortcut(mods=0, key_name='f'), KeyAction('start_search', (False, False))), # noqa
(ParsedShortcut(mods=0, key_name='f'), KeyAction('start_search', (False, False))),
# search_backward_simple
(ParsedShortcut(mods=0, key_name='b'), KeyAction('start_search', (False, True))), # noqa
(ParsedShortcut(mods=0, key_name='b'), KeyAction('start_search', (False, True))),
]

View File

@@ -5,9 +5,7 @@
from typing import Any, Container, Dict, Iterable, Tuple, Union
from kitty.conf.utils import (
KeyFuncWrapper, KittensKeyDefinition, parse_kittens_key
)
from kitty.conf.utils import KeyFuncWrapper, KittensKeyDefinition, parse_kittens_key
ReturnType = Tuple[str, Any]
func_with_args = KeyFuncWrapper[ReturnType]()

View File

@@ -13,10 +13,7 @@ from kitty.types import run_once
from kitty.utils import ScreenSize
from ..tui.images import ImageManager, can_display_images
from .collect import (
Collection, Segment, data_for_path, highlights_for_path, is_image,
lines_for_path, path_name_map, sanitize
)
from .collect import Collection, Segment, data_for_path, highlights_for_path, is_image, lines_for_path, path_name_map, sanitize
from .config import formats
from .diff_speedup import split_with_highlights as _split_with_highlights
from .patch import Chunk, Hunk, Patch

View File

@@ -5,9 +5,9 @@ import re
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Tuple
from kitty.fast_data_types import wcswidth
from .options.types import Options as DiffOptions
from ..tui.operations import styled
from .options.types import Options as DiffOptions
if TYPE_CHECKING:
from .render import Line

View File

@@ -8,10 +8,7 @@ import sys
from functools import lru_cache
from gettext import gettext as _
from itertools import repeat
from typing import (
Any, Callable, Dict, Generator, Iterable, Iterator, List, Optional,
Pattern, Sequence, Set, Tuple, Type, cast
)
from typing import Any, Callable, Dict, Generator, Iterable, Iterator, List, Optional, Pattern, Sequence, Set, Tuple, Type, cast
from kitty.cli import parse_args
from kitty.cli_stub import HintsCLIOptions
@@ -20,10 +17,7 @@ from kitty.constants import website_url
from kitty.fast_data_types import get_options, wcswidth
from kitty.key_encoding import KeyEvent
from kitty.typing import BossType, KittyCommonOpts
from kitty.utils import (
ScreenSize, kitty_ansi_sanitizer_pat, resolve_custom_file,
screen_size_function
)
from kitty.utils import ScreenSize, kitty_ansi_sanitizer_pat, resolve_custom_file, screen_size_function
from ..tui.handler import Handler, result_handler
from ..tui.loop import Loop

View File

@@ -1,15 +1,17 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
import argparse
import os
import re
import signal
import socket
import subprocess
import sys
from typing import Callable, cast
from typing import Callable, List, cast
from urllib.parse import quote_from_bytes
from kitty.utils import get_hostname
def write_hyperlink(write: Callable[[bytes], None], url: bytes, line: bytes, frag: bytes = b'') -> None:
text = b'\033]8;;' + url
@@ -19,16 +21,46 @@ def write_hyperlink(write: Callable[[bytes], None], url: bytes, line: bytes, fra
write(text)
def parse_options(argv: List[str]) -> argparse.Namespace:
p = argparse.ArgumentParser(add_help=False)
p.add_argument('--context-separator', default='--')
p.add_argument('-c', '--count', action='store_true')
p.add_argument('--count-matches', action='store_true')
p.add_argument('--field-context-separator', default='-')
p.add_argument('--field-match-separator', default='-')
p.add_argument('--files', action='store_true')
p.add_argument('-l', '--files-with-matches', action='store_true')
p.add_argument('--files-without-match', action='store_true')
p.add_argument('-h', '--help', action='store_true')
p.add_argument('--json', action='store_true')
p.add_argument('-I', '--no-filename', action='store_true')
p.add_argument('--no-heading', action='store_true')
p.add_argument('-N', '--no-line-number', action='store_true')
p.add_argument('-0', '--null', action='store_true')
p.add_argument('--null-data', action='store_true')
p.add_argument('--path-separator', default=os.path.sep)
p.add_argument('--stats', action='store_true')
p.add_argument('--type-list', action='store_true')
p.add_argument('-V', '--version', action='store_true')
p.add_argument('--vimgrep', action='store_true')
p.add_argument(
'-p', '--pretty',
default=sys.stdout.isatty(),
action='store_true',
)
p.add_argument('--kitten', action='append', default=[])
args, _ = p.parse_known_args(argv)
return args
def main() -> None:
i = 1
args = parse_options(sys.argv[1:])
all_link_options = {'matching_lines', 'context_lines', 'file_headers'}
link_options = set()
delegate_to_rg = False
def parse_link_options(raw: str) -> None:
nonlocal delegate_to_rg
if not raw:
raise SystemExit('Must specify an argument for --kitten option')
for raw in args.kitten:
p, _, s = raw.partition('=')
if p != 'hyperlink':
raise SystemExit(f'Unknown argument for --kitten: {raw}')
@@ -48,11 +80,8 @@ def main() -> None:
while i < len(sys.argv):
if sys.argv[i] == '--kitten':
next_item = '' if i + 1 >= len(sys.argv) else sys.argv[i + 1]
parse_link_options(next_item)
del sys.argv[i:i+2]
elif sys.argv[i].startswith('--kitten='):
parse_link_options(sys.argv[i][len('--kitten='):])
del sys.argv[i]
else:
i += 1
@@ -62,7 +91,23 @@ def main() -> None:
link_context_lines = 'context_lines' in link_options
link_matching_lines = 'matching_lines' in link_options
if delegate_to_rg or (not sys.stdout.isatty() and '--pretty' not in sys.argv and '-p' not in sys.argv):
if any((
args.context_separator != '--',
args.field_context_separator != '-',
args.field_match_separator != '-',
args.help,
args.json,
args.no_filename,
args.null,
args.null_data,
args.path_separator != os.path.sep,
args.type_list,
args.version,
not args.pretty,
)):
delegate_to_rg = True
if delegate_to_rg:
os.execlp('rg', 'rg', *sys.argv[1:])
cmdline = ['rg', '--pretty', '--with-filename'] + sys.argv[1:]
try:
@@ -70,13 +115,22 @@ def main() -> None:
except FileNotFoundError:
raise SystemExit('Could not find the rg executable in your PATH. Is ripgrep installed?')
assert p.stdout is not None
write: Callable[[bytes], None] = cast(Callable[[bytes], None], sys.stdout.buffer.write)
sgr_pat = re.compile(br'\x1b\[.*?m')
osc_pat = re.compile(b'\x1b\\].*?\x1b\\\\')
num_pat = re.compile(br'^(\d+)([:-])')
path_with_count_pat = re.compile(br'(.*?)(:\d+)')
path_with_linenum_pat = re.compile(br'^(.*?):(\d+):')
stats_pat = re.compile(br'^\d+ matches$')
vimgrep_pat = re.compile(br'^(.*?):(\d+):(\d+):')
in_stats = False
in_result: bytes = b''
hostname = socket.gethostname().encode('utf-8')
hostname = get_hostname().encode('utf-8')
def get_quoted_url(file_path: bytes) -> bytes:
return b'file://' + hostname + quote_from_bytes(os.path.abspath(file_path)).encode('utf-8')
try:
for line in p.stdout:
@@ -85,21 +139,42 @@ def main() -> None:
if not clean_line:
in_result = b''
write(b'\n')
elif in_stats:
write(line)
elif in_result:
m = num_pat.match(clean_line)
if m is not None:
is_match_line = m.group(2) == b':'
if (is_match_line and link_matching_lines) or (not is_match_line and link_context_lines):
write_hyperlink(write, in_result, line, frag=m.group(1))
continue
if not args.no_line_number:
m = num_pat.match(clean_line)
if m is not None:
is_match_line = m.group(2) == b':'
if (is_match_line and link_matching_lines) or (not is_match_line and link_context_lines):
write_hyperlink(write, in_result, line, frag=m.group(1))
continue
write(line)
else:
if line.strip():
path = quote_from_bytes(os.path.abspath(clean_line)).encode('utf-8')
in_result = b'file://' + hostname + path
if link_file_headers:
write_hyperlink(write, in_result, line)
continue
# The option priority should be consistent with ripgrep here.
if args.stats and not in_stats and stats_pat.match(clean_line):
in_stats = True
elif args.count or args.count_matches:
m = path_with_count_pat.match(clean_line)
if m is not None and link_file_headers:
write_hyperlink(write, get_quoted_url(m.group(1)), line)
continue
elif args.files or args.files_with_matches or args.files_without_match:
if link_file_headers:
write_hyperlink(write, get_quoted_url(clean_line), line)
continue
elif args.vimgrep or args.no_heading:
# When the vimgrep option is present, it will take precedence.
m = vimgrep_pat.match(clean_line) if args.vimgrep else path_with_linenum_pat.match(clean_line)
if m is not None and (link_file_headers or link_matching_lines):
write_hyperlink(write, get_quoted_url(m.group(1)), line, frag=m.group(2))
continue
else:
in_result = get_quoted_url(clean_line)
if link_file_headers:
write_hyperlink(write, in_result, line)
continue
write(line)
except KeyboardInterrupt:
p.send_signal(signal.SIGINT)
@@ -112,3 +187,6 @@ def main() -> None:
if __name__ == '__main__':
main()
elif __name__ == '__wrapper_of__':
cd = sys.cli_docs # type: ignore
cd['wrapper_of'] = 'rg'

View File

@@ -1,38 +1,6 @@
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import contextlib
import os
import re
import signal
import socket
import sys
import zlib
from base64 import standard_b64encode
from math import ceil
from tempfile import NamedTemporaryFile
from typing import (
Dict, Generator, List, NamedTuple, Optional, Pattern, Tuple, Union
)
from kitty.cli import parse_args
from kitty.cli_stub import IcatCLIOptions
from kitty.constants import appname
from kitty.guess_mime_type import guess_type
from kitty.rgb import to_color
from kitty.types import run_once
from kitty.typing import GRT_f, GRT_t
from kitty.utils import (
TTYIO, ScreenSize, ScreenSizeGetter, screen_size_function
)
from ..tui.images import (
ConvertFailed, Dispose, GraphicsCommand, NoImageMagick, OpenFailed,
OutdatedImageMagick, RenderedImage, fsenc, identify,
render_as_single_image, render_image
)
from ..tui.operations import clear_images_on_screen, raw_mode
OPTIONS = '''\
--align
type=choices
@@ -46,7 +14,10 @@ Choose where on the screen to display the image. The image will be scaled to fit
into the specified rectangle. The syntax for specifying rectangles is
<:italic:`width`>x<:italic:`height`>@<:italic:`left`>x<:italic:`top`>.
All measurements are in cells (i.e. cursor positions) with the origin
:italic:`(0, 0)` at the top-left corner of the screen.
:italic:`(0, 0)` at the top-left corner of the screen. Note that the :option:`--align`
option will horizontally align the image within this rectangle. By default, the image
is horizontally centered within the rectangle. Using place will cause the cursor to
be positioned at the top left corner of the image, instead of on the line after the image.
--scale-up
@@ -76,13 +47,14 @@ Remove all images currently displayed on the screen.
--transfer-mode
type=choices
choices=detect,file,stream
choices=detect,file,stream,memory
default=detect
Which mechanism to use to transfer images to the terminal. The default is to
auto-detect. :italic:`file` means to use a temporary file and :italic:`stream`
means to send the data via terminal escape codes. Note that if you use the
:italic:`file` transfer mode and you are connecting over a remote session then
image display will not work.
auto-detect. :italic:`file` means to use a temporary file, :italic:`memory` means
to use shared memory, :italic:`stream` means to send the data via terminal
escape codes. Note that if you use the :italic:`file` or :italic:`memory` transfer
modes and you are connecting over a remote session then image display will not
work.
--detect-support
@@ -117,7 +89,17 @@ not a terminal, but you can turn it off or on explicitly, if needed.
--silent
type=bool-set
Do not print out anything to STDOUT during operation.
Not used, present for legacy compatibility.
--engine
type=choices
choices=auto,builtin,magick
default=auto
The engine used for decoding and processing of images. The default is to use
the most appropriate engine. The :code:`builtin` engine uses Go's native
imaging libraries. The :code:`magick` engine uses ImageMagick which requires
it to be installed on the system.
--z-index -z
@@ -140,306 +122,6 @@ type=bool-set
Wait for a key press before exiting after displaying the images.
'''
screen_size: Optional[ScreenSizeGetter] = None
can_transfer_with_files = False
def get_screen_size_function() -> ScreenSizeGetter:
global screen_size
if screen_size is None:
screen_size = screen_size_function()
return screen_size
def get_screen_size() -> ScreenSize:
screen_size = get_screen_size_function()
return screen_size()
@run_once
def options_spec() -> str:
return OPTIONS.format(appname=f'{appname}-icat')
def write_gr_cmd(cmd: GraphicsCommand, payload: Optional[bytes] = None) -> None:
sys.stdout.buffer.write(cmd.serialize(payload or b''))
sys.stdout.flush()
def calculate_in_cell_x_offset(width: int, cell_width: int, align: str) -> int:
if align == 'left':
return 0
extra_pixels = width % cell_width
if not extra_pixels:
return 0
if align == 'right':
return cell_width - extra_pixels
return (cell_width - extra_pixels) // 2
def set_cursor(cmd: GraphicsCommand, width: int, height: int, align: str) -> None:
ss = get_screen_size()
cw = int(ss.width / ss.cols)
num_of_cells_needed = int(ceil(width / cw))
cmd.X = calculate_in_cell_x_offset(width, cw, align)
extra_cells = 0
if align == 'center':
extra_cells = (ss.cols - num_of_cells_needed) // 2
elif align == 'right':
extra_cells = (ss.cols - num_of_cells_needed)
if extra_cells:
sys.stdout.buffer.write(b' ' * extra_cells)
def set_cursor_for_place(place: 'Place', cmd: GraphicsCommand, width: int, height: int, align: str) -> None:
x = place.left + 1
ss = get_screen_size()
cw = int(ss.width / ss.cols)
num_of_cells_needed = int(ceil(width / cw))
cmd.X = calculate_in_cell_x_offset(width, cw, align)
extra_cells = 0
if align == 'center':
extra_cells = (place.width - num_of_cells_needed) // 2
elif align == 'right':
extra_cells = place.width - num_of_cells_needed
sys.stdout.buffer.write(f'\033[{place.top + 1};{x + extra_cells}H'.encode('ascii'))
def write_chunked(cmd: GraphicsCommand, data: bytes) -> None:
cmd = cmd.clone()
if cmd.f != 100:
data = zlib.compress(data)
cmd.o = 'z'
data = standard_b64encode(data)
ac = cmd.a
quiet = cmd.q
while data:
chunk, data = data[:4096], data[4096:]
cmd.m = 1 if data else 0
write_gr_cmd(cmd, chunk)
cmd.clear()
cmd.a = ac
cmd.q = quiet
def show(
outfile: str,
width: int, height: int, zindex: int,
fmt: 'GRT_f',
transmit_mode: 'GRT_t' = 't',
align: str = 'center',
place: Optional['Place'] = None,
use_number: int = 0
) -> None:
cmd = GraphicsCommand()
cmd.a = 'T'
cmd.f = fmt
cmd.s = width
cmd.v = height
cmd.z = zindex
if use_number:
cmd.I = use_number # noqa
cmd.q = 2
if place:
set_cursor_for_place(place, cmd, width, height, align)
else:
set_cursor(cmd, width, height, align)
if can_transfer_with_files:
cmd.t = transmit_mode
write_gr_cmd(cmd, standard_b64encode(os.path.abspath(outfile).encode(fsenc)))
else:
with open(outfile, 'rb') as f:
data = f.read()
if transmit_mode == 't':
os.unlink(outfile)
if fmt == 100:
cmd.S = len(data)
write_chunked(cmd, data)
def show_frames(frame_data: RenderedImage, use_number: int, loops: int) -> None:
transmit_cmd = GraphicsCommand()
transmit_cmd.a = 'f'
transmit_cmd.I = use_number # noqa
transmit_cmd.q = 2
if can_transfer_with_files:
transmit_cmd.t = 't'
transmit_cmd.f = 24 if frame_data.mode == 'rgb' else 32
def control(frame_number: int = 0, loops: Optional[int] = None, gap: Optional[int] = 0, animation_control: int = 0) -> None:
cmd = GraphicsCommand()
cmd.a = 'a'
cmd.I = use_number # noqa
cmd.r = frame_number
if loops is not None:
cmd.v = loops + 1
if gap is not None:
cmd.z = gap if gap > 0 else -1
if animation_control:
cmd.s = animation_control
write_gr_cmd(cmd)
anchor_frame = 0
for frame in frame_data.frames:
frame_number = frame.index + 1
if frame.dispose < Dispose.previous:
anchor_frame = frame_number
if frame_number == 1:
control(frame_number, gap=frame.gap, loops=None if loops < 1 else loops)
continue
if frame.dispose is Dispose.previous:
if anchor_frame != frame_number:
transmit_cmd.c = anchor_frame
else:
transmit_cmd.c = (frame_number - 1) if frame.needs_blend else 0
transmit_cmd.s = frame.width
transmit_cmd.v = frame.height
transmit_cmd.x = frame.canvas_x
transmit_cmd.y = frame.canvas_y
transmit_cmd.z = frame.gap if frame.gap > 0 else -1
if can_transfer_with_files:
write_gr_cmd(transmit_cmd, standard_b64encode(os.path.abspath(frame.path).encode(fsenc)))
else:
with open(frame.path, 'rb') as f:
data = f.read()
write_chunked(transmit_cmd, data)
if frame_number == 2:
control(animation_control=2)
control(animation_control=3)
def parse_z_index(val: str) -> int:
origin = 0
if val.startswith('--'):
val = val[1:]
origin = -1073741824
return origin + int(val)
class ParsedOpts:
place: Optional['Place'] = None
z_index: int = 0
remove_alpha: str = ''
flip: bool = False
flop: bool = False
def process(path: str, args: IcatCLIOptions, parsed_opts: ParsedOpts, is_tempfile: bool) -> bool:
m = identify(path)
ss = get_screen_size()
available_width = parsed_opts.place.width * (ss.width // ss.cols) if parsed_opts.place else ss.width
available_height = parsed_opts.place.height * (ss.height // ss.rows) if parsed_opts.place else 10 * m.height
needs_scaling = m.width > available_width or m.height > available_height
needs_scaling = needs_scaling or args.scale_up
needs_conversion = needs_scaling or bool(parsed_opts.remove_alpha) or parsed_opts.flip or parsed_opts.flop
file_removed = False
use_number = 0
if m.fmt == 'png' and not needs_conversion:
outfile = path
transmit_mode: 'GRT_t' = 't' if is_tempfile else 'f'
fmt: 'GRT_f' = 100
width, height = m.width, m.height
file_removed = transmit_mode == 't'
else:
fmt = 24 if m.mode == 'rgb' else 32
transmit_mode = 't'
if len(m) == 1 or args.loop == 0:
outfile, width, height = render_as_single_image(
path, m, available_width, available_height, args.scale_up,
remove_alpha=parsed_opts.remove_alpha, flip=parsed_opts.flip, flop=parsed_opts.flop)
else:
import struct
use_number = max(1, struct.unpack('@I', os.urandom(4))[0])
with NamedTemporaryFile(prefix='tty-graphics-protocol-') as f:
prefix = f.name
frame_data = render_image(
path, prefix, m, available_width, available_height, args.scale_up,
remove_alpha=parsed_opts.remove_alpha, flip=parsed_opts.flip, flop=parsed_opts.flop)
outfile, width, height = frame_data.frames[0].path, frame_data.width, frame_data.height
show(
outfile, width, height, parsed_opts.z_index, fmt, transmit_mode,
align=args.align, place=parsed_opts.place, use_number=use_number
)
if use_number:
show_frames(frame_data, use_number, args.loop)
if not can_transfer_with_files:
for fr in frame_data.frames:
with contextlib.suppress(FileNotFoundError):
os.unlink(fr.path)
if not args.place:
print() # ensure cursor is on a new line
return file_removed
def scan(d: str) -> Generator[Tuple[str, str], None, None]:
for dirpath, dirnames, filenames in os.walk(d):
for f in filenames:
mt = guess_type(f)
if mt and mt.startswith('image/'):
yield os.path.join(dirpath, f), mt
def detect_support(wait_for: float = 10, silent: bool = False) -> bool:
global can_transfer_with_files
if not silent:
print(f'Checking for graphics ({wait_for}s max. wait)...', end='\r')
sys.stdout.flush()
try:
received = b''
responses: Dict[int, bool] = {}
def parse_responses() -> None:
for m in re.finditer(b'\033_Gi=([1|2]);(.+?)\033\\\\', received):
iid = m.group(1)
if iid in (b'1', b'2'):
iid_ = int(iid.decode('ascii'))
if iid_ not in responses:
responses[iid_] = m.group(2) == b'OK'
def more_needed(data: bytes) -> bool:
nonlocal received
received += data
parse_responses()
return 1 not in responses or 2 not in responses
with NamedTemporaryFile(prefix='tty-graphics-protocol') as f:
f.write(b'abcd')
f.flush()
gc = GraphicsCommand()
gc.a = 'q'
gc.s = gc.v = gc.i = 1
write_gr_cmd(gc, standard_b64encode(b'abcd'))
gc.t = 'f'
gc.i = 2
write_gr_cmd(gc, standard_b64encode(f.name.encode(fsenc)))
with TTYIO() as io:
io.recv(more_needed, timeout=wait_for)
finally:
if not silent:
sys.stdout.buffer.write(b'\033[J'), sys.stdout.flush()
can_transfer_with_files = bool(responses.get(2))
return responses.get(1, False)
class Place(NamedTuple):
width: int
height: int
left: int
top: int
def parse_place(raw: str) -> Optional[Place]:
if raw:
area, pos = raw.split('@', 1)
w, h = map(int, area.split('x'))
l, t = map(int, pos.split('x'))
return Place(w, h, l, t)
return None
help_text = (
'A cat like utility to display images in the terminal.'
' You can specify multiple image files and/or directories.'
@@ -451,174 +133,15 @@ help_text = (
usage = 'image-file-or-url-or-directory ...'
@contextlib.contextmanager
def socket_timeout(seconds: int) -> Generator[None, None, None]:
old = socket.getdefaulttimeout()
socket.setdefaulttimeout(seconds)
try:
yield
finally:
socket.setdefaulttimeout(old)
def process_single_item(
item: Union[bytes, str],
args: IcatCLIOptions,
parsed_opts: ParsedOpts,
url_pat: Optional['Pattern[str]'] = None,
maybe_dir: bool = True
) -> None:
is_tempfile = False
file_removed = False
try:
if isinstance(item, bytes):
with NamedTemporaryFile(prefix='tty-graphics-protocol-', delete=False) as tf:
tf.write(item)
item = tf.name
is_tempfile = True
if url_pat is not None and url_pat.match(item) is not None:
from urllib.request import urlretrieve
with NamedTemporaryFile(prefix='tty-graphics-protocol-', delete=False) as tf:
try:
with socket_timeout(30):
urlretrieve(item, filename=tf.name)
except Exception as e:
raise SystemExit(f'Failed to download image at URL: {item} with error: {e}')
item = tf.name
is_tempfile = True
file_removed = process(item, args, parsed_opts, is_tempfile)
elif item.lower().startswith('file://'):
from urllib.parse import urlparse
from urllib.request import url2pathname
pitem = urlparse(item)
if os.sep == '\\':
item = pitem.netloc + pitem.path
else:
item = pitem.path
item = url2pathname(item)
file_removed = process(item, args, parsed_opts, is_tempfile)
else:
if maybe_dir and os.path.isdir(item):
for (x, mt) in scan(item):
process_single_item(x, args, parsed_opts, url_pat=None, maybe_dir=False)
else:
file_removed = process(item, args, parsed_opts, is_tempfile)
finally:
if is_tempfile and not file_removed:
os.remove(item)
def main(args: List[str] = sys.argv) -> None:
global can_transfer_with_files
cli_opts, items_ = parse_args(args[1:], options_spec, usage, help_text, f'{appname} +kitten icat', result_class=IcatCLIOptions)
items: List[Union[str, bytes]] = list(items_)
if cli_opts.print_window_size:
screen_size_function.cache_clear()
with open(os.ctermid()) as tty:
try:
fd = tty.fileno()
except AttributeError:
# use default value for fd if ctermid is not available
fd = None
ss = screen_size_function(fd)()
print(f'{ss.width}x{ss.height}', end='')
raise SystemExit(0)
if not sys.stdout.isatty():
sys.stdout = open(os.ctermid(), 'w')
stdin_data = None
if cli_opts.stdin == 'yes' or (cli_opts.stdin == 'detect' and sys.stdin is not None and not sys.stdin.isatty()):
stdin_data = sys.stdin.buffer.read()
if stdin_data:
items.insert(0, stdin_data)
sys.stdin.close()
sys.stdin = open(os.ctermid())
screen_size = get_screen_size_function()
signal.signal(signal.SIGWINCH, lambda signum, frame: setattr(screen_size, 'changed', True))
if screen_size().width == 0:
if cli_opts.detect_support:
raise SystemExit(1)
raise SystemExit(
'Terminal does not support reporting screen sizes via the TIOCGWINSZ ioctl'
)
parsed_opts = ParsedOpts()
if cli_opts.place:
try:
parsed_opts.place = parse_place(cli_opts.place)
except Exception:
raise SystemExit(f'Not a valid place specification: {cli_opts.place}')
try:
parsed_opts.z_index = parse_z_index(cli_opts.z_index)
except Exception:
raise SystemExit(f'Not a valid z-index specification: {cli_opts.z_index}')
if cli_opts.background != 'none':
ra = to_color(cli_opts.background)
if ra is None:
raise SystemExit(f'Not a valid color specification: {cli_opts.background}')
parsed_opts.remove_alpha = ra.as_sharp
parsed_opts.flip = cli_opts.mirror in ('both', 'vertical')
parsed_opts.flop = cli_opts.mirror in ('both', 'horizontal')
if cli_opts.detect_support:
if not detect_support(wait_for=cli_opts.detection_timeout, silent=True):
raise SystemExit(1)
print('file' if can_transfer_with_files else 'stream', end='', file=sys.stderr)
return
if cli_opts.transfer_mode == 'detect':
if not detect_support(wait_for=cli_opts.detection_timeout, silent=cli_opts.silent):
raise SystemExit('This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it')
else:
can_transfer_with_files = cli_opts.transfer_mode == 'file'
errors = []
if cli_opts.clear:
sys.stdout.write(clear_images_on_screen(delete_data=True))
if not items:
return
if not items:
raise SystemExit('You must specify at least one file to cat')
if parsed_opts.place:
if len(items) > 1 or (isinstance(items[0], str) and os.path.isdir(items[0])):
raise SystemExit(f'The --place option can only be used with a single image, not {items}')
sys.stdout.buffer.write(b'\0337') # save cursor
url_pat = re.compile(r'(?:https?|ftp)://', flags=re.I)
def hold_if_needed(exit_code_or_msg: Union[int, str]) -> None:
if cli_opts.hold:
if isinstance(exit_code_or_msg, str):
print(exit_code_or_msg, file=sys.stderr, flush=True)
exit_code_or_msg = 1
with open(os.ctermid()) as tty, raw_mode(tty.fileno()):
tty.buffer.read(1)
raise SystemExit(exit_code_or_msg)
for item in items:
try:
process_single_item(item, cli_opts, parsed_opts, url_pat)
except NoImageMagick as e:
hold_if_needed(str(e))
except OutdatedImageMagick as e:
print(e.detailed_error, file=sys.stderr)
hold_if_needed(str(e))
except ConvertFailed as e:
hold_if_needed(str(e))
except OpenFailed as e:
errors.append(e)
if parsed_opts.place:
sys.stdout.buffer.write(b'\0338') # restore cursor
if errors:
for err in errors:
print(err, file=sys.stderr)
hold_if_needed(1 if errors else 0)
raise SystemExit()
if __name__ == '__main__':
main()
raise SystemExit('This should be run as kitten icat')
elif __name__ == '__doc__':
import sys
from kitty.cli import CompletionSpec
cd = sys.cli_docs # type: ignore
cd['usage'] = usage
cd['options'] = options_spec
cd['options'] = lambda: OPTIONS.format()
cd['help_text'] = help_text
cd['short_desc'] = 'Display images in the terminal'
cd['args_completion'] = CompletionSpec.from_string('type:file mime:image/* group:Images')

View File

@@ -8,8 +8,8 @@ from typing import Any, Callable, Dict, List, Tuple
from kitty.cli import parse_args
from kitty.cli_stub import PanelCLIOptions
from kitty.constants import appname, is_macos
from kitty.os_window_size import WindowSizeData
from kitty.fast_data_types import make_x11_window_a_dock_window
from kitty.os_window_size import WindowSizeData
OPTIONS = r'''
--lines
@@ -134,7 +134,8 @@ def main(sys_args: List[str]) -> None:
for override in args.override:
sys.argv.extend(('--override', override))
sys.argv.extend(items)
from kitty.main import main as real_main, run_app
from kitty.main import main as real_main
from kitty.main import run_app
run_app.cached_values_name = 'panel'
run_app.first_window_callback = setup_x11_window
run_app.initial_window_size_func = initial_window_size_func

View File

@@ -5,7 +5,7 @@ import re
import sys
from binascii import hexlify, unhexlify
from contextlib import suppress
from typing import Dict, Iterable, List, Type, Optional
from typing import Dict, Iterable, List, Optional, Type
from kitty.cli import parse_args
from kitty.cli_stub import QueryTerminalCLIOptions

View File

@@ -16,17 +16,12 @@ from kitty.cli import parse_args
from kitty.cli_stub import RemoteFileCLIOptions
from kitty.constants import cache_dir
from kitty.typing import BossType
from kitty.utils import (
SSHConnectionData, command_for_open, get_editor, open_cmd
)
from kitty.utils import SSHConnectionData, command_for_open, get_editor, open_cmd
from ..tui.handler import result_handler
from ..tui.operations import (
faint, raw_mode, reset_terminal, styled
)
from ..tui.operations import faint, raw_mode, reset_terminal, styled
from ..tui.utils import get_key_press
is_ssh_kitten_sentinel = '!#*&$#($ssh-kitten)(##$'
@@ -234,9 +229,9 @@ Result = Optional[str]
def main(args: List[str]) -> Result:
msg = 'Ask the user what to do with the remote file'
msg = 'Ask the user what to do with the remote file. For internal use by kitty, do not run it directly.'
try:
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty remote_file', result_class=RemoteFileCLIOptions)
cli_opts, items = parse_args(args[1:], option_text, '', msg, 'kitty +kitten remote_file', result_class=RemoteFileCLIOptions)
except SystemExit as e:
if e.code != 0:
print(e.args[0])

View File

@@ -93,8 +93,8 @@ def launch(args: List[str]) -> None:
finally:
sys.stdin = sys.__stdin__
if result is not None:
import json
import base64
import json
data = base64.b85encode(json.dumps(result).encode('utf-8'))
sys.stdout.buffer.write(b'\x1bP@kitty-kitten-result|')
sys.stdout.buffer.write(data)
@@ -155,6 +155,14 @@ def get_kitten_cli_docs(kitten: str) -> Any:
return ans
def get_kitten_wrapper_of(kitten: str) -> str:
setattr(sys, 'cli_docs', {})
run_kitten(kitten, run_name='__wrapper_of__')
ans = getattr(sys, 'cli_docs')
delattr(sys, 'cli_docs')
return ans.get('wrapper_of') or ''
def get_kitten_completer(kitten: str) -> Any:
run_kitten(kitten, run_name='__completer__')
ans = getattr(sys, 'kitten_completer', None)

View File

@@ -23,8 +23,10 @@ The title for the error message.
def real_main(args: List[str]) -> None:
msg = 'Show an error message'
cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'hints', result_class=ErrorCLIOptions)
msg = 'Show an error message. For internal use by kitty.'
cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'kitty +kitten show_error', result_class=ErrorCLIOptions)
if sys.stdin.isatty():
raise SystemExit('Input data for this kitten must be piped as JSON to STDIN')
data = json.loads(sys.stdin.buffer.read())
error_message = data['msg']
if cli_opts.title:
@@ -33,6 +35,7 @@ def real_main(args: List[str]) -> None:
print(error_message, flush=True)
if data.get('tb'):
import select
from kittens.tui.operations import init_state, set_cursor_visible
fd, original_termios = open_tty()
msg = '\n\r\x1b[1;32mPress e to see detailed traceback or any other key to exit\x1b[m'

View File

@@ -1,13 +1,9 @@
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
from kitty.key_encoding import (
ALT, CAPS_LOCK, CTRL, HYPER, META, NUM_LOCK, PRESS, RELEASE, REPEAT, SHIFT,
SUPER, KeyEvent, encode_key_event
)
from kittens.tui.handler import Handler
from kittens.tui.loop import Loop
from kitty.key_encoding import ALT, CAPS_LOCK, CTRL, HYPER, META, NUM_LOCK, PRESS, RELEASE, REPEAT, SHIFT, SUPER, KeyEvent, encode_key_event
mod_names = {
SHIFT: 'Shift',

View File

@@ -6,9 +6,9 @@ import os
import sys
from typing import List
from kittens.tui.operations import raw_mode, styled
from kitty.cli import parse_args
from kitty.cli_stub import ShowKeyCLIOptions
from kittens.tui.operations import raw_mode, styled
ctrl_keys = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'

View File

@@ -1,321 +0,0 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re
import subprocess
from typing import Callable, Dict, Iterable, Iterator, Sequence, Tuple
from kitty.complete import Completions, complete_files_and_dirs, debug
from kitty.types import run_once
from .utils import ssh_options
debug
def lines_from_file(path: str) -> Iterator[str]:
try:
f = open(os.path.expanduser(path))
except OSError:
pass
else:
yield from f
def lines_from_command(*cmd: str) -> Iterator[str]:
try:
output = subprocess.check_output(cmd).decode('utf-8')
except Exception:
return
yield from output.splitlines()
def parts_yielder(lines: Iterable[str], pfilter: Callable[[str], Iterator[str]]) -> Iterator[str]:
for line in lines:
yield from pfilter(line)
def hosts_from_config_lines(line: str) -> Iterator[str]:
parts = line.strip().split()
if len(parts) > 1 and parts[0] == 'Host':
yield parts[1]
def hosts_from_known_hosts(line: str) -> Iterator[str]:
parts = line.strip().split()
if parts:
yield re.sub(r':\d+$', '', parts[0])
def hosts_from_hosts(line: str) -> Iterator[str]:
line = line.strip()
if not line.startswith('#'):
parts = line.split()
if parts:
yield parts[0]
if len(parts) > 1:
yield parts[1]
if len(parts) > 2:
yield parts[2]
def iter_known_hosts() -> Iterator[str]:
yield from parts_yielder(lines_from_file('~/.ssh/config'), hosts_from_config_lines)
yield from parts_yielder(lines_from_file('~/.ssh/known_hosts'), hosts_from_known_hosts)
yield from parts_yielder(lines_from_file('/etc/ssh/ssh_known_hosts'), hosts_from_known_hosts)
yield from parts_yielder(lines_from_file('/etc/hosts'), hosts_from_hosts)
yield from parts_yielder(lines_from_command('getent', 'hosts'), hosts_from_hosts)
@run_once
def known_hosts() -> Tuple[str, ...]:
return tuple(sorted(filter(lambda x: '*' not in x and '[' not in x, set(iter_known_hosts()))))
# option help {{{
@run_once
def option_help_map() -> Dict[str, str]:
ans: Dict[str, str] = {}
lines = '''
-4 -- force ssh to use IPv4 addresses only
-6 -- force ssh to use IPv6 addresses only
-a -- disable forwarding of authentication agent connection
-A -- enable forwarding of the authentication agent connection
-B -- bind to specified interface before attempting to connect
-b -- specify interface to transmit on
-C -- compress data
-c -- select encryption cipher
-D -- specify a dynamic port forwarding
-E -- append log output to file instead of stderr
-e -- set escape character
-f -- go to background
-F -- specify alternate config file
-g -- allow remote hosts to connect to local forwarded ports
-G -- output configuration and exit
-i -- select identity file
-I -- specify smartcard device
-J -- connect via a jump host
-k -- disable forwarding of GSSAPI credentials
-K -- enable GSSAPI-based authentication and forwarding
-L -- specify local port forwarding
-l -- specify login name
-M -- master mode for connection sharing
-m -- specify mac algorithms
-N -- don't execute a remote command
-n -- redirect stdin from /dev/null
-O -- control an active connection multiplexing master process
-o -- specify extra options
-p -- specify port on remote host
-P -- use non privileged port
-Q -- query parameters
-q -- quiet operation
-R -- specify remote port forwarding
-s -- invoke subsystem
-S -- specify location of control socket for connection sharing
-T -- disable pseudo-tty allocation
-t -- force pseudo-tty allocation
-V -- show version number
-v -- verbose mode (multiple increase verbosity, up to 3)
-W -- forward standard input and output to host
-w -- request tunnel device forwarding
-x -- disable X11 forwarding
-X -- enable (untrusted) X11 forwarding
-Y -- enable trusted X11 forwarding
-y -- send log info via syslog instead of stderr
'''.splitlines()
for line in lines:
line = line.strip()
if line:
parts = line.split(maxsplit=2)
ans[parts[0]] = parts[2]
return ans
# }}}
# option names {{{
@run_once
def option_names() -> Tuple[str, ...]:
return tuple(filter(None, (
line.strip() for line in '''
AddKeysToAgent
AddressFamily
BatchMode
BindAddress
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
CASignatureAlgorithms
CertificateFile
ChallengeResponseAuthentication
CheckHostIP
Ciphers
ClearAllForwardings
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
DynamicForward
EscapeChar
ExitOnForwardFailure
FingerprintHash
ForwardAgent
ForwardX11
ForwardX11Timeout
ForwardX11Trusted
GatewayPorts
GlobalKnownHostsFile
GSSAPIAuthentication
GSSAPIDelegateCredentials
HashKnownHosts
Host
HostbasedAcceptedAlgorithms
HostbasedAuthentication
HostKeyAlgorithms
HostKeyAlias
Hostname
IdentitiesOnly
IdentityAgent
IdentityFile
IPQoS
KbdInteractiveAuthentication
KbdInteractiveDevices
KexAlgorithms
KnownHostsCommand
LocalCommand
LocalForward
LogLevel
MACs
Match
NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts
PasswordAuthentication
PermitLocalCommand
PermitRemoteOpen
PKCS11Provider
Port
PreferredAuthentications
ProxyCommand
ProxyJump
ProxyUseFdpass
PubkeyAcceptedAlgorithms
PubkeyAuthentication
RekeyLimit
RemoteCommand
RemoteForward
RequestTTY
SendEnv
ServerAliveInterval
ServerAliveCountMax
SetEnv
StreamLocalBindMask
StreamLocalBindUnlink
StrictHostKeyChecking
TCPKeepAlive
Tunnel
TunnelDevice
UpdateHostKeys
User
UserKnownHostsFile
VerifyHostKeyDNS
VisualHostKey
XAuthLocation
'''.splitlines())))
# }}}
def complete_choices(ans: Completions, prefix: str, title: str, choices: Iterable[str], comma_separated: bool = False) -> None:
matches: Dict[str, str] = {}
word_transforms = {}
effective_prefix = prefix
hidden_prefix = ''
if comma_separated:
effective_prefix = prefix.split(',')[-1]
hidden_prefix = ','.join(prefix.split(',')[:-1])
if hidden_prefix:
hidden_prefix += ','
for q in choices:
if q.startswith(effective_prefix):
if comma_separated:
tq = q
q = f'{hidden_prefix}{q},'
word_transforms[q] = tq
matches[q] = ''
ans.add_match_group(title, matches, trailing_space=not comma_separated, word_transforms=word_transforms)
def complete_q_choices(ans: Completions, prefix: str, title: str, key: str, comma_separated: bool) -> None:
choices = (line.strip() for line in lines_from_command('ssh', '-Q', key))
complete_choices(ans, prefix, title, choices, comma_separated)
def complete_arg(ans: Completions, option_flag: str, prefix: str = '') -> None:
options = ssh_options()
option_name = options.get(option_flag[1:])
if option_name and (option_name.endswith('file') or option_name.endswith('path')):
return complete_files_and_dirs(ans, prefix, option_name)
choices = {
'mac_spec': ('MAC algorithm', 'mac', True),
'cipher_spec': ('encryption cipher', 'cipher', True),
'query_option': ('query option', 'help', False),
}
if option_name in choices:
return complete_q_choices(ans, prefix, *choices[option_name])
if option_name == 'destination':
return complete_destination(ans, prefix)
if option_name == 'ctl_cmd':
return complete_choices(ans, prefix, 'control command', ('check', 'forward', 'cancel', 'exit'))
if option_name == 'option':
matches = (x+'=' for x in option_names() if x.startswith(prefix))
word_transforms = {x+'=': x for x in option_names()}
ans.add_match_group('configure file option', matches, trailing_space=False, word_transforms=word_transforms)
def complete_destination(ans: Completions, prefix: str = '') -> None:
result = (k for k in known_hosts() if k.startswith(prefix))
ans.add_match_group('remote host name', result)
def complete_option(ans: Completions, prefix: str = '-') -> None:
hm = option_help_map()
if len(prefix) <= 1:
result = {k: v for k, v in hm.items() if k.startswith(prefix)}
ans.add_match_group('option', result)
else:
ans.add_match_group('option', {prefix: ''})
def complete(ans: Completions, words: Sequence[str], new_word: bool) -> None:
options = ssh_options()
expecting_arg = False
seen_destination = False
types = ['' for i in range(len(words))]
for i, word in enumerate(words):
if expecting_arg:
types[i] = 'arg'
expecting_arg = False
continue
if word.startswith('-'):
types[i] = 'option'
if len(word) == 2 and options.get(word[1]):
expecting_arg = True
continue
if seen_destination:
break
types[i] = 'destination'
seen_destination = True
if new_word:
if words:
if expecting_arg:
return complete_arg(ans, words[-1])
return complete_destination(ans)
if words:
if types[-1] == 'arg' and len(words) > 1:
return complete_arg(ans, words[-2], words[-1])
if types[-1] == 'destination':
return complete_destination(ans, words[-1])
if types[-1] == 'option':
return complete_option(ans, words[-1])

View File

@@ -6,12 +6,12 @@ import fnmatch
import os
from typing import Any, Dict, Iterable, Optional
from kitty.conf.utils import (
load_config as _load_config, parse_config_base, resolve_config
)
from kitty.conf.utils import load_config as _load_config
from kitty.conf.utils import parse_config_base, resolve_config
from kitty.constants import config_dir
from .options.types import Options as SSHOptions, defaults
from .options.types import Options as SSHOptions
from .options.types import defaults
SYSTEM_CONF = '/etc/xdg/kitty/ssh.conf'
defconf = os.path.join(config_dir, 'ssh.conf')
@@ -28,12 +28,8 @@ def host_matches(mpat: str, hostname: str, username: str) -> bool:
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None, hostname: str = '!', username: str = '') -> SSHOptions:
from .options.parse import (
create_result_dict, merge_result_dicts, parse_conf_item
)
from .options.utils import (
first_seen_positions, get_per_hosts_dict, init_results_dict
)
from .options.parse import create_result_dict, merge_result_dicts, parse_conf_item
from .options.utils import first_seen_positions, get_per_hosts_dict, init_results_dict
def merge_dicts(base: Dict[str, Any], vals: Dict[str, Any]) -> Dict[str, Any]:
base_phd = get_per_hosts_dict(base)

View File

@@ -6,9 +6,7 @@ import glob
import os
import shlex
import uuid
from typing import (
Dict, Iterable, Iterator, List, NamedTuple, Optional, Sequence, Tuple
)
from typing import Dict, Iterable, Iterator, List, NamedTuple, Optional, Sequence, Tuple
from kitty.cli import parse_args
from kitty.cli_stub import CopyCLIOptions

View File

@@ -22,27 +22,16 @@ from base64 import standard_b64decode, standard_b64encode
from contextlib import contextmanager, suppress
from getpass import getuser
from select import select
from typing import (
Any, Callable, Dict, Iterator, List, NoReturn, Optional, Sequence, Set,
Tuple, Union, cast
)
from typing import Any, Callable, Dict, Iterator, List, NoReturn, Optional, Sequence, Set, Tuple, Union, cast
from kitty.constants import (
cache_dir, runtime_dir, shell_integration_dir, ssh_control_master_template,
str_version, terminfo_dir
)
from kitty.constants import cache_dir, runtime_dir, shell_integration_dir, ssh_control_master_template, str_version, terminfo_dir
from kitty.shell_integration import as_str_literal
from kitty.shm import SharedMemory
from kitty.types import run_once
from kitty.utils import (
SSHConnectionData, expandvars, resolve_abs_or_config_path,
set_echo as turn_off_echo
)
from kitty.utils import SSHConnectionData, expandvars, resolve_abs_or_config_path
from kitty.utils import set_echo as turn_off_echo
from ..tui.operations import (
RESTORE_PRIVATE_MODE_VALUES, SAVE_PRIVATE_MODE_VALUES, Mode,
restore_colors, save_colors, set_mode
)
from ..tui.operations import RESTORE_PRIVATE_MODE_VALUES, SAVE_PRIVATE_MODE_VALUES, Mode, restore_colors, save_colors, set_mode
from ..tui.utils import kitty_opts, running_in_tmux
from .config import init_config
from .copy import CopyInstruction
@@ -62,7 +51,7 @@ def read_data_from_shared_memory(shm_name: str) -> Any:
if shm.stats.st_uid != os.geteuid() or shm.stats.st_gid != os.getegid():
raise ValueError('Incorrect owner on pwfile')
mode = stat.S_IMODE(shm.stats.st_mode)
if mode != stat.S_IREAD:
if mode != stat.S_IREAD | stat.S_IWRITE:
raise ValueError('Incorrect permissions on pwfile')
return json.loads(shm.read_data_with_size())
@@ -193,6 +182,7 @@ def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str], compression: st
arcname = 'home/' + rd + '/kitty'
add_data_as_file(tf, arcname + '/version', str_version.encode('ascii'))
tf.add(shell_integration_dir + '/ssh/kitty', arcname=arcname + '/bin/kitty', filter=normalize_tarinfo)
tf.add(shell_integration_dir + '/ssh/kitten', arcname=arcname + '/bin/kitten', filter=normalize_tarinfo)
tf.add(f'{terminfo_dir}/kitty.terminfo', arcname='home/.terminfo/kitty.terminfo', filter=normalize_tarinfo)
tf.add(glob.glob(f'{terminfo_dir}/*/xterm-kitty')[0], arcname='home/.terminfo/x/xterm-kitty', filter=normalize_tarinfo)
return buf.getvalue()
@@ -623,9 +613,7 @@ def drain_potential_tty_garbage(p: 'subprocess.Popen[bytes]', data_request: str)
def change_colors(color_scheme: str) -> bool:
if not color_scheme:
return False
from kittens.themes.collection import (
NoCacheFound, load_themes, text_as_opts
)
from kittens.themes.collection import NoCacheFound, load_themes, text_as_opts
from kittens.themes.main import colors_as_escape_codes
if color_scheme.endswith('.conf'):
conf_file = resolve_abs_or_config_path(color_scheme)
@@ -754,9 +742,9 @@ def main(args: List[str]) -> None:
if __name__ == '__main__':
main(sys.argv)
elif __name__ == '__completer__':
from .completion import complete
setattr(sys, 'kitten_completer', complete)
elif __name__ == '__wrapper_of__':
cd = sys.cli_docs # type: ignore
cd['wrapper_of'] = 'ssh'
elif __name__ == '__conf__':
from .options.definition import definition
sys.options_definition = definition # type: ignore

View File

@@ -6,7 +6,6 @@
from kitty.conf.types import Definition
copy_message = '''\
Copy files and directories from local to remote hosts. The specified files are
assumed to be relative to the HOME directory and copied to the HOME on the

View File

@@ -1,5 +1,6 @@
# generated by gen-config.py DO NOT edit
# isort: skip_file
import typing
from kittens.ssh.options.utils import copy, env, hostname
from kitty.conf.utils import merge_dicts, to_bool

View File

@@ -1,5 +1,6 @@
# generated by gen-config.py DO NOT edit
# isort: skip_file
import typing
import kittens.ssh.copy

View File

@@ -79,11 +79,10 @@ def set_cwd_in_cmdline(cwd: str, argv: List[str]) -> None:
def create_shared_memory(data: Any, prefix: str) -> str:
import atexit
import json
import stat
from kitty.shm import SharedMemory
db = json.dumps(data).encode('utf-8')
with SharedMemory(size=len(db) + SharedMemory.num_bytes_for_size, mode=stat.S_IREAD, prefix=prefix) as shm:
with SharedMemory(size=len(db) + SharedMemory.num_bytes_for_size, prefix=prefix) as shm:
shm.write_data_with_size(db)
shm.flush()
atexit.register(shm.unlink)

View File

@@ -8,17 +8,18 @@ import os
import re
import shutil
import signal
import sys
import tempfile
import zipfile
from contextlib import suppress
from typing import Any, Callable, Dict, Iterator, Match, Optional, Tuple, Union, Type
from typing import Any, Callable, Dict, Iterator, Match, Optional, Tuple, Type, Union
from urllib.error import HTTPError
from urllib.request import Request, urlopen
from kitty.config import atomic_save, parse_config
from kitty.constants import cache_dir, config_dir
from kitty.options.types import Options as KittyOptions
from kitty.fast_data_types import Color
from kitty.options.types import Options as KittyOptions
from kitty.utils import reload_conf_in_all_kitties
from ..choose.match import match
@@ -647,3 +648,13 @@ def load_themes(cache_age: float = 1., ignore_no_cache: bool = False) -> Themes:
ans.load_from_dir(os.path.join(config_dir, 'themes'))
ans.index_map = tuple(ans.themes)
return ans
def print_theme_names() -> None:
found = False
for theme in load_themes(cache_age=-1, ignore_no_cache=True):
print(theme.name)
found = True
if not found:
print('Default')
sys.stdout.flush()

View File

@@ -7,16 +7,14 @@ import sys
import traceback
from enum import Enum, auto
from gettext import gettext as _
from typing import (
Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
)
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union
from kitty.cli import create_default_opts, parse_args
from kitty.cli import CompletionSpec, create_default_opts, parse_args
from kitty.cli_stub import ThemesCLIOptions
from kitty.config import cached_values_for
from kitty.options.types import Options as KittyOptions
from kitty.constants import config_dir
from kitty.fast_data_types import truncate_point_for_length, wcswidth
from kitty.options.types import Options as KittyOptions
from kitty.rgb import color_as_sharp, color_from_int
from kitty.typing import KeyEventType
from kitty.utils import ScreenSize
@@ -180,7 +178,7 @@ class ThemesHandler(Handler):
self.cmd.save_colors()
self.cmd.set_line_wrapping(False)
self.cmd.set_window_title('Choose a theme for kitty')
self.cmd.set_cursor_shape('bar')
self.cmd.set_cursor_shape('beam')
def initialize(self) -> None:
self.init_terminal_state()
@@ -235,8 +233,11 @@ class ThemesHandler(Handler):
self.redraw_after_category_change()
def fetch() -> None:
from urllib.error import URLError
try:
themes: Union[Themes, str] = load_themes(self.cli_opts.cache_age)
except URLError as e:
themes = f'Could not download themes, check your internet connection. Error: {e}'
except Exception:
themes = format_traceback('Failed to download themes')
self.asyncio_loop.call_soon_threadsafe(fetching_done, themes)
@@ -553,7 +554,9 @@ instead of changing kitty.conf.
default=kitty.conf
The name or path to the config file to edit. Relative paths are interpreted
with respect to the kitty config directory. By default the kitty config file,
kitty.conf is edited.
kitty.conf is edited. This is most useful if you add :code:`include themes.conf`
to your kitty.conf and then have the kitten operate only on :file:`themes.conf`,
allowing :code:`kitty.conf` to remain unchanged.
'''.format
@@ -616,3 +619,4 @@ elif __name__ == '__doc__':
cd['usage'] = usage
cd['options'] = OPTIONS
cd['help_text'] = help_text
cd['args_completion'] = CompletionSpec.from_string('type:special group:complete_themes')

View File

@@ -5,10 +5,7 @@ import os
import tempfile
from typing import IO, TYPE_CHECKING, Iterator, Union
from .rsync import (
IO_BUFFER_SIZE, RsyncError, begin_create_delta, begin_create_signature,
begin_load_signature, begin_patch, build_hash_table, iter_job
)
from .rsync import IO_BUFFER_SIZE, RsyncError, begin_create_delta, begin_create_signature, begin_load_signature, begin_patch, build_hash_table, iter_job
if TYPE_CHECKING:
from .rsync import JobCapsule, SignatureCapsule

View File

@@ -12,7 +12,6 @@ from kitty.cli_stub import TransferCLIOptions
from .receive import receive_main
from .send import send_main
usage = 'source_files_or_directories destination_path'
help_text = 'Transfer files over the TTY device'

View File

@@ -14,9 +14,16 @@ from typing import IO, Deque, Dict, Iterator, List, Optional, Union
from kitty.cli_stub import TransferCLIOptions
from kitty.fast_data_types import FILE_TRANSFER_CODE, wcswidth
from kitty.file_transmission import (
Action, Compression, FileTransmissionCommand, FileType,
IdentityDecompressor, NameReprEnum, TransmissionType, ZlibDecompressor,
encode_bypass, split_for_transfer
Action,
Compression,
FileTransmissionCommand,
FileType,
IdentityDecompressor,
NameReprEnum,
TransmissionType,
ZlibDecompressor,
encode_bypass,
split_for_transfer,
)
from kitty.typing import KeyEventType, ScreenSize
from kitty.utils import sanitize_control_codes
@@ -28,10 +35,7 @@ from ..tui.spinners import Spinner
from ..tui.utils import human_size
from .librsync import PatchFile, signature_of_file
from .send import Transfer
from .utils import (
expand_home, print_rsync_stats, random_id, render_progress_in_width,
safe_divide, should_be_compressed
)
from .utils import expand_home, print_rsync_stats, random_id, render_progress_in_width, safe_divide, should_be_compressed
debug
file_counter = count(1)

View File

@@ -9,17 +9,11 @@ from collections import deque
from enum import auto
from itertools import count
from time import monotonic
from typing import (
IO, Callable, Deque, Dict, Iterable, Iterator, List, Optional, Sequence,
Set, Tuple, Union
)
from typing import IO, Callable, Deque, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Union
from kitty.cli_stub import TransferCLIOptions
from kitty.fast_data_types import FILE_TRANSFER_CODE, wcswidth
from kitty.file_transmission import (
Action, Compression, FileTransmissionCommand, FileType, NameReprEnum,
TransmissionType, encode_bypass, split_for_transfer
)
from kitty.file_transmission import Action, Compression, FileTransmissionCommand, FileType, NameReprEnum, TransmissionType, encode_bypass, split_for_transfer
from kitty.typing import KeyEventType, ScreenSize
from kitty.utils import sanitize_control_codes
@@ -30,9 +24,16 @@ from ..tui.spinners import Spinner
from ..tui.utils import human_size
from .librsync import LoadSignature, delta_for_file
from .utils import (
IdentityCompressor, ZlibCompressor, abspath, expand_home, home_path,
print_rsync_stats, random_id, render_progress_in_width, safe_divide,
should_be_compressed
IdentityCompressor,
ZlibCompressor,
abspath,
expand_home,
home_path,
print_rsync_stats,
random_id,
render_progress_in_width,
safe_divide,
should_be_compressed,
)
debug

View File

@@ -6,16 +6,21 @@ from collections import deque
from contextlib import suppress
from time import monotonic
from types import TracebackType
from typing import (
TYPE_CHECKING, Any, Callable, ContextManager, Deque, Dict, NamedTuple,
Optional, Sequence, Type, Union, cast
)
from typing import TYPE_CHECKING, Any, Callable, ContextManager, Deque, Dict, NamedTuple, Optional, Sequence, Type, Union, cast
from kitty.types import DecoratedFunc, ParsedShortcut
from kitty.typing import (
AbstractEventLoop, BossType, Debug, ImageManagerType, KeyActionType,
KeyEventType, LoopType, MouseButton, MouseEvent, ScreenSize,
TermManagerType
AbstractEventLoop,
BossType,
Debug,
ImageManagerType,
KeyActionType,
KeyEventType,
LoopType,
MouseButton,
MouseEvent,
ScreenSize,
TermManagerType,
)
from .operations import MouseTracking, pending_update

View File

@@ -9,17 +9,11 @@ from collections import defaultdict, deque
from contextlib import suppress
from enum import IntEnum
from itertools import count
from typing import (
Any, Callable, ClassVar, DefaultDict, Deque, Dict, Generic, Iterator, List,
Optional, Sequence, Tuple, Type, TypeVar, Union, cast
)
from typing import Any, Callable, ClassVar, DefaultDict, Deque, Dict, Generic, Iterator, List, Optional, Sequence, Tuple, Type, TypeVar, Union, cast
from kitty.conf.utils import positive_float, positive_int
from kitty.fast_data_types import create_canvas
from kitty.typing import (
GRT_C, CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t,
HandlerType
)
from kitty.typing import GRT_C, CompletedProcess, GRT_a, GRT_d, GRT_f, GRT_m, GRT_o, GRT_t, HandlerType
from kitty.utils import ScreenSize, fit_image, which
from .operations import cursor

View File

@@ -6,9 +6,7 @@ from typing import Callable, Tuple
from kitty.fast_data_types import truncate_point_for_length, wcswidth
from kitty.key_encoding import EventType, KeyEvent
from .operations import (
RESTORE_CURSOR, SAVE_CURSOR, move_cursor_by, set_cursor_shape
)
from .operations import RESTORE_CURSOR, SAVE_CURSOR, move_cursor_by, set_cursor_shape
class LineEdit:
@@ -53,7 +51,7 @@ class LineEdit:
write('\r')
if cursor_pos:
write(move_cursor_by(cursor_pos, 'right'))
write(set_cursor_shape('bar'))
write(set_cursor_shape('beam'))
def add_text(self, text: str) -> None:
if self.current_input:

View File

@@ -16,17 +16,10 @@ from functools import partial
from typing import Any, Callable, Dict, Generator, List, NamedTuple, Optional
from kitty.constants import is_macos
from kitty.fast_data_types import (
FILE_TRANSFER_CODE, close_tty, normal_tty, open_tty,
parse_input_from_terminal, raw_tty
)
from kitty.key_encoding import (
ALT, CTRL, SHIFT, backspace_key, decode_key_event, enter_key
)
from kitty.fast_data_types import FILE_TRANSFER_CODE, close_tty, normal_tty, open_tty, parse_input_from_terminal, raw_tty
from kitty.key_encoding import ALT, CTRL, SHIFT, backspace_key, decode_key_event, enter_key
from kitty.typing import ImageManagerType, KeyEventType, Protocol
from kitty.utils import (
ScreenSize, ScreenSizeGetter, screen_size_function, write_all
)
from kitty.utils import ScreenSize, ScreenSizeGetter, screen_size_function, write_all
from .handler import Handler
from .operations import MouseTracking, init_state, reset_state

View File

@@ -1,17 +1,16 @@
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import os
import sys
from contextlib import contextmanager
from enum import Enum, auto
from functools import wraps
from typing import IO, Any, Callable, Dict, Generator, Optional, TypeVar, Union
from typing import Any, Callable, Dict, Generator, Optional, TypeVar, Union
from kitty.fast_data_types import Color
from kitty.rgb import color_as_sharp, to_color
from kitty.typing import (
GraphicsCommandType, HandlerType, ScreenSize, UnderlineLiteral
)
from kitty.typing import GraphicsCommandType, HandlerType, ScreenSize, UnderlineLiteral
from .operations_stub import CMD
@@ -141,7 +140,7 @@ def move_cursor_by(amt: int, direction: str) -> str:
@cmd
def set_cursor_shape(shape: str = 'block', blink: bool = True) -> str:
val = {'block': 1, 'underline': 3, 'bar': 5}.get(shape, 1)
val = {'block': 1, 'underline': 3, 'beam': 5}.get(shape, 1)
if not blink:
val += 1
return f'\033[{val} q'
@@ -350,13 +349,13 @@ def cursor(write: Callable[[str], None]) -> Generator[None, None, None]:
@contextmanager
def alternate_screen(f: Optional[IO[str]] = None) -> Generator[None, None, None]:
f = f or sys.stdout
print(set_mode(Mode.ALTERNATE_SCREEN), end='', file=f)
try:
yield
finally:
print(reset_mode(Mode.ALTERNATE_SCREEN), end='', file=f)
def alternate_screen() -> Generator[None, None, None]:
with open(os.ctermid(), 'w') as f:
print(set_mode(Mode.ALTERNATE_SCREEN), end='', file=f, flush=True)
try:
yield
finally:
print(reset_mode(Mode.ALTERNATE_SCREEN), end='', file=f, flush=True)
@contextmanager

View File

@@ -2,7 +2,7 @@
# License: GPLv3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
from .operations import styled, repeat
from .operations import repeat, styled
def render_progress_bar(frac: float, width: int = 80) -> str:

View File

@@ -7,10 +7,7 @@ import sys
from contextlib import suppress
from functools import lru_cache
from gettext import gettext as _
from typing import (
Any, Dict, FrozenSet, Generator, Iterable, List, Optional, Sequence, Tuple,
Union
)
from typing import Any, Dict, FrozenSet, Generator, Iterable, List, Optional, Sequence, Tuple, Union
from kitty.cli import parse_args
from kitty.cli_stub import UnicodeCLIOptions
@@ -24,10 +21,7 @@ from kitty.utils import ScreenSize, get_editor
from ..tui.handler import Handler, result_handler
from ..tui.line_edit import LineEdit
from ..tui.loop import Loop
from ..tui.operations import (
clear_screen, colored, cursor, faint, set_line_wrapping, set_window_title,
sgr, styled
)
from ..tui.operations import clear_screen, colored, cursor, faint, set_line_wrapping, set_window_title, sgr, styled
from ..tui.utils import report_unhandled_error
HEX, NAME, EMOTICONS, FAVORITES = 'HEX', 'NAME', 'EMOTICONS', 'FAVORITES'
@@ -418,7 +412,7 @@ class UnicodeInput(Handler):
if self.mode is HEX:
writeln(faint(_('Type {} followed by the index for the recent entries below').format(INDEX_CHAR)))
elif self.mode is NAME:
writeln(faint(_('Use Tab or the arrow keys to choose a character from below')))
writeln(faint(_('Use Tab or arrow keys to choose a character. Type space and {} to select by index').format(INDEX_CHAR)))
elif self.mode is FAVORITES:
writeln(faint(_('Press F12 to edit the list of favorites')))
self.table_at = y

View File

@@ -1,5 +1,6 @@
// unicode data, built from the unicode standard on: 2022-09-29
// see gen-wcwidth.py
// Unicode data, built from the Unicode Standard 15.0.0
// Code generated by gen-wcwidth.py, DO NOT EDIT.
#pragma once
#include "data-types.h"

Some files were not shown because too many files have changed in this diff Show More