Compare commits

...

208 Commits

Author SHA1 Message Date
Kovid Goyal
cc4f1c0a24 version 0.25.1 2022-05-26 07:59:25 +05:30
Kovid Goyal
3eb5320e29 Add tpix to list of programs that speak the graphics protocol 2022-05-25 12:27:38 +05:30
Kovid Goyal
4f63cff1a4 Make _run_kitten public API 2022-05-25 07:14:18 +05:30
Kovid Goyal
8381171c8d Forgot trailing newline 2022-05-24 06:54:53 +05:30
Kovid Goyal
1b2d54d97a Output a warning when libwayland-cursor returns incorrectly sized cursor images 2022-05-23 12:50:47 +05:30
Kovid Goyal
e7da874b82 GNOME: Workaround for GNOME's text input system going into an infinite loop if cursor position is updated in response to a done event
Fixes #5105
2022-05-23 10:36:58 +05:30
Kovid Goyal
ea8bed2a71 Fix #5113 2022-05-20 20:45:08 +05:30
Kovid Goyal
c747e681a2 Merge branch 'patch-1' of https://github.com/jack1142/kitty 2022-05-20 20:42:11 +05:30
Jakub Kuczys
a9a9ec80b5 Support the short pretty flag (-p) in hyperlinked_grep kitten 2022-05-20 10:57:42 +02:00
Kovid Goyal
eb84990f5a Fix #5110 2022-05-19 09:55:12 +05:30
Kovid Goyal
1938ba3108 Add changelog entry for previous PR 2022-05-18 20:04:09 +05:30
Kovid Goyal
0eee2db199 Merge branch 'add-option-select_by_word_characters_forward' of https://github.com/kgraefe/kitty 2022-05-18 20:02:11 +05:30
Kovid Goyal
bba1455e28 Dont import all of the ssh kitten just to detect commandlines 2022-05-18 15:58:06 +05:30
Konrad Gräfe
8c41cc8d3e Add option select_by_word_characters_forward
This adds an option to select separate characters for forward and
backward word extension on double click. If it is empty the old behavior
is preserved. This is the default.

If it is not empty, select_by_word_characters_forward will be used for
extending the selection in forward direction (right) and
select_by_word_characters will be used for extending in backward
direction (left).

Signed-off-by: Konrad Gräfe <kgraefe@paktolos.net>
2022-05-16 11:09:36 +02:00
Kovid Goyal
5efcb35cfb Only integrate with ssh kitten if shared connections are enabled for that host 2022-05-14 10:37:05 +05:30
Kovid Goyal
1b4cf1fea7 Remote file kitten: Integrate with the ssh kitten 2022-05-14 10:31:18 +05:30
Kovid Goyal
d3656bf7e9 Linux: Load libfontconfig at runtime to allow the binaries to work for running kittens on servers without FontConfig 2022-05-13 19:56:19 +05:30
Kovid Goyal
aaffec1cbc Better error message 2022-05-13 19:25:37 +05:30
Kovid Goyal
ed9391d4d6 Add a note explaining why fontconfig is not bundled 2022-05-13 17:45:16 +05:30
Kovid Goyal
58333f260b Fix spurious error print in test 2022-05-13 17:42:00 +05:30
Kovid Goyal
cf8ccabad9 Fix deleting images by row not calculating image bounds correctly
Fixes #5081
2022-05-13 09:51:25 +05:30
Kovid Goyal
600c595fdf Fix reloading of config not working when kitty.conf does not exist when kitty is launched
Fixes #5071
2022-05-08 20:57:23 +05:30
Kovid Goyal
2427d2d9da Workaround Apple's "hardening" breaking the platform module
Fix #5065
Fix #5051
2022-05-07 20:43:10 +05:30
Kovid Goyal
4ca70bfa26 ... 2022-05-04 13:21:17 +05:30
Kovid Goyal
4e8eb2f7f0 Merge branch 'rc-match' of https://github.com/page-down/kitty 2022-05-01 21:23:58 +05:30
pagedown
b6cf4bc78f ... 2022-05-01 23:27:33 +08:00
pagedown
622cd5531a Raise an exception when not in broadcast and no match for send-text
send-text still won't return an error code when there is no match,
since no_response is True by default.
2022-05-01 23:05:44 +08:00
pagedown
ec35b0cc7c Fix remote command --match=all returns empty 2022-05-01 23:05:22 +08:00
pagedown
0719c7f8bb DRYer: Use window matching function in remote commands 2022-05-01 23:04:50 +08:00
Kovid Goyal
bb7e4039e8 Merge branch 'rc-err' of https://github.com/page-down/kitty 2022-05-01 07:11:21 +05:30
pagedown
a0559e506b Show error message when remote command arguments are invalid 2022-04-30 22:01:58 +08:00
Kovid Goyal
4ce4176bbe cleanup previous PR 2022-04-30 15:03:27 +05:30
Kovid Goyal
99409f0a8b Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-30 14:41:12 +05:30
pagedown
13303416b8 Docs: Improve the documentations
Add more text roles and links.
Fix typos.
Adjust the default shortcut order in overview.
Notes on the impact of kitty-open.desktop on the default open apps.
Document KITTY_DEVELOP_FROM in glossary.
Add Python type hints to the watcher example.
Mention clone-in-kitty in launch --copy-env.
Fix remote control ls example does not work, by escaping the backslash.
2022-04-30 17:07:36 +08:00
Kovid Goyal
9811d677e5 query terminal kitten: Return fast when run in non-kitty terminals 2022-04-30 14:25:39 +05:30
pagedown
b9fd039668 Docs: Document the env vars set by kitty for auto shell integration 2022-04-30 16:54:53 +08:00
pagedown
6c1f20bb27 Docs: Mention close_shared_ssh_connections in ssh kitten config docs 2022-04-30 16:54:46 +08:00
pagedown
2b58316c64 ... 2022-04-30 16:54:41 +08:00
Kovid Goyal
f2df629634 ... 2022-04-30 09:38:08 +05:30
Kovid Goyal
8f46505a50 Header to print stack traces in C 2022-04-30 09:28:05 +05:30
Kovid Goyal
c48bf4fd85 Output debug lines for when kitty sets the pointer in Wayland 2022-04-30 09:13:08 +05:30
Kovid Goyal
8c67f5aea8 Merge branch 'fix-gen-conf' of https://github.com/page-down/kitty 2022-04-30 07:35:15 +05:30
pagedown
76f84e32c4 Fix the generated sample kitty.conf containing invalid options 2022-04-30 02:23:33 +08:00
Kovid Goyal
4a7125ec92 ssh kitten: Suppress error prints about invalid items in kitty.conf
Fixes #4985
2022-04-29 20:39:32 +05:30
Kovid Goyal
92c3af6a92 Allow using --match=all in all rc commands 2022-04-29 17:17:07 +05:30
Kovid Goyal
443f36ebc7 Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-29 07:11:40 +05:30
pagedown
17632dea3c Docs: Improve remote control command documentation
Improve the --match option description.
Add more text roles and links.
Fix typos.
2022-04-29 01:31:11 +08:00
pagedown
bb78dc5ccb Docs: Fix the help text of query_terminal and other minor tweaks
Use --match-tab in broadcast kitten example.
2022-04-29 01:30:45 +08:00
Kovid Goyal
2737cb7dd0 Fix #5026 2022-04-28 22:12:43 +05:30
Kovid Goyal
08b2ce444f Also dont apply umask when extracting bootstrap data 2022-04-28 17:28:40 +05:30
Kovid Goyal
289028b468 Prevent umask from interfering with tar file extraction
Fixes #5025
2022-04-28 17:21:34 +05:30
Kovid Goyal
2b3be147e6 Allow three combining chars per cell
Makes use of otherwise wasted padding in the CPUCell struct
2022-04-28 09:45:34 +05:30
Kovid Goyal
1a2d9c6fba Fix a couple of issues highlighted by updated mypy 2022-04-28 07:03:35 +05:30
Kovid Goyal
af15b0313a Ensure there are no duplicate watchers for send-text sessions 2022-04-27 22:17:09 +05:30
Kovid Goyal
b080296326 Remove unused code 2022-04-27 21:25:39 +05:30
Kovid Goyal
516e0e8bb3 broadcast kitten: Keep the ghost cursors in target windows as long as broadcast window has focus 2022-04-27 21:24:18 +05:30
Kovid Goyal
57e23bd4e3 Handle zero blink time correctly 2022-04-27 20:37:23 +05:30
Kovid Goyal
59534d620e Use cursor blink interval as TIMEOUT_FOR_SESSION 2022-04-27 20:31:16 +05:30
Kovid Goyal
068b7e8d63 remove unused adjust_line_height() function 2022-04-27 20:21:36 +05:30
Kovid Goyal
2c1edb9611 Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-27 20:18:39 +05:30
pagedown
510022c3c1 Docs: Improve the documentation for kittens
Add more text roles and links.
Add an example that broadcasts only to other windows in the current tab.
Initial capitalization of the key names in the kbd text role.
Add Python type hints for custom kittens.
Note about hyperlink support for ls on macOS.
Add description text for show_key.
2022-04-27 16:14:54 +08:00
Kovid Goyal
627c79ffbb Show detailed traceback when using show_error() 2022-04-26 13:58:57 +05:30
Kovid Goyal
e80cd36237 Show traceback on stderr for action failures 2022-04-26 11:58:17 +05:30
Kovid Goyal
92ebada9a6 ... 2022-04-26 11:15:45 +05:30
Kovid Goyal
462ae3bb58 ... 2022-04-26 11:15:33 +05:30
Kovid Goyal
6d6d9cc26b macOS: Add the macos_colorspace option to control what color space colors are rendered in
Fixed #4686
2022-04-26 11:14:01 +05:30
Kovid Goyal
a36d5dcde1 GLFW API for changing colorspace of windows on cocoa 2022-04-26 10:56:34 +05:30
Kovid Goyal
f9f6f98527 Note that neovim is also getting support for the kitty keyboard protocol 2022-04-26 08:39:44 +05:30
Kovid Goyal
ee94114eb2 Fix #5016 2022-04-26 08:20:24 +05:30
Kovid Goyal
8e98fcf2f6 Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-25 14:16:16 +05:30
pagedown
c4710bf9cb Docs: Add text to the ref text role and minor tweaks
The text will be used when generating the commented configuration file.
Use inline literal to quote codes with spaces, as the `code` text role
will be removed when the commented configuration is generated, making it
indistinguishable from normal text.
2022-04-25 15:36:57 +08:00
pagedown
97a568a405 Docs: Improve the FAQ
Add more text roles and links.
Document `PATH` in the glossary.
2022-04-25 15:36:51 +08:00
pagedown
7bace19aed clone-in-kitty: Skip more SSH env vars to use the correct values 2022-04-25 15:36:43 +08:00
pagedown
7282f1f684 Docs: Improve ssh kitten documentation
Add more text roles.
Put the env example at the end.
The alias syntax of fish and bash requires quotation marks.
Document `SSH_ASKPASS` in the glossary.
2022-04-25 15:36:37 +08:00
Kovid Goyal
9edb772a81 Merge branch 'fix-launch-cwd-oldest' of https://github.com/rafikdraoui/kitty 2022-04-24 22:04:05 +05:30
Rafik Draoui
d123b6c377 Fix launch --cwd=oldest 2022-04-24 13:19:22 -03:00
Kovid Goyal
c9ba3695d3 ... 2022-04-24 15:50:02 +05:30
Kovid Goyal
0ee970b418 --hold is not suitable for replay commands as it outputs to the terminal 2022-04-24 15:37:20 +05:30
Kovid Goyal
8239cb1b5a Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-24 15:36:35 +05:30
pagedown
97caa073b0 Docs: Improvements to the configuration documentation
Slightly adjust and simplify the config option descriptions.
Add more text roles.
Initial capitalized key names.
Change some examples to better demonstrate configurations.
Fix listen_on description.
Also document cmd+c and cmd+v.
Fix doc text role links in commented out configuration file.
2022-04-24 17:32:49 +08:00
pagedown
45bbe17559 Docs: Minor improvements to the kitty cli help documentation
Add some text roles.
Use `kitty --hold`.
Use `appname` and `conf_name`.
`appname` is also applied to the system-wide configuration path.
2022-04-24 17:18:55 +08:00
pagedown
288d16f7be Docs: Minor tweaks to the help documentation of hints kitten 2022-04-24 17:18:45 +08:00
pagedown
ecb60b313e Docs: Improve clone-in-kitty documentation and fix LANG descriptions
Reduce duplicate `launch`.
Add links to python venv and conda.
Adjust the order of env vars, `.._CODE` takes precedence over `.._PATH`.
Add clone-in-kitty env vars to glossary.
Correct the description of the LANG env var.
2022-04-24 17:18:31 +08:00
Kovid Goyal
cf2a20e4ea Merge branch 'fix-f-string' of https://github.com/page-down/kitty 2022-04-24 08:03:51 +05:30
pagedown
bc4f40fea7 ... 2022-04-24 09:34:22 +08:00
Kovid Goyal
102097da5a DRYer 2022-04-23 12:51:02 +05:30
Kovid Goyal
0e3528df14 Merge branch 'feat-macos-open-website' of https://github.com/page-down/kitty 2022-04-23 12:49:21 +05:30
Kovid Goyal
214631c2dd Sort frozenset literals in generated options class definition 2022-04-23 11:23:21 +05:30
pagedown
e919857dfc macOS: Make the global menu shortcut to open kitty website configurable
This allows remapping the key combination shift+cmd+/
2022-04-23 13:22:27 +08:00
pagedown
a5bd1dcb08 Add a new mappable action open_url 2022-04-23 13:17:28 +08:00
Kovid Goyal
37cdaea9ed Also save command history before cloning in bash 2022-04-22 23:40:59 +05:30
Kovid Goyal
6bbaf5f1cf zsh cloning: save history so that it is up-to-date in cloned shell 2022-04-22 23:34:34 +05:30
Kovid Goyal
8808a252ae Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-22 13:29:24 +05:30
pagedown
5f1376b9a0 ... 2022-04-22 15:02:23 +08:00
Kovid Goyal
efa873bf50 DRYer 2022-04-22 10:53:25 +05:30
Kovid Goyal
714461de76 Also ensure oldest cwd request type is honored by modify_argv 2022-04-22 08:40:18 +05:30
Kovid Goyal
b753cf6879 Forgot to implement at_prompt use of reported cwd in modify_argv 2022-04-22 08:25:46 +05:30
Kovid Goyal
27010d0446 Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-21 15:24:18 +05:30
Kovid Goyal
bdc039fbf5 Fix docstring 2022-04-21 14:51:23 +05:30
pagedown
72f92f3174 Docs: Mention again that kitty.conf will be created if not present 2022-04-21 16:45:12 +08:00
Kovid Goyal
8fcd5e40d4 Proper fix for reporting button in drag events to children 2022-04-21 11:41:57 +05:30
Kovid Goyal
b76319b7e8 Update changelog 2022-04-21 11:34:18 +05:30
Kovid Goyal
feeb8f28c4 Fix #4993 2022-04-21 11:00:34 +05:30
Kovid Goyal
55b21b741e Fix a regression in the previous release that caused mouse move events to be incorrectly reported as drag events even when a button is not pressed
Fixes #4992

Will need to investigate a different fix for #4925. xterm does report
the button press that caused the drag to start with move events, so we
will have to track that to match its behavior as glfw does not track it
for us.
2022-04-21 07:53:37 +05:30
Kovid Goyal
6941884221 ... 2022-04-20 13:36:26 +05:30
Kovid Goyal
6174c2008f ... 2022-04-20 10:10:05 +05:30
Kovid Goyal
1a32e79470 ... 2022-04-19 21:14:34 +05:30
Kovid Goyal
dd032db89c Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-19 21:07:03 +05:30
pagedown
f70e0e216c Docs: Show copy button for installation command snippets 2022-04-19 23:28:51 +08:00
Kovid Goyal
51362706d7 Fix closing a tab incorrectly storing the tab to its right in the active tab history 2022-04-19 17:44:01 +05:30
Kovid Goyal
b2c317ebc6 ... 2022-04-19 17:38:16 +05:30
Kovid Goyal
90acbd0dd5 Add a note about ssh kitten colors to FAQ 2022-04-19 15:21:05 +05:30
Kovid Goyal
402fac3edf ... 2022-04-19 10:53:18 +05:30
Kovid Goyal
c4c62c1505 When using --keep-focus ensure active history list is not affected
Fixes #4987
2022-04-18 20:23:15 +05:30
Kovid Goyal
b569c01b49 Fix #4986 2022-04-18 17:04:05 +05:30
Kovid Goyal
c0d9b6e979 Merge branch 'docs' of https://github.com/page-down/kitty 2022-04-18 12:41:05 +05:30
pagedown
b94afbba13 ... 2022-04-18 14:51:15 +08:00
Kovid Goyal
1994c17c75 Note on how clone-in-kitty works 2022-04-18 12:08:32 +05:30
Kovid Goyal
f88a4fe986 ... 2022-04-18 11:13:16 +05:30
Kovid Goyal
25616aaa7b Merge branch 'clone-in-kitty' of https://github.com/page-down/kitty 2022-04-18 10:57:55 +05:30
pagedown
19fdcec358 ... 2022-04-18 11:54:14 +08:00
pagedown
45eb4a0760 clone-in-kitty: Remove duplicate PATH entries in fish implementation 2022-04-18 11:46:29 +08:00
pagedown
9e026983e6 clone-in-kitty: Remove CONDA_PREFIX_* env vars 2022-04-18 11:42:22 +08:00
Kovid Goyal
be0a524e23 Yet another try to get zsh to de-dup $PATH 2022-04-18 07:40:37 +05:30
Kovid Goyal
339af1b4b2 Add more send_text examples 2022-04-17 22:48:03 +05:30
Kovid Goyal
31fda568e4 typeset -U both path and PATH 2022-04-17 21:27:08 +05:30
Kovid Goyal
3efbccc850 ... 2022-04-17 20:56:24 +05:30
Kovid Goyal
93c23f99cb conda activate now works under fish so use it 2022-04-17 20:55:53 +05:30
Kovid Goyal
6590d0690e Document venv and sourcing behavior of clone-in-kitty 2022-04-17 19:51:27 +05:30
Kovid Goyal
230a9f4678 Implement option to control clone sourcing strategies 2022-04-17 19:39:32 +05:30
Kovid Goyal
f2189b3e70 only pass VIRTUAL_ENV if it is currently active 2022-04-17 15:43:57 +05:30
Kovid Goyal
0ee5712e00 Start work on option to control sourcing strategies 2022-04-17 15:30:57 +05:30
Kovid Goyal
f9cad2c4ea Add a note about show__key limitations 2022-04-17 08:45:27 +05:30
Kovid Goyal
4372cf2893 ... 2022-04-17 08:43:23 +05:30
Kovid Goyal
34c18bacd8 Free up memory used to store copy of child env block 2022-04-17 08:35:55 +05:30
Kovid Goyal
3af11e92d6 Ensure the clone launch env var is not set accidentally 2022-04-17 08:29:47 +05:30
Kovid Goyal
74d5f2c259 Dont allow inappropriate types for cloning 2022-04-17 08:19:01 +05:30
Kovid Goyal
291f9e9a5e Make cloning safer
Now env vars are set after shell rc files are sourced. And the clone
request cannot specify the cmdline to execute.
2022-04-17 07:49:58 +05:30
Kovid Goyal
38e1d32065 Actually implement allow_cloning 2022-04-16 22:40:05 +05:30
Kovid Goyal
b45fedd794 Infrastructure for serializing env blocks 2022-04-16 22:16:20 +05:30
Kovid Goyal
df9b13fb74 Ask for confirmation before doing a clone by default 2022-04-16 20:04:26 +05:30
Kovid Goyal
53788c4c89 Get conda working with fish 2022-04-16 15:16:53 +05:30
Kovid Goyal
831043b773 Implement venv detection for fish 2022-04-16 14:45:02 +05:30
Kovid Goyal
1daf745d74 Add explicit support for python and conda venvs to clone-in-kitty
Still needs to be implemented for fish
2022-04-16 13:15:10 +05:30
Kovid Goyal
d6c5b40ead ... 2022-04-16 09:26:53 +05:30
Kovid Goyal
57ea524464 Merge branch 'clone-in-kitty' of https://github.com/page-down/kitty 2022-04-15 20:27:36 +05:30
pagedown
e19ce6cce6 clone-in-kitty: Skip some user-related environment variables 2022-04-15 22:47:57 +08:00
Kovid Goyal
8d4f6681e8 Merge branch 'clone-in-kitty' of https://github.com/page-down/kitty 2022-04-15 19:49:33 +05:30
pagedown
9c855a8377 Skip environment variables such as SSH_TTY when using clone-in-kitty 2022-04-15 19:43:40 +08:00
Kovid Goyal
716813e38a Proper fix for macOS argv[0] 2022-04-15 15:23:45 +05:30
Kovid Goyal
e5322cdc52 Fix clone-in-kitty --env not working over ssh 2022-04-15 15:20:38 +05:30
Kovid Goyal
b5701691c6 Dont clone prompt related env variables
These really shouldnt be exported but people often do
2022-04-15 15:18:43 +05:30
Kovid Goyal
aab9482e31 ... 2022-04-15 15:01:13 +05:30
Kovid Goyal
775584b5a5 Use literal quoting for env vars sent over ssh by clone 2022-04-15 14:34:21 +05:30
Kovid Goyal
25f022cc14 Ensure copy_env is False 2022-04-15 14:04:52 +05:30
Kovid Goyal
981ad88309 Allow nuking expandvars globally 2022-04-15 13:58:01 +05:30
Kovid Goyal
e71b9091a3 Dont rely on env -0 for bash either 2022-04-15 13:33:32 +05:30
Kovid Goyal
bde468594e ssh kitten: handle newlines in env vars 2022-04-15 12:49:35 +05:30
Kovid Goyal
0fcfe104e3 Handle argv[0] being buggered on macOS 2022-04-15 12:25:05 +05:30
Kovid Goyal
4cf54d2dfb Dont rely on env -0 in zsh
zsh outputs env vars in a nice one per line format using $'' encoding.
So exploit it
2022-04-15 12:17:59 +05:30
Kovid Goyal
b866c3e783 Add a zsh test for clone env serialization 2022-04-15 12:04:50 +05:30
Kovid Goyal
c15a31e725 Ensure colors are copied form the correct window when cloning
Also, encapsulate clone command into its own class to ease testing
2022-04-15 11:53:28 +05:30
Kovid Goyal
afaf866b15 Merge branch 'ksi-fish-clone-in-kitty' of https://github.com/page-down/kitty 2022-04-14 19:47:41 +05:30
pagedown
af6b1837cb Minor refactoring for fish clone-in-kitty and allow use without env -0
The builtin option from the latest version of fish is not used for now.
clone-in-kitty has been tested with fish 3.2.x.
BusyBox env does not support the -0 option.
2022-04-14 21:32:28 +08:00
Kovid Goyal
aab6f3e450 ... 2022-04-14 17:28:41 +05:30
Kovid Goyal
829ed0ec0d Fix #4964 2022-04-14 17:20:30 +05:30
Kovid Goyal
d9899cb489 Add missing item to changelog 2022-04-14 15:04:48 +05:30
Kovid Goyal
1a370ea9b6 Put the examples front and center 2022-04-14 07:59:32 +05:30
Kovid Goyal
cc07b1f79d Use 2048 chunk size in fish as well 2022-04-13 22:50:24 +05:30
Kovid Goyal
3ddea42660 ... 2022-04-13 22:45:36 +05:30
Kovid Goyal
236dbd95c9 ... 2022-04-13 22:34:23 +05:30
Kovid Goyal
6b078c4267 Implement clone-in-kitty for the fish shell 2022-04-13 22:33:21 +05:30
Kovid Goyal
1dec5f2e08 Help message for clone-in-kitty 2022-04-13 21:38:33 +05:30
Kovid Goyal
e5f70b7306 ... 2022-04-13 21:22:27 +05:30
Kovid Goyal
e2bb856e41 Document clone-in-kitty 2022-04-13 21:01:45 +05:30
Kovid Goyal
88d597f6b2 Dont define clone-in-kitty in POSIX mode
POSIX mode doesnt allow - in identifiers
2022-04-13 20:55:00 +05:30
Kovid Goyal
d0c0b01724 Get clone-in-kitty working for bash as well 2022-04-13 20:38:04 +05:30
Kovid Goyal
4b7c50518e Fix usage of chunk_num 2022-04-13 20:16:51 +05:30
Kovid Goyal
a1bfcd9fc5 Also transfer env vars when cloning over ssh kitten 2022-04-13 20:08:06 +05:30
Kovid Goyal
eb024fa40a ... 2022-04-13 15:51:00 +05:30
Kovid Goyal
122475ad4d Work on getting cloning working with the SSH kitten
Still need to do environment passing
2022-04-13 15:41:42 +05:30
Kovid Goyal
f7114bc1c5 ... 2022-04-13 15:35:06 +05:30
Kovid Goyal
feea6998f8 Allow using the cwd of the oldest as well as the newest foreground process for launch --cwd 2022-04-13 15:31:17 +05:30
Kovid Goyal
e187110611 Use $PWD instead of pwd -P as we want the exact same cwd not the resolved one when cloning 2022-04-13 15:13:58 +05:30
Kovid Goyal
c19e69855a Start work on a command to clone the current working env into a new kitty window 2022-04-13 15:02:22 +05:30
Kovid Goyal
7788f48dd5 Ensure IFS is correct when iterating over KITTY_SHELL_INTEGRATION 2022-04-12 23:03:05 +05:30
Kovid Goyal
073eecb6bb Also package kitty.termcap 2022-04-12 22:43:22 +05:30
Kovid Goyal
030e7e2db3 termcap should be generated in generate not compile 2022-04-12 22:41:19 +05:30
Kovid Goyal
aead3c1c35 Also generate a termcap database entry when building terminfo 2022-04-12 22:38:52 +05:30
Kovid Goyal
587f44ad4e A working implementation of cwd_of_process for FreeBSD 2022-04-12 22:06:46 +05:30
Kovid Goyal
c9ef4aa8c8 Sessions: Fix os_window_size and os_window_class not applying to the first OS Window
Fixes #4957
2022-04-12 21:38:29 +05:30
Kovid Goyal
aabadd8517 ... 2022-04-12 21:19:28 +05:30
Kovid Goyal
b8866371a3 avoid unneccessary session creation during startup 2022-04-12 21:18:18 +05:30
Kovid Goyal
0f3883af02 ... 2022-04-12 21:13:56 +05:30
Kovid Goyal
5876ce0845 Remove --target-group in favor of the new boolean search expressions with matching on window/tab state 2022-04-12 20:41:17 +05:30
Kovid Goyal
2c72c56e22 Add a couple more states to match against
So we can now select windows/tabs that are not active/focused but are in
the active/focused tab/os window.
2022-04-12 20:35:31 +05:30
Kovid Goyal
f15ce21da1 Markup the --match options help text a bit more 2022-04-12 20:20:29 +05:30
Kovid Goyal
b3fa7310cb Allow matching on window/tab state 2022-04-12 20:14:01 +05:30
Kovid Goyal
ade38870a0 Allow using boolean operators when matching windows or tabs 2022-04-12 19:55:20 +05:30
Kovid Goyal
11bc1b100c Handle <> inside :ref: on the CLI 2022-04-12 19:48:09 +05:30
Kovid Goyal
93a7b220c9 Fix parsing of quoted words 2022-04-12 19:31:56 +05:30
Kovid Goyal
8f92c594f2 Create a search query parser 2022-04-12 19:26:25 +05:30
Kovid Goyal
afebea8635 --tab-title=current should respect any override title set on the tab 2022-04-12 12:53:59 +05:30
Kovid Goyal
5d76cfb578 Remove output start mark from last command output 2022-04-12 08:55:07 +05:30
Kovid Goyal
f085f853bd unactive -> inactive 2022-04-12 06:35:29 +05:30
Kovid Goyal
4ac2312b2a Fix #4954 2022-04-12 06:33:35 +05:30
Kovid Goyal
c6dcbe6521 Dont check if running in kitty when updating
I dont actually know if it causes any problems and its fairly
inconvenient to use another terminal.
2022-04-11 22:07:36 +05:30
Kovid Goyal
49efbf0c6e Remove the code to generate installer.sh from installer.py 2022-04-11 21:35:59 +05:30
157 changed files with 4414 additions and 2488 deletions

View File

@@ -4,7 +4,6 @@
import glob import glob
import os import os
import re
import shutil import shutil
import subprocess import subprocess
import sys import sys
@@ -13,11 +12,10 @@ import tempfile
def compile_terminfo(base): def compile_terminfo(base):
with tempfile.TemporaryDirectory() as tdir: with tempfile.TemporaryDirectory() as tdir:
proc = subprocess.run(['tic', '-x', f'-o{tdir}', 'terminfo/kitty.terminfo'], check=True, stderr=subprocess.PIPE) proc = subprocess.run(['tic', '-x', f'-o{tdir}', 'terminfo/kitty.terminfo'], capture_output=True)
regex = '^"terminfo/kitty.terminfo", line [0-9]+, col [0-9]+, terminal \'xterm-kitty\': older tic versions may treat the description field as an alias$' if proc.returncode != 0:
for error in proc.stderr.decode('utf-8').splitlines(): sys.stderr.buffer.write(proc.stderr)
if not re.match(regex, error): raise SystemExit(proc.returncode)
print(error, file=sys.stderr)
tfiles = glob.glob(os.path.join(tdir, '*', 'xterm-kitty')) tfiles = glob.glob(os.path.join(tdir, '*', 'xterm-kitty'))
if not tfiles: if not tfiles:
raise SystemExit('tic failed to output the compiled kitty terminfo file') raise SystemExit('tic failed to output the compiled kitty terminfo file')
@@ -40,6 +38,13 @@ def generate_terminfo():
with open('terminfo/kitty.terminfo', 'w') as f: with open('terminfo/kitty.terminfo', 'w') as f:
f.write(generate_terminfo()) f.write(generate_terminfo())
proc = subprocess.run(['tic', '-CrT0', 'terminfo/kitty.terminfo'], capture_output=True)
if proc.returncode != 0:
sys.stderr.buffer.write(proc.stderr)
raise SystemExit(proc.returncode)
tcap = proc.stdout.decode('utf-8').splitlines()[-1]
with open('terminfo/kitty.termcap', 'w') as f:
f.write(tcap)
compile_terminfo(os.path.join(base, 'terminfo')) compile_terminfo(os.path.join(base, 'terminfo'))

View File

@@ -35,6 +35,9 @@ def binary_includes():
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'crypt', 'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'crypt',
'iconv', 'pcre', 'graphite2', 'glib-2.0', 'freetype', 'rsync', 'iconv', 'pcre', 'graphite2', 'glib-2.0', 'freetype', 'rsync',
'harfbuzz', 'xkbcommon', 'xkbcommon-x11', 'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
# fontconfig is not bundled because in typical brain dead Linux
# distro fashion, different distros use different default config
# paths for fontconfig.
'ncursesw', 'readline', 'brotlicommon', 'brotlienc', 'brotlidec', 'ncursesw', 'readline', 'brotlicommon', 'brotlienc', 'brotlidec',
'wayland-client', 'wayland-cursor', 'wayland-client', 'wayland-cursor',
))) + ( ))) + (

View File

@@ -1,12 +1,13 @@
Tabs and Windows Tabs and Windows
------------------- -------------------
|kitty| is capable of running multiple programs organized into tabs and |kitty| is capable of running multiple programs organized into tabs and windows.
windows. The top level of organization is the *Tab*. Each tab consists The top level of organization is the :term:`OS window <os_window>`. Each OS
of one or more *windows*. The windows can be arranged in multiple window consists of one or more :term:`tabs <tab>`. Each tab consists of one or more
different layouts, like windows are organized in a tiling window :term:`kitty windows <window>`. The kitty windows can be arranged in multiple
manager. The keyboard controls (which are all customizable) for tabs and different :term:`layouts <layout>`, like windows are organized in a tiling
windows are: window manager. The keyboard controls (which are :ref:`all customizable
<conf-kitty-shortcuts>`) for tabs and windows are:
Scrolling Scrolling
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
@@ -64,8 +65,9 @@ Focus specific window :sc:`first_window`, :sc:`second_window` ... :sc:`ten
(clockwise from the top-left) (clockwise from the top-left)
======================== ======================= ======================== =======================
Additionally, you can define shortcuts in :file:`kitty.conf` to focus neighboring Additionally, you can define shortcuts in :file:`kitty.conf` to focus
windows and move windows around (similar to window movement in vim):: neighboring windows and move windows around (similar to window movement in
:program:`vim`)::
map ctrl+left neighboring_window left map ctrl+left neighboring_window left
map shift+left move_window right map shift+left move_window right
@@ -77,20 +79,20 @@ You can also define a shortcut to switch to the previously active window::
map ctrl+p nth_window -1 map ctrl+p nth_window -1
``nth_window`` will focus the nth window for positive numbers (starting from :ac:`nth_window` will focus the nth window for positive numbers (starting from
zero) and the previously active windows for negative numbers. zero) and the previously active windows for negative numbers.
To switch to the nth OS window, you can define ``nth_os_window``. Only positive To switch to the nth OS window, you can define :ac:`nth_os_window`. Only
numbers are accepted, starting from one. positive numbers are accepted, starting from one.
.. _detach_window: .. _detach_window:
You can define shortcuts to detach the current window and You can define shortcuts to detach the current window and move it to another tab
move it to another tab or another OS window:: or another OS window::
# moves the window into a new OS window # moves the window into a new OS window
map ctrl+f2 detach_window map ctrl+f2 detach_window
# moves the window into a new Tab # moves the window into a new tab
map ctrl+f3 detach_window new-tab map ctrl+f3 detach_window new-tab
# moves the window into the previously active tab # moves the window into the previously active tab
map ctrl+f3 detach_window tab-prev map ctrl+f3 detach_window tab-prev
@@ -106,8 +108,8 @@ Similarly, you can detach the current tab, with::
# asks which OS Window to move the tab into # asks which OS Window to move the tab into
map ctrl+f4 detach_tab ask map ctrl+f4 detach_tab ask
Finally, you can define a shortcut to close all windows in a tab other than Finally, you can define a shortcut to close all windows in a tab other than the
the currently active window:: currently active window::
map f9 close_other_windows_in_tab map f9 close_other_windows_in_tab
@@ -124,18 +126,18 @@ Action Shortcut
Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS) Copy to clipboard :sc:`copy_to_clipboard` (also :kbd:`⌘+c` on macOS)
Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS) Paste from clipboard :sc:`paste_from_clipboard` (also :kbd:`⌘+v` on macOS)
Paste from selection :sc:`paste_from_selection` Paste from selection :sc:`paste_from_selection`
Pass selection to program :sc:`pass_selection_to_program`
Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS) Increase font size :sc:`increase_font_size` (also :kbd:`⌘++` on macOS)
Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS) Decrease font size :sc:`decrease_font_size` (also :kbd:`⌘+-` on macOS)
Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS) Restore font size :sc:`reset_font_size` (also :kbd:`⌘+0` on macOS)
Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`⌃+⌘+f` on macOS) Toggle fullscreen :sc:`toggle_fullscreen` (also :kbd:`⌃+⌘+f` on macOS)
Toggle maximized :sc:`toggle_maximized` Toggle maximized :sc:`toggle_maximized`
Input unicode character :sc:`input_unicode_character` (also :kbd:`⌃+⌘+space` on macOS) Input Unicode character :sc:`input_unicode_character` (also :kbd:`⌃+⌘+space` on macOS)
Open URL in web browser :sc:`open_url` Open URL in web browser :sc:`open_url`
Reset the terminal :sc:`reset_terminal` (also :kbd:`⌥+⌘+r` on macOS) Reset the terminal :sc:`reset_terminal` (also :kbd:`⌥+⌘+r` on macOS)
Edit :file:`kitty.conf` :sc:`edit_config_file` (also :kbd:`⌘+,` on macOS)
Reload :file:`kitty.conf` :sc:`reload_config_file` (also :kbd:`⌃+⌘+,` on macOS) Reload :file:`kitty.conf` :sc:`reload_config_file` (also :kbd:`⌃+⌘+,` on macOS)
Debug :file:`kitty.conf` :sc:`debug_config` (also :kbd:`⌥+⌘+,` on macOS) Debug :file:`kitty.conf` :sc:`debug_config` (also :kbd:`⌥+⌘+,` on macOS)
Pass current selection to program :sc:`pass_selection_to_program`
Edit |kitty| config file :sc:`edit_config_file` (also :kbd:`⌘+,` on macOS)
Open a |kitty| shell :sc:`kitty_shell` Open a |kitty| shell :sc:`kitty_shell`
Increase background opacity :sc:`increase_background_opacity` Increase background opacity :sc:`increase_background_opacity`
Decrease background opacity :sc:`decrease_background_opacity` Decrease background opacity :sc:`decrease_background_opacity`

View File

@@ -4,17 +4,14 @@ Install kitty
Binary install Binary install
---------------- ----------------
.. |ins| replace:: curl -L :literal:`https://sw.kovidgoyal.net/kitty/installer.sh` | sh /dev/stdin
.. highlight:: sh .. highlight:: sh
You can install pre-built binaries of |kitty| if you are on macOS or Linux using You can install pre-built binaries of |kitty| if you are on macOS or Linux using
the following simple command: the following simple command:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| _kitty_install_cmd
The binaries will be installed in the standard location for your OS, The binaries will be installed in the standard location for your OS,
@@ -24,7 +21,7 @@ simply re-run the command.
.. warning:: .. warning::
**Do not** copy the kitty binary out of the installation folder. If you want **Do not** copy the kitty binary out of the installation folder. If you want
to add it to your ``PATH`` create a symlink in :file:`~/.local/bin` or 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.
@@ -33,11 +30,12 @@ Manually installing
If something goes wrong or you simply do not want to run the installer, you can If something goes wrong or you simply do not want to run the installer, you can
manually download and install |kitty| from the `GitHub releases page manually download and install |kitty| from the `GitHub releases page
<https://github.com/kovidgoyal/kitty/releases>`_. If you are on macOS, download <https://github.com/kovidgoyal/kitty/releases>`__. If you are on macOS, download
the :file:`.dmg` and install as normal. If you are on Linux, download the tarball the :file:`.dmg` and install as normal. If you are on Linux, download the
and extract it into a directory. The |kitty| executable will be in the tarball and extract it into a directory. The |kitty| executable will be in the
:file:`bin` sub-directory. :file:`bin` sub-directory.
Desktop integration on Linux Desktop integration on Linux
-------------------------------- --------------------------------
@@ -60,9 +58,19 @@ particular desktop, but it should work for most major desktop environments.
sed -i "s|Exec=kitty|Exec=/home/$USER/.local/kitty.app/bin/kitty|g" ~/.local/share/applications/kitty*.desktop sed -i "s|Exec=kitty|Exec=/home/$USER/.local/kitty.app/bin/kitty|g" ~/.local/share/applications/kitty*.desktop
.. note:: .. note::
If you use the venerable `stow <https://www.gnu.org/software/stow/>`_ In :file:`kitty-open.desktop`, kitty is registered to handle some supported
MIME types. This will cause kitty to take precedence on some systems where
the default apps are not explicitly set. For example, you expect to use
other GUI file managers to open dir paths when using commands such as
:program:`xdg-open`, you should configure the default opener for the MIME
type ``inode/directory``::
xdg-mime default org.kde.dolphin.desktop inode/directory
.. note::
If you use the venerable `stow <https://www.gnu.org/software/stow/>`__
command to manage your manual installations, the following takes care of the command to manage your manual installations, the following takes care of the
above for you (use with :file:`dest=~/.local/stow`):: above for you (use with :code:`dest=~/.local/stow`)::
cd ~/.local/stow cd ~/.local/stow
stow -v kitty.app stow -v kitty.app
@@ -75,44 +83,39 @@ Customizing the installation
* You can install the latest nightly kitty build with ``installer``: * You can install the latest nightly kitty build with ``installer``:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| \\ _kitty_install_cmd \\
installer=nightly installer=nightly
If you want to install it in parallel to the released kitty specify a If you want to install it in parallel to the released kitty specify a
different install locations with ``dest``: different install locations with ``dest``:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| \\ _kitty_install_cmd \\
installer=nightly dest=/some/other/location installer=nightly dest=/some/other/location
* You can specify a different install location, with ``dest``: * You can specify a different install location, with ``dest``:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| \\ _kitty_install_cmd \\
dest=/some/other/location dest=/some/other/location
* You can tell the installer not to launch |kitty| after installing it with * You can tell the installer not to launch |kitty| after installing it with
``launch=n``: ``launch=n``:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| \\ _kitty_install_cmd \\
launch=n launch=n
* You can use a previously downloaded dmg/tarball, with ``installer``: * You can use a previously downloaded dmg/tarball, with ``installer``:
.. parsed-literal:: .. code-block:: sh
:class: pre
|ins| \\ _kitty_install_cmd \\
installer=/path/to/dmg or tarball installer=/path/to/dmg or tarball

View File

@@ -7,21 +7,21 @@ Build from source
.. highlight:: sh .. highlight:: sh
|kitty| is designed to run from source, for easy hack-ability. Make sure |kitty| is designed to run from source, for easy hack-ability. Make sure the
the following dependencies are installed first. following dependencies are installed first.
.. note:: .. note::
If you just want to test the latest changes to kitty you dont need to build If you just want to test the latest changes to kitty, you don't need to build
from source. Instead install the :ref:`latest nightly build <nightly>`. from source. Instead install the :ref:`latest nightly build <nightly>`.
.. note:: .. note::
If you are making small changes only to the python parts of kitty, there is no need to If you are making small changes only to the Python parts of kitty, there is
build kitty at all, instead, assuming you have installed the official kitty no need to build kitty at all, instead, assuming you have installed the
binaries, you can simply set the KITTY_DEVELOP_FROM enviroment variable to official kitty binaries, you can simply set the :envvar:`KITTY_DEVELOP_FROM`
point to the directory into which you have checked out the kitty source enviroment variable to point to the directory into which you have checked out
code. kitty will then load its python code from there. You should use a the kitty source code. kitty will then load its Python code from there. You
version of the source that matches the binary version as closely as should use a version of the source that matches the binary version as closely
possible, since the two are tightly coupled. as possible, since the two are tightly coupled.
Dependencies Dependencies
@@ -46,7 +46,9 @@ Build-time dependencies:
* ``gcc`` or ``clang`` * ``gcc`` or ``clang``
* ``pkg-config`` * ``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 your distro: * 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
your distro:
- ``libdbus-1-dev`` - ``libdbus-1-dev``
- ``libxcursor-dev`` - ``libxcursor-dev``
@@ -77,9 +79,8 @@ You can run |kitty|, as::
./kitty/launcher/kitty ./kitty/launcher/kitty
If that works, you can create a symlink to the launcher in :file:`~/bin` or If that works, you can create a symlink to the launcher in :file:`~/bin` or some
some other directory on your PATH so that you can run |kitty| using other directory on your PATH so that you can run |kitty| using just ``kitty``.
just ``kitty``.
Building kitty.app on macOS from source Building kitty.app on macOS from source
@@ -90,25 +91,24 @@ Run::
make app make app
This :file:`kitty.app` unlike the released one does not include its own copy of This :file:`kitty.app` unlike the released one does not include its own copy of
python and the other dependencies. So if you ever un-install/upgrade those dependencies Python and the other dependencies. So if you ever un-install/upgrade those
you might have to rebuild the app. dependencies you might have to rebuild the app.
.. note:: .. note::
The released :file:`kitty.dmg` includes all dependencies, unlike the The released :file:`kitty.dmg` includes all dependencies, unlike the
:file:`kitty.app` built above and is built automatically by using the :file:`kitty.app` built above and is built automatically by using the
`bypy framework <https://github.com/kovidgoyal/bypy>`_ however, that is `bypy framework <https://github.com/kovidgoyal/bypy>`__ however, that is
designed to run on Linux and is not for the faint of heart. designed to run on Linux and is not for the faint of heart.
.. note:: .. note::
Apple disallows certain functionality, such as notifications for unsigned applications. Apple disallows certain functionality, such as notifications for unsigned
If you need this functionality, you can try signing the built kitty.app with applications. If you need this functionality, you can try signing the built
a self signed certificate, see for example, `here :file:`kitty.app` with a self signed certificate, see for example, `here
<https://stackoverflow.com/questions/27474751/how-can-i-codesign-an-app-without-being-in-the-mac-developer-program/27474942>`_. <https://stackoverflow.com/questions/27474751/how-can-i-codesign-an-app-without-being-in-the-mac-developer-program/27474942>`__.
.. note:: .. note::
If you are facing issues with ``linker`` while building, If you are facing issues with ``linker`` while building, try with a ``brew``
try with a ``brew`` installed python instead, see :iss:`289` installed Python instead, see :iss:`289` for more discussion.
for more discussion.
Build and run from source with Nix Build and run from source with Nix
@@ -116,13 +116,14 @@ Build and run from source with Nix
On NixOS or any other Linux or macOS system with the Nix package manager On NixOS or any other Linux or macOS system with the Nix package manager
installed, execute `nix-shell installed, execute `nix-shell
<https://nixos.org/guides/nix-pills/developing-with-nix-shell.html>`_ to create <https://nixos.org/guides/nix-pills/developing-with-nix-shell.html>`__ to create
the correct environment to build kitty or use ``nix-shell --pure`` instead to the correct environment to build kitty or use ``nix-shell --pure`` instead to
eliminate most of the influence of the outside system, e.g. globally installed eliminate most of the influence of the outside system, e.g. globally installed
packages. ``nix-shell`` will automatically fetch all required dependencies and packages. ``nix-shell`` will automatically fetch all required dependencies and
make them available in the newly spawned shell. make them available in the newly spawned shell.
Then proceed with ``make`` or ``make app`` according to the platform specific instructions above. Then proceed with ``make`` or ``make app`` according to the platform specific
instructions above.
Debug builds Debug builds
@@ -132,7 +133,8 @@ A basic debug build can be done with::
make debug make debug
This includes debug info in the binary for better traces. To build with address sanitizer, use:: This includes debug info in the binary for better traces. To build with address
sanitizer, use::
make asan make asan
@@ -144,46 +146,45 @@ Notes for Linux/macOS packagers
---------------------------------- ----------------------------------
The released |kitty| source code is available as a `tarball`_ from The released |kitty| source code is available as a `tarball`_ from
`the GitHub releases page <https://github.com/kovidgoyal/kitty/releases>`_. `the GitHub releases page <https://github.com/kovidgoyal/kitty/releases>`__.
While |kitty| does use python, it is not a traditional python package, so please While |kitty| does use Python, it is not a traditional Python package, so please
do not install it in site-packages. do not install it in site-packages.
Instead run:: Instead run::
python3 setup.py linux-package python3 setup.py linux-package
This will install |kitty| into the directory :file:`linux-package`. You can run |kitty| This will install |kitty| into the directory :file:`linux-package`. You can run
with :file:`linux-package/bin/kitty`. All the files needed to run kitty will be in |kitty| with :file:`linux-package/bin/kitty`. All the files needed to run kitty
:file:`linux-package/lib/kitty`. The terminfo file will be installed into will be in :file:`linux-package/lib/kitty`. The terminfo file will be installed
:file:`linux-package/share/terminfo`. Simply copy these files into :file:`/usr` to install into :file:`linux-package/share/terminfo`. Simply copy these files into
|kitty|. In other words, :file:`linux-package` is the staging area into which |kitty| is :file:`/usr` to install |kitty|. In other words, :file:`linux-package` is the
installed. You can choose a different staging area, by passing the ``--prefix`` staging area into which |kitty| is installed. You can choose a different staging
argument to :file:`setup.py`. area, by passing the ``--prefix`` argument to :file:`setup.py`.
You should probably split |kitty| into three packages: You should probably split |kitty| into three packages:
:code:`kitty-terminfo` :code:`kitty-terminfo`
installs the terminfo file Installs the terminfo file
:code:`kitty-shell-integration` :code:`kitty-shell-integration`
installs the shell integration scripts (the contents of the Installs the shell integration scripts (the contents of the
shell-integration directory in the kitty source code, probably to shell-integration directory in the kitty source code), probably to
:file:`/usr/share/kitty/shell-integration` :file:`/usr/share/kitty/shell-integration`
:code:`kitty` :code:`kitty`
installs the main program Installs the main program
This allows users to install the terminfo and shell integration files on This allows users to install the terminfo and shell integration files on servers
servers into which they ssh, without needing to install all of |kitty|. into which they ssh, without needing to install all of |kitty|.
.. note:: .. note::
You need a couple of extra dependencies to build linux-package. You need a couple of extra dependencies to build linux-package. :file:`tic`
:file:`tic` to compile terminfo files, usually found in the to compile terminfo files, usually found in the development package of
development package of :file:`ncurses`. Also, if you are building from :file:`ncurses`. Also, if you are building from a git checkout instead of the
a git checkout instead of the released source code tarball, you will released source code tarball, you will need to install the dependencies from
need to install the dependencies from ``docs/requirements.txt`` to :file:`docs/requirements.txt` to build the kitty documentation. They can be
build the kitty documentation. They can be installed most easily with installed most easily with ``python -m pip -r docs/requirements.txt``.
``python -m pip -r docs/requirements.txt``.
This applies to creating packages for |kitty| for macOS package managers such as This applies to creating packages for |kitty| for macOS package managers such as
Homebrew or MacPorts as well. Homebrew or MacPorts as well.

View File

@@ -34,6 +34,51 @@ mouse anywhere in the current command to move the cursor there. See
Detailed list of changes Detailed list of changes
------------------------------------- -------------------------------------
0.25.1 [2022-05-26]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Shell integration: Add a command to :ref:`clone_shell`
- Remote control: Allow using :ref:`Boolean operators <search_syntax>` when constructing queries to match windows or tabs
- Sessions: Fix :code:`os_window_size` and :code:`os_window_class` not applying to the first OS Window (:iss:`4957`)
- Allow using the cwd of the oldest as well as the newest foreground process for :option:`launch --cwd` (:disc:`4869`)
- Bash integration: Fix the value of :opt:`shell_integration` not taking effect if the integration script is sourced in bashrc (:pull:`4964`)
- Fix a regression in the previous release that caused mouse move events to be incorrectly reported as drag events even when a button is not pressed (:iss:`4992`)
- remote file kitten: Integrate with the ssh kitten for improved performance
and robustness. Re-uses the control master connection of the ssh kitten to
avoid round-trip latency.
- Fix tab selection when closing a new tab not correct in some scenarios (:iss:`4987`)
- A new action :ac:`open_url` to open the specified URL (:pull:`5004`)
- A new option :opt:`select_by_word_characters_forward` that allows changing
which characters are considered part of a word to the right when double clicking to select
words (:pull:`5103`)
- macOS: Make the global menu shortcut to open kitty website configurable (:pull:`5004`)
- macOS: Add the :opt:`macos_colorspace` option to control what color space colors are rendered in (:iss:`4686`)
- Fix reloading of config not working when :file:`kitty.conf` does not exist when kitty is launched (:iss:`5071`)
- Fix deleting images by row not calculating image bounds correctly (:iss:`5081`)
- Increase the max number of combining chars per cell from two to three, without increasing memory usage.
- Linux: Load libfontconfig at runtime to allow the binaries to work for
running kittens on servers without FontConfig
- GNOME: Fix for high CPU usage caused by GNOME's text input subsystem going
into an infinite loop when IME cursor position is updated after a done event
(:iss:`5105`)
0.25.0 [2022-04-11] 0.25.0 [2022-04-11]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -43,6 +88,10 @@ Detailed list of changes
- When pasting URLs at shell prompts automatically quote them. Also allow filtering pasted text and confirm pastes. See :opt:`paste_actions` for details. (:iss:`4873`) - When pasting URLs at shell prompts automatically quote them. Also allow filtering pasted text and confirm pastes. See :opt:`paste_actions` for details. (:iss:`4873`)
- Change the default value of :opt:`confirm_os_window_close` to ask for confirmation when closing windows that are not sitting at shell prompts
- A new value :code:`last_reported` for :option:`launch --cwd` to use the current working directory last reported by the program running in the terminal
- macOS: When using Apple's less as the pager for viewing scrollback strip out OSC codes as it cant parse them (:iss:`4788`) - macOS: When using Apple's less as the pager for viewing scrollback strip out OSC codes as it cant parse them (:iss:`4788`)
- diff kitten: Fix incorrect rendering in rare circumstances when scrolling after changing the context size (:iss:`4831`) - diff kitten: Fix incorrect rendering in rare circumstances when scrolling after changing the context size (:iss:`4831`)

View File

@@ -2,25 +2,25 @@ Saving and restoring colors
============================== ==============================
It is often useful for a full screen application with its own color themes to It is often useful for a full screen application with its own color themes to
set the default foreground, background, selection and cursor colors and the set the default foreground, background, selection and cursor colors and the ANSI
ANSI color table. This allows for various performance optimizations when color table. This allows for various performance optimizations when drawing the
drawing the screen. The problem is that if the user previously used the escape screen. The problem is that if the user previously used the escape codes to
codes to change these colors herself, then running the full screen application change these colors themselves, then running the full screen application will
will lose her changes even after it exits. To avoid this, kitty introduces a lose those changes even after it exits. To avoid this, kitty introduces a new
new pair of *OSC* escape codes to push and pop the current color values from a pair of *OSC* escape codes to push and pop the current color values from a
stack:: stack::
<ESC>]30001<ESC>\ # push onto stack <ESC>]30001<ESC>\ # push onto stack
<ESC>]30101<ESC>\ # pop from stack <ESC>]30101<ESC>\ # pop from stack
These escape codes save/restore the colors, default These escape codes save/restore the colors, default background, default
background, default foreground, selection background, selection foreground and foreground, selection background, selection foreground and cursor color and the
cursor color and the 256 colors of the ANSI color table. 256 colors of the ANSI color table.
.. note:: In July 2020, after several years, XTerm copied this protocol .. note:: In July 2020, after several years, xterm copied this protocol
extension, without acknowledgement, and using incompatible escape codes extension, without acknowledgement, and using incompatible escape codes
(XTPUSHCOLORS, XTPOPCOLORS, XTREPORTCOLORS). And they decided to save not (XTPUSHCOLORS, XTPOPCOLORS, XTREPORTCOLORS). And they decided to save not
just the dynamic colors but the entire ANSI color table. In the interests of just the dynamic colors but the entire ANSI color table. In the interests of
promoting interoperability, kitty added support for XTerm's escape codes as promoting interoperability, kitty added support for xterm's escape codes as
well, and changed this extension to also save/restore the entire ANSI color well, and changed this extension to also save/restore the entire ANSI color
table. table.

View File

@@ -104,6 +104,10 @@ rst_prolog = '''
'''.replace('VERSION', str_version) '''.replace('VERSION', str_version)
smartquotes_action = 'qe' # educate quotes and ellipses but not dashes smartquotes_action = 'qe' # educate quotes and ellipses but not dashes
string_replacements = {
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
}
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------
@@ -300,8 +304,16 @@ def write_remote_control_protocol_docs() -> None: # {{{
# }}} # }}}
def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
src = source[0]
for k, v in app.config.string_replacements.items():
src = src.replace(k, v)
source[0] = src
# }}}
# config file docs {{{ # config file docs {{{
class ConfLexer(RegexLexer): # type: ignore class ConfLexer(RegexLexer): # type: ignore
name = 'Conf' name = 'Conf'
aliases = ['conf'] aliases = ['conf']
@@ -516,6 +528,8 @@ def setup(app: Any) -> None:
write_cli_docs(kn) write_cli_docs(kn)
write_remote_control_protocol_docs() write_remote_control_protocol_docs()
write_conf_docs(app, kn) write_conf_docs(app, kn)
app.add_config_value('string_replacements', {}, True)
app.connect('source-read', replace_string)
app.add_config_value('analytics_id', '', 'env') app.add_config_value('analytics_id', '', 'env')
app.connect('html-page-context', add_html_context) app.connect('html-page-context', add_html_context)
app.add_lexer('session', SessionLexer() if version_info[0] < 3 else SessionLexer) app.add_lexer('session', SessionLexer() if version_info[0] < 3 else SessionLexer)

View File

@@ -3,13 +3,14 @@ kitty.conf
.. highlight:: conf .. highlight:: conf
|kitty| is highly customizable, everything from keyboard shortcuts, to |kitty| is highly customizable, everything from keyboard shortcuts, to rendering
rendering frames-per-second. See below for an overview of all customization frames-per-second. See below for an overview of all customization possibilities.
possibilities.
You can open the config file within kitty by pressing :sc:`edit_config_file` (:kbd:`⌘+,` on macOS). You can open the config file within kitty by pressing :sc:`edit_config_file`
You can reload the config file within kitty by pressing (:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default
:sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending kitty the ``SIGUSR1`` signal. configurations and descriptions will be created if the file does not exist.
You can reload the config file within kitty by pressing :sc:`reload_config_file`
(:kbd:`⌃+⌘+,` on macOS) or sending kitty the ``SIGUSR1`` signal.
You can also display the current configuration by pressing :sc:`debug_config` You can also display the current configuration by pressing :sc:`debug_config`
(:kbd:`⌥+⌘+,` on macOS). (:kbd:`⌥+⌘+,` on macOS).
@@ -17,12 +18,12 @@ You can also display the current configuration by pressing :sc:`debug_config`
|kitty| looks for a config file in the OS config directories (usually |kitty| looks for a config file in the OS config directories (usually
:file:`~/.config/kitty/kitty.conf`) but you can pass a specific path via the :file:`~/.config/kitty/kitty.conf`) but you can pass a specific path via the
:option:`kitty --config` option or use the ``KITTY_CONFIG_DIRECTORY`` :option:`kitty --config` option or use the :envvar:`KITTY_CONFIG_DIRECTORY`
environment variable. See the :option:`kitty --config` option for full details. environment variable. See :option:`kitty --config` for full details.
Comments can be added to the config file as lines starting with the ``#`` Comments can be added to the config file as lines starting with the ``#``
character. This works only if the ``#`` character is the first character character. This works only if the ``#`` character is the first character in the
in the line. line.
.. _include: .. _include:
@@ -42,7 +43,7 @@ from environment variables. For example::
.. note:: Syntax highlighting for :file:`kitty.conf` in vim is available via .. note:: Syntax highlighting for :file:`kitty.conf` in vim is available via
`vim-kitty <https://github.com/fladson/vim-kitty>`_. `vim-kitty <https://github.com/fladson/vim-kitty>`__.
.. include:: /generated/conf-kitty.rst .. include:: /generated/conf-kitty.rst
@@ -53,17 +54,17 @@ Sample kitty.conf
.. only:: html .. only:: html
You can download a sample :file:`kitty.conf` file with all default settings and You can download a sample :file:`kitty.conf` file with all default settings
comments describing each setting by clicking: :download:`sample kitty.conf and comments describing each setting by clicking: :download:`sample
</generated/conf/kitty.conf>`. kitty.conf </generated/conf/kitty.conf>`.
.. only:: man .. only:: man
You can edit a fully commented sample kitty.conf by pressing the You can edit a fully commented sample kitty.conf by pressing the
:sc:`edit_config_file` shortcut in kitty. This will generate a config :sc:`edit_config_file` shortcut in kitty. This will generate a config file
file with full documentation and all settings commented out. If you with full documentation and all settings commented out. If you have a
have a pre-existing kitty.conf, then that will be used instead, delete pre-existing :file:`kitty.conf`, then that will be used instead, delete it to
it to see the sample file. see the sample file.
All mappable actions All mappable actions

View File

@@ -3,19 +3,18 @@ Setting text styles/colors in arbitrary regions of the screen
There already exists an escape code to set *some* text attributes in arbitrary There already exists an escape code to set *some* text attributes in arbitrary
regions of the screen, `DECCARA regions of the screen, `DECCARA
<https://vt100.net/docs/vt510-rm/DECCARA.html>`_. However, it is limited to <https://vt100.net/docs/vt510-rm/DECCARA.html>`__. However, it is limited to
only a few attributes. |kitty| extends this to work with *all* SGR attributes. only a few attributes. |kitty| extends this to work with *all* SGR attributes.
So, for example, this can be used to set the background color in an arbitrary So, for example, this can be used to set the background color in an arbitrary
region of the screen. region of the screen.
The motivation for this extension is the various problems with the existing The motivation for this extension is the various problems with the existing
solution for erasing to background color, namely the *background color erase solution for erasing to background color, namely the *background color erase
(bce)* capability. See (bce)* capability. See :iss:`this discussion <160#issuecomment-346470545>`
:iss:`this discussion <160#issuecomment-346470545>` and `this FAQ <https://invisible-island.net/ncurses/ncurses.faq.html#bce_mismatches>`__
and `this FAQ <https://invisible-island.net/ncurses/ncurses.faq.html#bce_mismatches>`_
for a summary of problems with *bce*. for a summary of problems with *bce*.
For example, to set the background color to blue in a For example, to set the background color to blue in a rectangular region of the
rectangular region of the screen from (3, 4) to (10, 11), you use:: screen from (3, 4) to (10, 11), you use::
<ESC>[2*x<ESC>[4;3;11;10;44$r<ESC>[*x <ESC>[2*x<ESC>[4;3;11;10;44$r<ESC>[*x

View File

@@ -5,21 +5,20 @@ Desktop notifications
======================= =======================
|kitty| implements an extensible escape code (OSC 99) to show desktop |kitty| implements an extensible escape code (OSC 99) to show desktop
notifications. It is easy to use from shell scripts and fully extensible to notifications. It is easy to use from shell scripts and fully extensible to show
show title and body. Clicking on the notification can optionally focus the title and body. Clicking on the notification can optionally focus the window it
window it came from, and/or send an escape code back to the application running came from, and/or send an escape code back to the application running in that
in that window. window.
The design of the escape code is partially based on the discussion in The design of the escape code is partially based on the discussion in the
the defunct defunct `terminal-wg <https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/13>`__
`terminal-wg <https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/13>`_
The escape code has the form:: The escape code has the form::
<OSC> 99 ; metadata ; payload <terminator> <OSC> 99 ; metadata ; payload <terminator>
Here ``<OSC>`` is :code:`<ESC>]` and ``<terminator>`` is Here ``<OSC>`` is :code:`<ESC>]` and ``<terminator>`` is
:code:`<ESC><backslash>`. The metadata is a section of colon separated :code:`<ESC><backslash>`. The ``metadata`` is a section of colon separated
:code:`key=value` pairs. Every key must be a single character from the set :code:`key=value` pairs. Every key must be a single character from the set
:code:`a-zA-Z` and every value must be a word consisting of characters from :code:`a-zA-Z` and every value must be a word consisting of characters from
the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be
@@ -45,28 +44,27 @@ The design of the escape code is fundamentally chunked, this is because
different terminal emulators have different limits on how large a single escape different terminal emulators have different limits on how large a single escape
code can be. Chunking is accomplished by the ``i`` and ``d`` keys. The ``i`` code can be. Chunking is accomplished by the ``i`` and ``d`` keys. The ``i``
key is the *notification id* which can be any string containing the characters key is the *notification id* which can be any string containing the characters
``[a-zA-Z0-9_-+.]``. The ``d`` key stands for *done* and ``[a-zA-Z0-9_-+.]``. The ``d`` key stands for *done* and can only take the
can only take the values ``0`` and ``1``. A value of ``0`` means the values ``0`` and ``1``. A value of ``0`` means the notification is not yet done
notification is not yet done and the terminal emulator should hold off and the terminal emulator should hold off displaying it. A value of ``1`` means
displaying it. A value of ``1`` means the notification is done, and should be the notification is done, and should be displayed. You can specify the title or
displayed. You can specify the title or body multiple times and the terminal body multiple times and the terminal emulator will concatenate them, thereby
emulator will concatenate them, thereby allowing arbitrarily long text allowing arbitrarily long text (terminal emulators are free to impose a sensible
(terminal emulators are free to impose a sensible limit to avoid limit to avoid Denial-of-Service attacks).
Denial-of-Service attacks).
Both the ``title`` and ``body`` payloads must be either UTF-8 encoded plain 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 text with no embedded escape codes, or UTF-8 text that is Base64 encoded, in
which case there must be an ``e=1`` key in the metadata to indicate the payload which case there must be an ``e=1`` key in the metadata to indicate the payload
is base64 encoded. is Base64 encoded.
When the user clicks the notification, a couple of things can happen, the When the user clicks the notification, a couple of things can happen, the
terminal emulator can focus the window from which the notification came, and/or terminal emulator can focus the window from which the notification came, and/or
it can send back an escape code to the application indicating the notification it can send back an escape code to the application indicating the notification
was activated. This is controlled by the ``a`` key which takes a comma was activated. This is controlled by the ``a`` key which takes a comma separated
separated set of values, ``report`` and ``focus``. The value ``focus`` means set of values, ``report`` and ``focus``. The value ``focus`` means focus the
focus the window from which the notification was issued and is the default. window from which the notification was issued and is the default. ``report``
``report`` means send an escape code back to the application. The format of the means send an escape code back to the application. The format of the returned
returned escape code is:: escape code is::
<OSC> 99 ; i=identifier ; <terminator> <OSC> 99 ; i=identifier ; <terminator>
@@ -87,9 +85,9 @@ to display it based on what it does understand.
.. note:: .. note::
It is possible to extend this escape code to allow specifying an icon for It is possible to extend this escape code to allow specifying an icon for
the notification, however, given that some platforms, such as macOS, dont the notification, however, given that some platforms, such as legacy versions
allow displaying custom icons on a notification, at all, it was decided to of macOS, don't allow displaying custom images on a notification, it was
leave it out of the spec for the time being. decided to leave it out of the spec for the time being.
Similarly, features such as scheduled notifications could be added in future Similarly, features such as scheduled notifications could be added in future
revisions. revisions.
@@ -107,7 +105,7 @@ Key Value Default Description
``d`` ``0`` or ``1`` ``1`` Indicates if the notification is ``d`` ``0`` or ``1`` ``1`` Indicates if the notification is
complete or not. complete or not.
``e`` ``0`` or ``1`` ``0`` If set to ``1`` means the payload is base64 encoded UTF-8, ``e`` ``0`` or ``1`` ``0`` If set to ``1`` means the payload is Base64 encoded UTF-8,
otherwise it is plain UTF-8 text with no C0 control codes in it otherwise it is plain UTF-8 text with no C0 control codes in it
``i`` ``[a-zA-Z0-9-_+.]`` ``0`` Identifier for the notification ``i`` ``[a-zA-Z0-9-_+.]`` ``0`` Identifier for the notification
@@ -118,5 +116,6 @@ Key Value Default Description
.. note:: .. note::
|kitty| also supports the legacy OSC 9 protocol developed by iTerm2 for |kitty| also supports the `legacy OSC 9 protocol developed by iTerm2
desktop notifications. <https://iterm2.com/documentation-escape-codes.html>`__ for desktop
notifications.

View File

@@ -27,14 +27,15 @@ turned off for specific symbols using :opt:`narrow_symbols`.
Using a color theme with a background color does not work well in vim? Using a color theme with a background color does not work well in vim?
----------------------------------------------------------------------- -----------------------------------------------------------------------
First make sure you have not changed the TERM environment variable, it should First make sure you have not changed the :envvar:`TERM` environment variable, it
be ``xterm-kitty``. vim uses *background color erase* even if the terminfo file should be ``xterm-kitty``. vim uses *background color erase* even if the
does not contain the ``bce`` capability. This is a bug in vim. You can work around terminfo file does not contain the ``bce`` capability. This is a bug in vim. You
it by adding the following to your vimrc:: can work around it by adding the following to your vimrc::
let &t_ut='' let &t_ut=''
See :doc:`here <deccara>` for why |kitty| does not support background color erase. See :doc:`here <deccara>` for why |kitty| does not support background color
erase.
I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer? I get errors about the terminal being unknown or opening the terminal failing when SSHing into a different computer?
@@ -47,32 +48,32 @@ terminfo files to the server::
kitty +kitten ssh myserver kitty +kitten ssh myserver
This :doc:`ssh kitten <kittens/ssh>` takes all the same command line arguments This :doc:`ssh kitten <kittens/ssh>` takes all the same command line arguments
as ssh, you can alias it to something small in your shell's rc files to avoid as :program:`ssh`, you can alias it to something small in your shell's rc files
having to type it each time:: to avoid having to type it each time::
alias s="kitty +kitten ssh" alias s="kitty +kitten ssh"
If the ssh kitten fails, use the following one-liner instead (it If the ssh kitten fails, use the following one-liner instead (it is slower as it
is slower as it needs to ssh into the server twice, but will work with most needs to ssh into the server twice, but will work with most servers)::
servers)::
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
If you are behind a proxy (like Balabit) that prevents this, or ``tic`` comes If you are behind a proxy (like Balabit) that prevents this, or :program:`tic`
with macOS that does not support reading from STDIN, you must redirect the 1st comes with macOS that does not support reading from STDIN, you must redirect the
command to a file, copy that to the server and run ``tic`` manually. If you first command to a file, copy that to the server and run :program:`tic`
connect to a server, embedded or Android system that doesn't have ``tic``, copy over manually. If you connect to a server, embedded or Android system that doesn't
your local file terminfo to the other system as :file:`~/.terminfo/x/xterm-kitty`. have :program:`tic`, copy over your local file terminfo to the other system as
:file:`~/.terminfo/x/xterm-kitty`.
Really, the correct solution for this is to convince the OpenSSH maintainers to Really, the correct solution for this is to convince the OpenSSH maintainers to
have ssh do this automatically, if possible, when connecting to a server, so that have :program:`ssh` do this automatically, if possible, when connecting to a
all terminals work transparently. server, so that all terminals work transparently.
If the server is running FreeBSD, or another system that relies on termcap 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 rather than terminfo, you will need to convert the terminfo file on your local
machine by running (on local machine with |kitty|):: machine by running (on local machine with |kitty|)::
infocmp -C xterm-kitty infocmp -CrT0 xterm-kitty
The output of this command is the termcap description, which should be appended 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 to :file:`/usr/share/misc/termcap` on the remote server. Then run the following
@@ -84,9 +85,9 @@ command to apply your change (on the server)::
Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo? Keys such as arrow keys, backspace, delete, home/end, etc. do not work when using su or sudo?
------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------
Make sure the TERM environment variable, is ``xterm-kitty``. And either the Make sure the :envvar:`TERM` environment variable, is ``xterm-kitty``. And
TERMINFO environment variable points to a directory containing :file:`x/xterm-kitty` either the :envvar:`TERMINFO` environment variable points to a directory
or that file is under :file:`~/.terminfo/x/`. 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/`:: For macOS, you may also need to put that file under :file:`~/.terminfo/78/`::
@@ -94,18 +95,19 @@ For macOS, you may also need to put that file under :file:`~/.terminfo/78/`::
ln -snf ../x/xterm-kitty ~/.terminfo/78/xterm-kitty ln -snf ../x/xterm-kitty ~/.terminfo/78/xterm-kitty
tic -x -o ~/.terminfo "$KITTY_INSTALLATION_DIR/terminfo/kitty.terminfo" tic -x -o ~/.terminfo "$KITTY_INSTALLATION_DIR/terminfo/kitty.terminfo"
Note that ``sudo`` might remove TERMINFO. Then setting it at the shell prompt can Note that :program:`sudo` might remove :envvar:`TERMINFO`. Then setting it at
be too late, because command line editing may not be reinitialized. In that case the shell prompt can be too late, because command line editing may not be
you can either ask ``sudo`` to set it or if that is not supported, insert an ``env`` reinitialized. In that case you can either ask :program:`sudo` to set it or if
command before starting the shell, or, if not possible, after sudo start another that is not supported, insert an :program:`env` command before starting the
Shell providing the right terminfo path:: shell, or, if not possible, after sudo start another shell providing the right
terminfo path::
sudo … TERMINFO=$HOME/.terminfo bash -i sudo … TERMINFO=$HOME/.terminfo bash -i
sudo … env TERMINFO=$HOME/.terminfo bash -i sudo … env TERMINFO=$HOME/.terminfo bash -i
TERMINFO=/home/ORIGINALUSER/.terminfo exec bash -i TERMINFO=/home/ORIGINALUSER/.terminfo exec bash -i
You can configure sudo to preserve TERMINFO by running ``sudo You can configure :program:`sudo` to preserve :envvar:`TERMINFO` by running
visudo`` and adding the following line:: ``sudo visudo`` and adding the following line::
Defaults env_keep += "TERM TERMINFO" Defaults env_keep += "TERM TERMINFO"
@@ -129,12 +131,15 @@ You can also define keyboard shortcuts to set colors, for example::
map f1 set_colors --configured /path/to/some/config/file/colors.conf map f1 set_colors --configured /path/to/some/config/file/colors.conf
Or you can enable :doc:`remote control <remote-control>` for |kitty| and use :ref:`at_set-colors`. Or you can enable :doc:`remote control <remote-control>` for |kitty| and use
The shortcut mapping technique has the same syntax as the remote control :ref:`at_set-colors`. The shortcut mapping technique has the same syntax as the
command, for details, see :ref:`at_set-colors`. remote control command, for details, see :ref:`at_set-colors`.
To change colors when SSHing into a remote host, use the :opt:`color_scheme
<kitten-ssh.color_scheme>` setting for the :doc:`ssh kitten <kittens/ssh>`.
Additionally, You can use the Additionally, You can use the
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands>`_ `OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands>`__
to set colors. Examples of using OSC escape codes to set colors:: to set colors. Examples of using OSC escape codes to set colors::
Change the default foreground color: Change the default foreground color:
@@ -151,7 +156,7 @@ to set colors. Examples of using OSC escape codes to set colors::
printf '\x1b]4;n;green\x1b\\' printf '\x1b]4;n;green\x1b\\'
You can use various syntaxes/names for color specifications in the above You can use various syntaxes/names for color specifications in the above
examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`_ examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`__
for full details. for full details.
If a ``?`` is given rather than a color specification, kitty will respond If a ``?`` is given rather than a color specification, kitty will respond
@@ -164,14 +169,15 @@ How do I specify command line options for kitty on macOS?
Apple does not want you to use command line options with GUI applications. To Apple does not want you to use command line options with GUI applications. To
workaround that limitation, |kitty| will read command line options from the file workaround that limitation, |kitty| will read command line options from the file
:file:`<kitty config dir>/macos-launch-services-cmdline` when it is launched :file:`<kitty config dir>/macos-launch-services-cmdline` when it is launched
from the GUI, i.e. by clicking the |kitty| application icon or using ``open -a kitty``. from the GUI, i.e. by clicking the |kitty| application icon or using
Note that this file is *only read* when running via the GUI. ``open -a kitty``. Note that this file is *only read* when running via the GUI.
You can, of course, also run |kitty| from a terminal with command line options, using: You can, of course, also run |kitty| from a terminal with command line options,
:file:`/Applications/kitty.app/Contents/MacOS/kitty`. using: :file:`/Applications/kitty.app/Contents/MacOS/kitty`.
And within |kitty| itself, you can always run |kitty| using just ``kitty`` as it
cleverly adds itself to the :envvar:`PATH`.
And within |kitty| itself, you can always run |kitty| using just `kitty` as it
cleverly adds itself to the ``PATH``.
I catted a binary file and now kitty is hung? I catted a binary file and now kitty is hung?
----------------------------------------------- -----------------------------------------------
@@ -179,10 +185,10 @@ I catted a binary file and now kitty is hung?
**Never** output unknown binary data directly into a terminal. **Never** output unknown binary data directly into a terminal.
Terminals have a single channel for both data and control. Certain bytes Terminals have a single channel for both data and control. Certain bytes
are control codes. Some of these control codes are of arbitrary length, so are control codes. Some of these control codes are of arbitrary length, so if
if the binary data you output into the terminal happens to contain the starting the binary data you output into the terminal happens to contain the starting
sequence for one of these control codes, the terminal will hang waiting for sequence for one of these control codes, the terminal will hang waiting for the
the closing sequence. Press :kbd:`ctrl+shift+delete` to reset the terminal. closing sequence. Press :sc:`reset_terminal` to reset the terminal.
If you do want to cat unknown data, use ``cat -v``. If you do want to cat unknown data, use ``cat -v``.
@@ -190,30 +196,34 @@ If you do want to cat unknown data, use ``cat -v``.
kitty is not able to use my favorite font? kitty is not able to use my favorite font?
--------------------------------------------- ---------------------------------------------
|kitty| achieves its stellar performance by caching alpha masks of each |kitty| achieves its stellar performance by caching alpha masks of each rendered
rendered character on the GPU, and rendering them all in parallel. This means character on the GPU, and rendering them all in parallel. This means it is a
it is a strictly character cell based display. As such it can use only strictly character cell based display. As such it can use only monospace fonts,
monospace fonts, since every cell in the grid has to be the same size. since every cell in the grid has to be the same size. Furthermore, it needs
Furthermore, it needs fonts to be freely resizable, so it does not support fonts to be freely resizable, so it does not support bitmapped fonts.
bitmapped fonts.
.. note:: .. note::
If you are trying to use a font patched with NERD font symbols, dont do that If you are trying to use a font patched with `Nerd Fonts
as patching destroys fonts. There is no need, simply install the standalone <https://nerdfonts.com/>`__ symbols, don't do that as patching destroys
NERD font (the file :file:`NerdFontsSymbolsOnly.zip` from the `NERD font fonts. There is no need, simply install the standalone ``Symbols Nerd Font``
releases page <https://github.com/ryanoasis/nerd-fonts/releases>`__). kitty (the file :file:`NerdFontsSymbolsOnly.zip` from the `Nerd Fonts releases page
should pick up symbols from it automatically, and you can tell it to do so <https://github.com/ryanoasis/nerd-fonts/releases>`__). kitty should pick up
explicitly in case it doesnt with the :opt:`symbol_map` directive:: symbols from it automatically, and you can tell it to do so explicitly in
case it doesn't with the :opt:`symbol_map` directive::
symbol_map U+23FB-U+23FE,U+2665,U+26A1,U+2B58,U+E000-U+E00A,U+E0A0-U+E0A3,U+E0B0-U+E0C8,U+E0CA,U+E0CC-U+E0D2,U+E0D4,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E62F,U+E700-U+E7C5,U+F000-U+F2E0,U+F300-U+F31C,U+F400-U+F4A9,U+F500-U+F8FF Symbols Nerd Font symbol_map U+23FB-U+23FE,U+2665,U+26A1,U+2B58,U+E000-U+E00A,U+E0A0-U+E0A3,U+E0B0-U+E0C8,U+E0CA,U+E0CC-U+E0D2,U+E0D4,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E62F,U+E700-U+E7C5,U+F000-U+F2E0,U+F300-U+F31C,U+F400-U+F4A9,U+F500-U+F8FF Symbols Nerd Font
Those Unicode symbols beyond the ``E000-F8FF`` Unicode private use area are
not included.
If your font is not listed in ``kitty +list-fonts`` it means that it is not If your font is not listed in ``kitty +list-fonts`` it means that it is not
monospace or is a bitmapped font. On Linux you can list all monospace fonts with:: monospace or is a bitmapped font. On Linux you can list all monospace fonts
with::
fc-list : family spacing outline scalable | grep -e spacing=100 -e spacing=90 | grep -e outline=True | grep -e scalable=True fc-list : family spacing outline scalable | grep -e spacing=100 -e spacing=90 | grep -e outline=True | grep -e scalable=True
Note that the spacing property is calculated by fontconfig based on actual Note that the spacing property is calculated by fontconfig based on actual glyph
glyph widths in the font. If for some reason fontconfig concludes your favorite widths in the font. If for some reason fontconfig concludes your favorite
monospace font does not have ``spacing=100`` you can override it by using the monospace font does not have ``spacing=100`` you can override it by using the
following :file:`~/.config/fontconfig/fonts.conf`:: following :file:`~/.config/fontconfig/fonts.conf`::
@@ -275,7 +285,7 @@ homepage:
On macOS you can change the icon by following the steps: On macOS you can change the icon by following the steps:
#. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+i` #. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I`
#. Drag :file:`kitty.icns` onto the application icon in the kitty info pane #. Drag :file:`kitty.icns` onto the application icon in the kitty info pane
#. Delete the icon cache and restart Dock:: #. Delete the icon cache and restart Dock::
@@ -295,7 +305,10 @@ the :sc:`send_text <send_text>` you can use the ``show_key`` kitten. Run::
kitty +kitten show_key kitty +kitten show_key
Then press the key you want to emulate. Then press the key you want to emulate. Note that this kitten will only show
keys that actually reach the terminal program, in particular, keys mapped to
actions in kitty will not be shown. To check those first map them to
:ac:`no_op`.
How do I open a new window or tab with the same working directory as the current window? How do I open a new window or tab with the same working directory as the current window?
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
@@ -322,8 +335,8 @@ variables which kitty will now inherit.
You need to make sure that the environment variables you define in your shell's You need to make sure that the environment variables you define in your shell's
rc files are either also defined system wide or via the :opt:`env` directive in rc files are either also defined system wide or via the :opt:`env` directive in
:file:`kitty.conf`. Common environment variables that cause issues are those :file:`kitty.conf`. Common environment variables that cause issues are those
related to localization, such as ``LANG, LC_*`` and loading of configuration related to localization, such as :envvar:`LANG`, ``LC_*`` and loading of
files such as ``XDG_*, KITTY_CONFIG_DIRECTORY``. configuration files such as ``XDG_*``, :envvar:`KITTY_CONFIG_DIRECTORY`.
To see the environment variables that kitty sees, you can add the following To see the environment variables that kitty sees, you can add the following
mapping to :file:`kitty.conf`:: mapping to :file:`kitty.conf`::
@@ -340,40 +353,42 @@ sorts of places where they may or may not work.
I am using tmux and have a problem I am using tmux and have a problem
-------------------------------------- --------------------------------------
First, terminal multiplexers are :iss:`a bad idea <391#issuecomment-638320745>`, do First, terminal multiplexers are :iss:`a bad idea <391#issuecomment-638320745>`,
not use them, if at all possible. kitty contains features that do all of what do not use them, if at all possible. kitty contains features that do all of what
tmux does, but better, with the exception of remote persistence (:iss:`391`). tmux does, but better, with the exception of remote persistence (:iss:`391`).
If you still want to use tmux, read on. If you still want to use tmux, read on.
Image display will not work, see `tmux issue Image display will not work, see `tmux issue
<https://github.com/tmux/tmux/issues/1391>`_. <https://github.com/tmux/tmux/issues/1391>`__.
Using ancient versions of tmux such as 1.8 will Using ancient versions of tmux such as 1.8 will cause gibberish on screen when
cause gibberish on screen when pressing keys (:iss:`3541`). pressing keys (:iss:`3541`).
If you are using tmux with multiple terminals or you start it under one If you are using tmux with multiple terminals or you start it under one terminal
terminal and then switch to another and these terminals have different TERM and then switch to another and these terminals have different :envvar:`TERM`
variables, tmux will break. You will need to restart it as tmux does not variables, tmux will break. You will need to restart it as tmux does not support
support multiple terminfo definitions. multiple terminfo definitions.
If you use any of the advanced features that kitty has innovated, such as If you use any of the advanced features that kitty has innovated, such as
styled underlines, desktop notifications, extended keyboard support, etc. :doc:`styled underlines </underlines>`, :doc:`desktop notifications
they may or may not work, depending on the whims of tmux's maintainer, your </desktop-notifications>`, :doc:`extended keyboard support
version of tmux, etc. </keyboard-protocol>`, etc. they may or may not work, depending on the whims of
tmux's maintainer, your version of tmux, etc.
I opened and closed a lot of windows/tabs and top shows kitty's memory usage is very high? I opened and closed a lot of windows/tabs and top shows kitty's memory usage is very high?
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
``top`` is not a good way to measure process memory usage. That is because on :program:`top` is not a good way to measure process memory usage. That is
modern systems, when allocating memory to a process, the C library functions because on modern systems, when allocating memory to a process, the C library
will typically allocate memory in large blocks, and give the process chunks of functions will typically allocate memory in large blocks, and give the process
these blocks. When the process frees a chunk, the C library will not chunks of these blocks. When the process frees a chunk, the C library will not
necessarily release the underlying block back to the OS. So even though the necessarily release the underlying block back to the OS. So even though the
application has released the memory, ``top`` will still claim the process is application has released the memory, :program:`top` will still claim the process
using it. is using it.
To check for memory leaks, instead use a tool like ``valgrind``. Run:: To check for memory leaks, instead use a tool like `Valgrind
<https://valgrind.org/>`__. Run::
PYTHONMALLOC=malloc valgrind --tool=massif kitty PYTHONMALLOC=malloc valgrind --tool=massif kitty
@@ -386,18 +401,19 @@ that window, maybe run yes or find again. Then quit kitty and run::
You will see the allocations graph goes up when you opened the windows, then You will see the allocations graph goes up when you opened the windows, then
goes back down when you closed them, indicating there were no memory leaks. goes back down when you closed them, indicating there were no memory leaks.
For those interested, you can get a similar profile out of ``valgrind`` as you get For those interested, you can get a similar profile out of :program:`valgrind`
with ``top`` by adding ``--pages-as-heap=yes`` then you will see that memory as you get with :program:`top` by adding ``--pages-as-heap=yes`` then you will
allocated in malloc is not freed in free. This can be further refined if you see that memory allocated in malloc is not freed in free. This can be further
use `glibc`` as your C library by setting the environment variable refined if you use ``glibc`` as your C library by setting the environment
``MALLOC_MMAP_THRESHOLD_=64``. This will cause free to actually free memory variable ``MALLOC_MMAP_THRESHOLD_=64``. This will cause free to actually free
allocated in sizes of more than 64 bytes. With this set, memory usage will memory allocated in sizes of more than 64 bytes. With this set, memory usage
climb high, then fall when closing windows, but not fall all the way back. The will climb high, then fall when closing windows, but not fall all the way back.
remaining used memory can be investigated using valgrind again, and it will The remaining used memory can be investigated using valgrind again, and it will
come from arenas in the GPU drivers and the per thread arenas glibc's malloc come from arenas in the GPU drivers and the per thread arenas glibc's malloc
maintains. These too allocate memory in large blocks and dont release it back maintains. These too allocate memory in large blocks and don't release it back
to the OS immediately. to the OS immediately.
Why does kitty sometimes start slowly on my Linux system? Why does kitty sometimes start slowly on my Linux system?
------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------
@@ -421,4 +437,4 @@ The correct command will depend on your situation and hardware.
:file:`libEGL_mesa.so` and ignore :file:`libEGL_nvidia.so` also available on the :file:`libEGL_mesa.so` and ignore :file:`libEGL_nvidia.so` also available on the
system, which will wake the NVIDIA card during device enumeration. system, which will wake the NVIDIA card during device enumeration.
``MESA_LOADER_DRIVER_OVERRIDE`` also assures that Mesa won't offer any NVIDIA ``MESA_LOADER_DRIVER_OVERRIDE`` also assures that Mesa won't offer any NVIDIA
card during enumeration, and will instead just use `/lib/dri/radeonsi_dri.so`. card during enumeration, and will instead just use :file:`radeonsi_dri.so`.

View File

@@ -37,7 +37,8 @@ Glossary
hyperlinks hyperlinks
Terminals can have hyperlinks, just like the internet. In kitty you can Terminals can have hyperlinks, just like the internet. In kitty you can
:doc:`control exactly what happens <open_actions>` when clicking on a :doc:`control exactly what happens <open_actions>` when clicking on a
hyperlink, based on the type of link and its URL. hyperlink, based on the type of link and its URL. See also `Hyperlinks in terminal
emulators <https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`__.
.. _env_vars: .. _env_vars:
@@ -45,6 +46,7 @@ Environment variables
------------------------ ------------------------
Variables that influence kitty behavior Variables that influence kitty behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. envvar:: KITTY_CONFIG_DIRECTORY .. envvar:: KITTY_CONFIG_DIRECTORY
@@ -65,9 +67,9 @@ Variables that influence kitty behavior
.. envvar:: VISUAL .. envvar:: VISUAL
The terminal editor (such as ``vi`` or ``nano``) kitty uses, when, for The terminal based text editor (such as :program:`vi` or :program:`nano`)
instance, opening :file:`kitty.conf` in response to :sc:`edit_config_file`. kitty uses, when, for instance, opening :file:`kitty.conf` in response to
:sc:`edit_config_file`.
.. envvar:: EDITOR .. envvar:: EDITOR
@@ -84,13 +86,41 @@ Variables that influence kitty behavior
is possible for the autodiscovery to fail; the default Wayland XKB mappings is possible for the autodiscovery to fail; the default Wayland XKB mappings
are used in this case. See :pull:`3943` for details. are used in this case. See :pull:`3943` for details.
.. envvar:: SSH_ASKPASS
Specify the program for SSH to ask for passwords. When this is set, :doc:`ssh
kitten </kittens/ssh>` will use this environment variable by default. See
:opt:`askpass <kitten-ssh.askpass>` for details.
.. envvar:: KITTY_CLONE_SOURCE_CODE
Set this to some shell code that will be executed in the cloned window with
:code:`eval` when :ref:`clone-in-kitty <clone_shell>` is used.
.. envvar:: KITTY_CLONE_SOURCE_PATH
Set this to the path of a file that will be sourced in the cloned window when
:ref:`clone-in-kitty <clone_shell>` is used.
.. envvar:: KITTY_DEVELOP_FROM
Set this to the directory path of the kitty source code and its Python code
will be loaded from there. Only works with official binary builds.
Variables that kitty sets when running child programs Variables that kitty sets when running child programs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. envvar:: LANG .. envvar:: LANG
This is set only on macOS, and only if the country and language from the This is only set on macOS. If the country and language from the macOS user
macOS user settings form a valid locale. settings form an invalid locale, it will be set to :code:`en_US.UTF-8`.
.. envvar:: PATH
kitty prepends itself to the PATH of its own environment to ensure the
functions calling :program:`kitty` will work properly.
.. envvar:: KITTY_WINDOW_ID .. envvar:: KITTY_WINDOW_ID
@@ -137,7 +167,7 @@ Variables that kitty sets when running child programs
Set when the :doc:`remote control <remote-control>` facility is enabled and Set when the :doc:`remote control <remote-control>` facility is enabled and
the a socket is used for control via :option:`kitty --listen-on` or :opt:`listen_on`. the a socket is used for control via :option:`kitty --listen-on` or :opt:`listen_on`.
Contains the path to the socket. Avoids needs to use :option:`kitty @ --to` when Contains the path to the socket. Avoid the need to use :option:`kitty @ --to` when
issuing remote control commands. issuing remote control commands.
@@ -158,10 +188,28 @@ Variables that kitty sets when running child programs
.. envvar:: KITTY_COMMON_OPTS .. envvar:: KITTY_COMMON_OPTS
Set with the values of some common kitty options when running Set with the values of some common kitty options when running
kittens, so kittens can use them without needing to load kitty.conf. kittens, so kittens can use them without needing to load :file:`kitty.conf`.
.. envvar:: KITTY_SHELL_INTEGRATION .. envvar:: KITTY_SHELL_INTEGRATION
Set when enabling :ref:`shell_integration`. It is automatically removed by Set when enabling :ref:`shell_integration`. It is automatically removed by
the shell integration scripts. the shell integration scripts.
.. envvar:: ZDOTDIR
Set when enabling :ref:`shell_integration` with :program:`zsh`, allowing
:program:`zsh` to automatically load the integration script.
.. envvar:: XDG_DATA_DIRS
Set when enabling :ref:`shell_integration` with :program:`fish`, allowing
:program:`fish` to automatically load the integration script.
.. envvar:: ENV
Set when enabling :ref:`shell_integration` with :program:`bash`, allowing
:program:`bash` to automatically load the integration script.

View File

@@ -31,6 +31,7 @@ Some programs and libraries that use the kitty graphics protocol:
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with * `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with
image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_ image previews, see this `PR <https://github.com/ranger/ranger/pull/1077>`_
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images * :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
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol * `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 * `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system
information tool information tool

View File

@@ -156,7 +156,6 @@ exec_kitty() {
} }
main() { main() {
[ -n "$KITTY_WINDOW_ID" ] && die "You should not try to update kitty from within kitty itself. For best results, quit all kitty instances and run this script from another terminal"
detect_os detect_os
parse_args "$@" parse_args "$@"
detect_network_tool detect_network_tool

View File

@@ -4,8 +4,8 @@ Integrations with other tools
================================ ================================
kitty provides extremely powerful interfaces such as :doc:`remote-control` and kitty provides extremely powerful interfaces such as :doc:`remote-control` and
:doc:`kittens/custom` and :doc:`kittens/icat` :doc:`kittens/custom` and :doc:`kittens/icat` that allow it to be integrated
that allow it to be integrated with other tools seamlessly. with other tools seamlessly.
Image and document viewers Image and document viewers
@@ -30,19 +30,22 @@ Display markdown files nicely formatted with images in the terminal
`ranger <https://github.com/ranger/ranger>`_ `ranger <https://github.com/ranger/ranger>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A terminal file manager, with previews of file contents powered by kitty's graphics protocol. A terminal file manager, with previews of file contents powered by kitty's
graphics protocol.
.. _tool_nnn: .. _tool_nnn:
`nnn <https://github.com/jarun/nnn/>`_ `nnn <https://github.com/jarun/nnn/>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another terminal file manager, with previews of file contents powered by kitty's graphics protocol. Another terminal file manager, with previews of file contents powered by kitty's
graphics protocol.
.. _tool_hunter: .. _tool_hunter:
`hunter <https://github.com/rabite0/hunter>`_ `hunter <https://github.com/rabite0/hunter>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Another terminal file manager, with previews of file contents powered by kitty's graphics protocol. Another terminal file manager, with previews of file contents powered by kitty's
graphics protocol.
.. _tool_koneko: .. _tool_koneko:
@@ -61,8 +64,8 @@ View images in the terminal, similar to kitty's icat.
`nb <https://github.com/xwmx/nb>`_ `nb <https://github.com/xwmx/nb>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
command line and local web note-taking, bookmarking, archiving, and Command line and local web note-taking, bookmarking, archiving, and knowledge
knowledge base application that uses kitty's graphics protocol for images. base application that uses kitty's graphics protocol for images.
.. _tool_w3m: .. _tool_w3m:
@@ -75,9 +78,9 @@ images.
`timg <https://github.com/hzeller/timg>`_ `timg <https://github.com/hzeller/timg>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A terminal image and video viewer, that displays static and animated A terminal image and video viewer, that displays static and animated images or
images or plays videos. Fast multi-threaded loading, JPEG exif rotation, plays videos. Fast multi-threaded loading, JPEG exif rotation, grid view and
grid view and connecting to the webcam make it a versatile terminal utility. connecting to the webcam make it a versatile terminal utility.
System and data visualisation tools System and data visualisation tools
@@ -87,7 +90,8 @@ System and data visualisation tools
`neofetch <https://github.com/dylanaraps/neofetch>`_ `neofetch <https://github.com/dylanaraps/neofetch>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A command line system information tool that shows images using kitty's graphics protocol A command line system information tool that shows images using kitty's graphics
protocol
.. _tool_matplotlib: .. _tool_matplotlib:
@@ -105,16 +109,16 @@ Show images from Julia directly in kitty
`euporie <https://github.com/joouha/euporie>`_ `euporie <https://github.com/joouha/euporie>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A text-based user interface for running and editing Jupyter notebooks, A text-based user interface for running and editing Jupyter notebooks, powered
powered by kitty's graphics protocol for displaying plots by kitty's graphics protocol for displaying plots
.. _tool_gnuplot: .. _tool_gnuplot:
`gnuplot <http://www.gnuplot.info/>`_ `gnuplot <http://www.gnuplot.info/>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A graphing and data visualization tool that can be made to display its A graphing and data visualization tool that can be made to display its output in
output in kitty with the following bash snippet: kitty with the following bash snippet:
.. code-block:: sh .. code-block:: sh
@@ -171,26 +175,28 @@ Run applications on your system with fuzzy find inside a kitty window
Editor integration Editor integration
----------------------- -----------------------
|kitty| can be integrated into many different terminal editors to add features |kitty| can be integrated into many different terminal based text editors to add
such a split windows, previews, REPLs etc. features such a split windows, previews, REPLs etc.
.. tool_kakoune: .. tool_kakoune:
`kakoune <https://kakoune.org/>`_ `kakoune <https://kakoune.org/>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
integrates with kitty to use native kitty windows for its windows/panels and REPLs. Integrates with kitty to use native kitty windows for its windows/panels and
REPLs.
.. tool_vim_slime: .. tool_vim_slime:
`vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_ `vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
uses kitty remote control for a Lisp REPL. Uses kitty remote control for a Lisp REPL.
.. tool_vim_kitty_navigator: .. tool_vim_kitty_navigator:
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_ `vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys. Allows you to navigate seamlessly between vim and kitty splits using a
consistent set of hotkeys.
.. tool_vim_test: .. tool_vim_test:
@@ -202,7 +208,7 @@ Allows easily running tests in a terminal window
`hologram.nvim <https://github.com/edluffy/hologram.nvim>`_ `hologram.nvim <https://github.com/edluffy/hologram.nvim>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Terminal image viewer for nvim Terminal image viewer for Neovim
Scrollback manipulation Scrollback manipulation
@@ -228,21 +234,21 @@ Miscellaneous
`kitty-smart-tab <https://github.com/yurikhan/kitty-smart-tab>`_ `kitty-smart-tab <https://github.com/yurikhan/kitty-smart-tab>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
use keys to either control tabs or pass them onto running applications if Use keys to either control tabs or pass them onto running applications if no
no tabs are present tabs are present
.. tool_kitty_smart_scroll: .. tool_kitty_smart_scroll:
`kitty-smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_ `kitty-smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
use keys to either scroll or pass them onto running applications if Use keys to either scroll or pass them onto running applications if no
no scrollback buffer is present scrollback buffer is present
.. tool_kitti3: .. tool_kitti3:
`kitti3 <https://github.com/LandingEllipse/kitti3>`_ `kitti3 <https://github.com/LandingEllipse/kitti3>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
allow using kitty as a drop-down terminal under the i3 window manager Allow using kitty as a drop-down terminal under the i3 window manager
.. tool_weechat_hints: .. tool_weechat_hints:

View File

@@ -37,6 +37,7 @@ In addition to kitty, this protocol is also implemented in:
* The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__ * The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__
* The `notcurses library * The `notcurses library
<https://github.com/dankamongmen/notcurses/issues/2131>`__ <https://github.com/dankamongmen/notcurses/issues/2131>`__
* The `neovim text editor <https://github.com/neovim/neovim/pull/18181>`__
* The `kakoune text editor <https://github.com/mawww/kakoune/issues/4103>`__ * The `kakoune text editor <https://github.com/mawww/kakoune/issues/4103>`__
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__ * The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
@@ -377,7 +378,7 @@ An application can query the terminal for support of this protocol by sending
the escape code querying for the :ref:`current progressive enhancement the escape code querying for the :ref:`current progressive enhancement
<progressive_enhancement>` status <progressive_enhancement>` status
followed by request for the `primary device attributes followed by request for the `primary device attributes
<https://vt100.net/docs/vt510-rm/DA1.html>`. If an answer for the device <https://vt100.net/docs/vt510-rm/DA1.html>`__. If an answer for the device
attributes is received without getting back an answer for the progressive attributes is received without getting back an answer for the progressive
enhancement the terminal does not support this protocol. enhancement the terminal does not support this protocol.

View File

@@ -3,18 +3,21 @@ broadcast
*Type text in all kitty windows simultaneously* *Type text in all kitty windows simultaneously*
The ``broadcast`` kitten can be used to type text simultaneously in The ``broadcast`` kitten can be used to type text simultaneously in all
all kitty windows (or a subset as desired). :term:`kitty windows <window>` (or a subset as desired).
To use it, simply create a mapping in :file:`kitty.conf` such as:: To use it, simply create a mapping in :file:`kitty.conf` such as::
map F1 launch --allow-remote-control kitty +kitten broadcast map f1 launch --allow-remote-control kitty +kitten broadcast
Then press the :kbd:`F1` key and whatever you type in the newly created widow Then press the :kbd:`F1` key and whatever you type in the newly created window
will be sent to all kitty windows. will be sent to all kitty windows.
You can use the options described below to control which windows You can use the options described below to control which windows are selected.
are selected.
For example, only broadcast to other windows in the current tab::
map f1 launch --allow-remote-control kitty +kitten broadcast --match-tab state:focused
.. program:: kitty +kitten broadcast .. program:: kitty +kitten broadcast

View File

@@ -1,21 +1,20 @@
Custom kittens Custom kittens
================= =================
You can easily create your own kittens to extend kitty. They are just You can easily create your own kittens to extend kitty. They are just terminal
terminal programs written in Python. When launching a kitten, kitty will programs written in Python. When launching a kitten, kitty will open an overlay
open an overlay window over the current window and optionally pass the window over the current window and optionally pass the contents of the current
contents of the current window/scrollback to the kitten over its :file:`STDIN`. window/scrollback to the kitten over its :file:`STDIN`. The kitten can then
The kitten can then perform whatever actions it likes, just as a normal perform whatever actions it likes, just as a normal terminal program. After
terminal program. After execution of the kitten is complete, it has access execution of the kitten is complete, it has access to the running kitty instance
to the running kitty instance so it can perform arbitrary actions so it can perform arbitrary actions such as closing windows, pasting text, etc.
such as closing windows, pasting text, etc.
Let's see a simple example of creating a kitten. It will ask the user for some Let's see a simple example of creating a kitten. It will ask the user for some
input and paste it into the terminal window. input and paste it into the terminal window.
Create a file in the kitty config folder, :file:`~/.config/kitty/mykitten.py` Create a file in the kitty config directory, :file:`~/.config/kitty/mykitten.py`
(you might need to adjust the path to wherever the kitty config folder is on (you might need to adjust the path to wherever the :ref:`kitty config directory
your machine). <confloc>` is on your machine).
.. code-block:: python .. code-block:: python
@@ -43,11 +42,12 @@ Now in :file:`kitty.conf` add the lines::
map ctrl+k kitten mykitten.py map ctrl+k kitten mykitten.py
Start kitty and press :kbd:`ctrl+k` and you should see the kitten running. Start kitty and press :kbd:`Ctrl+K` and you should see the kitten running.
The best way to develop your own kittens is to modify one of the built in The best way to develop your own kittens is to modify one of the built-in
kittens. Look in the kittens sub-directory of the kitty source code for those. kittens. Look in the `kittens sub-directory
Or see below for a list of :ref:`third-party kittens <external_kittens>`, <https://github.com/kovidgoyal/kitty/tree/master/kittens>`__ of the kitty source
that other kitty users have created. code for those. Or see below for a list of :ref:`third-party kittens
<external_kittens>`, that other kitty users have created.
Passing arguments to kittens Passing arguments to kittens
@@ -60,36 +60,40 @@ You can pass arguments to kittens by defining them in the map directive in
These will be available as the ``args`` parameter in the ``main()`` and These will be available as the ``args`` parameter in the ``main()`` and
``handle_result()`` functions. Note also that the current working directory ``handle_result()`` functions. Note also that the current working directory
of the kitten is set to the working directory of whatever program is of the kitten is set to the working directory of whatever program is running in
running in the active kitty window. The special argument ``@selection`` the active kitty window. The special argument ``@selection`` is replaced by the
is replaced by the currently selected text in the active kitty window. currently selected text in the active kitty window.
Passing the contents of the screen to the kitten Passing the contents of the screen to the kitten
--------------------------------------------------- ---------------------------------------------------
If you would like your kitten to have access to the contents of the screen If you would like your kitten to have access to the contents of the screen
and/or the scrollback buffer, you just need to add an annotation to the ``handle_result()`` and/or the scrollback buffer, you just need to add an annotation to the
function, telling kitty what kind of input your kitten would like. For example: ``handle_result()`` function, telling kitty what kind of input your kitten would
like. For example:
.. code-block:: py .. code-block:: py
from typing import List
from kitty.boss import Boss
# in main, STDIN is for the kitten process and will contain # in main, STDIN is for the kitten process and will contain
# the contents of the screen # the contents of the screen
def main(args): def main(args: List[str]) -> str:
return sys.stdin.read() return sys.stdin.read()
# in handle_result, STDIN is for the kitty process itself, rather # in handle_result, STDIN is for the kitty process itself, rather
# than the kitten process and should not be read from. # than the kitten process and should not be read from.
from kittens.tui.handler import result_handler from kittens.tui.handler import result_handler
@result_handler(type_of_input='text') @result_handler(type_of_input='text')
def handle_result(args, stdin_data, target_window_id, boss): def handle_result(args: List[str], stdin_data: str, target_window_id: int, boss: Boss) -> None:
pass pass
This will send the plain text of the active window to the kitten's This will send the plain text of the active window to the kitten's
:file:`STDIN`. There are many other types of input you can ask for, :file:`STDIN`. There are many other types of input you can ask for, described in
described in the table below: the table below:
.. table:: Types of input to kittens .. table:: Types of input to kittens
:align: left :align: left
@@ -121,31 +125,35 @@ and ``first_output`` gives the output of the first command currently on screen.
These can also be combined with ``screen`` and ``ansi`` for formatting. These can also be combined with ``screen`` and ``ansi`` for formatting.
.. note:: .. note::
For the types based on the output of a command, For the types based on the output of a command, :ref:`shell_integration` is
:ref:`shell_integration` is required. required.
Using kittens to script kitty, without any terminal UI Using kittens to script kitty, without any terminal UI
----------------------------------------------------------- -----------------------------------------------------------
If you would like your kitten to script kitty, without bothering to write a If you would like your kitten to script kitty, without bothering to write a
terminal program, you can tell the kittens system to run the terminal program, you can tell the kittens system to run the ``handle_result()``
``handle_result()`` function without first running the ``main()`` function. function without first running the ``main()`` function.
For example, here is a kitten that "zooms/unzooms" the current terminal window For example, here is a kitten that "zooms in/zooms out" the current terminal
by switching to the stack layout or back to the previous layout. This is window by switching to the stack layout or back to the previous layout. This is
equivalent to the builtin :ac:`toggle_layout` action. equivalent to the builtin :ac:`toggle_layout` action.
Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py` Create a Python file in the :ref:`kitty config directory <confloc>`,
:file:`~/.config/kitty/zoom_toggle.py`
.. code-block:: py .. code-block:: py
def main(args): from typing import List
from kitty.boss import Boss
def main(args: List[str]) -> str:
pass pass
from kittens.tui.handler import result_handler from kittens.tui.handler import result_handler
@result_handler(no_ui=True) @result_handler(no_ui=True)
def handle_result(args, answer, target_window_id, boss): def handle_result(args: List[str], answer: str, target_window_id: int, boss: Boss) -> None:
tab = boss.active_tab tab = boss.active_tab
if tab is not None: if tab is not None:
if tab.current_layout.name == 'stack': if tab.current_layout.name == 'stack':
@@ -154,7 +162,7 @@ Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
tab.goto_layout('stack') tab.goto_layout('stack')
Now in kitty.conf add:: Now in :file:`kitty.conf` add::
map f11 kitten zoom_toggle.py map f11 kitten zoom_toggle.py
@@ -165,7 +173,7 @@ layout, by simply adding the line::
boss.toggle_fullscreen() boss.toggle_fullscreen()
To the ``handle_result()`` function, above. to the ``handle_result()`` function, above.
.. _send_mouse_event: .. _send_mouse_event:
@@ -173,7 +181,7 @@ To the ``handle_result()`` function, above.
Sending mouse events Sending mouse events
-------------------- --------------------
If the program running in a window is receiving mouse events you can simulate If the program running in a window is receiving mouse events, you can simulate
those using:: those using::
from kitty.fast_data_types import send_mouse_event from kitty.fast_data_types import send_mouse_event
@@ -200,15 +208,15 @@ that type, and will return ``True`` if it sent the event, and ``False`` if not.
Debugging kittens Debugging kittens
-------------------- --------------------
The part of the kitten that runs in ``main()`` is just a normal program and The part of the kitten that runs in ``main()`` is just a normal program and the
the output of print statements will be visible in the kitten window. Or output of print statements will be visible in the kitten window. Or alternately,
alternately, you can use:: you can use::
from kittens.tui.loop import debug from kittens.tui.loop import debug
debug('whatever') debug('whatever')
The ``debug()`` function is just like ``print()`` except that the output The ``debug()`` function is just like ``print()`` except that the output will
will appear in the ``STDOUT`` of the kitty process inside which the kitten is appear in the ``STDOUT`` of the kitty process inside which the kitten is
running. running.
The ``handle_result()`` part of the kitten runs inside the kitty process. The ``handle_result()`` part of the kitten runs inside the kitty process.
@@ -216,12 +224,13 @@ The output of print statements will go to the ``STDOUT`` of the kitty process.
So if you run kitty from another kitty instance, the output will be visible So if you run kitty from another kitty instance, the output will be visible
in the first kitty instance. in the first kitty instance.
Adding options to kittens Adding options to kittens
---------------------------- ----------------------------
If you would like to use kitty's config framework to make your kittens If you would like to use kitty's config framework to make your kittens
configurable, you will need some boilerplate. In the directory configurable, you will need some boilerplate. Put the following files in the
of your kitten make the following files. directory of your kitten.
:file:`kitten_options_definition.py` :file:`kitten_options_definition.py`
@@ -311,8 +320,9 @@ You can parse and read the options in your kitten using the following code:
opts.config_overrides = overrides opts.config_overrides = overrides
return opts return opts
See the code for the builtin diff kitten for examples of creating more options See `the code <https://github.com/kovidgoyal/kitty/tree/master/kittens/diff>`__
and keyboard shortcuts. for the builtin :doc:`diff kitten </kittens/diff>` for examples of creating more
options and keyboard shortcuts.
.. _external_kittens: .. _external_kittens:
@@ -320,7 +330,8 @@ Kittens created by kitty users
--------------------------------------------- ---------------------------------------------
`vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_ `vim-kitty-navigator <https://github.com/knubie/vim-kitty-navigator>`_
Allows you to navigate seamlessly between vim and kitty splits using a consistent set of hotkeys. Allows you to navigate seamlessly between vim and kitty splits using a
consistent set of hotkeys.
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_ `smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
Makes the kitty scroll bindings work in full screen applications Makes the kitty scroll bindings work in full screen applications

View File

@@ -12,8 +12,8 @@ Major Features
* Displays diffs side-by-side in the kitty terminal * Displays diffs side-by-side in the kitty terminal
* Does syntax highlighting of the displayed diffs, asynchronously, for maximum * Does syntax highlighting of the displayed diffs, asynchronously, for
speed maximum speed
* Displays images as well as text diffs, even over SSH * Displays images as well as text diffs, even over SSH
@@ -31,11 +31,11 @@ Major Features
Installation Installation
--------------- ---------------
Simply :ref:`install kitty <quickstart>`. You also need Simply :ref:`install kitty <quickstart>`. You also need to have either the `git
to have either the `git <https://git-scm.com/>`_ program or the ``diff`` program <https://git-scm.com/>`__ program or the :program:`diff` program installed.
installed. Additionally, for syntax highlighting to work, Additionally, for syntax highlighting to work, `pygments
`pygments <https://pygments.org/>`_ must be installed (note that pygments is <https://pygments.org/>`__ must be installed (note that pygments is included in
included in the official kitty binary builds). the official kitty binary builds).
Usage Usage
@@ -45,9 +45,10 @@ In the kitty terminal, run::
kitty +kitten diff file1 file2 kitty +kitten diff file1 file2
to see the diff between file1 and file2. to see the diff between :file:`file1` and :file:`file2`.
Create an alias in your shell's startup file to shorten the command, for example: Create an alias in your shell's startup file to shorten the command, for
example:
.. code-block:: sh .. code-block:: sh
@@ -67,20 +68,20 @@ Keyboard controls
========================= =========================== ========================= ===========================
Action Shortcut Action Shortcut
========================= =========================== ========================= ===========================
Quit :kbd:`q`, :kbd:`ctrl+c`, :kbd:`Esc` Quit :kbd:`Q`, :kbd:`Ctrl+C`, :kbd:`Esc`
Scroll line up :kbd:`k`, :kbd:`Up` Scroll line up :kbd:`K`, :kbd:`Up`
Scroll line down :kbd:`j`, :kbd:`Down` Scroll line down :kbd:`J`, :kbd:`Down`
Scroll page up :kbd:`PgUp` Scroll page up :kbd:`PgUp`
Scroll page down :kbd:`PgDn` Scroll page down :kbd:`PgDn`
Scroll to top :kbd:`Home` Scroll to top :kbd:`Home`
Scroll to bottom :kbd:`End` Scroll to bottom :kbd:`End`
Scroll to next page :kbd:`Space`, :kbd:`PgDn` Scroll to next page :kbd:`Space`, :kbd:`PgDn`
Scroll to previous page :kbd:`PgUp` Scroll to previous page :kbd:`PgUp`
Scroll to next change :kbd:`n` Scroll to next change :kbd:`N`
Scroll to previous change :kbd:`p` Scroll to previous change :kbd:`P`
Increase lines of context :kbd:`+` Increase lines of context :kbd:`+`
Decrease lines of context :kbd:`-` Decrease lines of context :kbd:`-`
All lines of context :kbd:`a` All lines of context :kbd:`A`
Restore default context :kbd:`=` Restore default context :kbd:`=`
Search forwards :kbd:`/` Search forwards :kbd:`/`
Search backwards :kbd:`?` Search backwards :kbd:`?`
@@ -93,7 +94,7 @@ Scroll to previous match :kbd:`<`, :kbd:`,`
Integrating with git Integrating with git
----------------------- -----------------------
Add the following to `~/.gitconfig`: Add the following to :file:`~/.gitconfig`:
.. code-block:: ini .. code-block:: ini
@@ -119,24 +120,23 @@ Why does this work only in kitty?
---------------------------------------- ----------------------------------------
The diff kitten makes use of various features that are :doc:`kitty only The diff kitten makes use of various features that are :doc:`kitty only
</protocol-extensions>`, such as the :doc:`kitty graphics protocol </protocol-extensions>`, such as the :doc:`kitty graphics protocol
</graphics-protocol>`, the :doc:`extended keyboard protocol </graphics-protocol>`, the :doc:`extended keyboard protocol
</keyboard-protocol>`, etc. It also leverages terminal program </keyboard-protocol>`, etc. It also leverages terminal program infrastructure
infrastructure I created for all of kitty's other kittens to reduce the amount I created for all of kitty's other kittens to reduce the amount of code needed
of code needed (the entire implementation is under 2000 lines of code). (the entire implementation is under 2000 lines of code).
And fundamentally, it's kitty only because I wrote it for myself, and I am And fundamentally, it's kitty only because I wrote it for myself, and I am
highly unlikely to use any other terminals :) highly unlikely to use any other terminals :)
Configuration Configuration
------------------------ ------------------------
You can configure the colors used, keyboard shortcuts, the diff implementation, You can configure the colors used, keyboard shortcuts, the diff implementation,
the default lines of context, etc. by creating a :file:`diff.conf` file in the default lines of context, etc. by creating a :file:`diff.conf` file in your
your :ref:`kitty config folder <confloc>`. See below for the supported :ref:`kitty config folder <confloc>`. See below for the supported configuration
configuration directives. directives.
.. include:: /generated/conf-kitten-diff.rst .. include:: /generated/conf-kitten-diff.rst
@@ -145,7 +145,6 @@ configuration directives.
.. include:: /generated/cli-kitten-diff.rst .. include:: /generated/cli-kitten-diff.rst
Sample diff.conf Sample diff.conf
----------------- -----------------

View File

@@ -1,9 +1,9 @@
Hints Hints
========== ==========
|kitty| has a *hints mode* to select and act on arbitrary text snippets currently |kitty| has a *hints mode* to select and act on arbitrary text snippets
visible on the screen. For example, you can press :sc:`open_url` currently visible on the screen. For example, you can press :sc:`open_url`
to choose any URL visible on the screen and then open it using your system to choose any URL visible on the screen and then open it using your default web
browser. browser.
.. figure:: ../screenshots/hints_mode.png .. figure:: ../screenshots/hints_mode.png
@@ -13,25 +13,29 @@ browser.
URL hints mode URL hints mode
Similarly, you can press :sc:`insert_selected_path` to Similarly, you can press :sc:`insert_selected_path` to select anything that
select anything that looks like a path or filename and then insert it into the looks like a path or filename and then insert it into the terminal, very useful
terminal, very useful for picking files from the output of a ``git`` or ``ls`` command and for picking files from the output of a :program:`git` or :program:`ls` command
adding them to the command line for the next command. and adding them to the command line for the next command.
You can also press :sc:`goto_file_line` to select anything that looks You can also press :sc:`goto_file_line` to select anything that looks like a
like a path or filename followed by a colon and a line number and open path or filename followed by a colon and a line number and open the file in
the file in vim at the specified line number. The patterns and editor :program:`vim` at the specified line number. The patterns and editor to be used
to be used can be modified using options passed to the kitten. For example:: can be modified using options passed to the kitten. For example::
map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path} map ctrl+g kitten hints --type=linenum --linenum-action=tab nvim +{line} {path}
will open the selected file in a new tab inside neovim when you press will open the selected file in a new tab inside `Neovim <https://neovim.io/>`__
:kbd:`ctrl+g`. when you press :kbd:`Ctrl+G`.
Pressing :sc:`open_selected_hyperlink` will open hyperlinks, i.e. a URL Pressing :sc:`open_selected_hyperlink` will open :term:`hyperlinks`, i.e. a URL
that has been marked as such by the program running in the terminal, that has been marked as such by the program running in the terminal,
for example, by ``ls --hyperlink=auto``. You can also :doc:`customize what actions are for example, by ``ls --hyperlink=auto``. If :program:`ls` comes with your OS
taken for different types of URLs <../open_actions>`. does not support hyperlink, you may need to install `GNU Coreutils
<https://www.gnu.org/software/coreutils/>`__.
You can also :doc:`customize what actions are taken for different types of URLs
<../open_actions>`.
.. note:: If there are more hints than letters, hints will use multiple .. note:: If there are more hints than letters, hints will use multiple
letters. In this case, when you press the first letter, only hints letters. In this case, when you press the first letter, only hints
@@ -48,13 +52,12 @@ snippets. See :sc:`insert_selected_path <insert_selected_path>` for examples.
Completely customizing the matching and actions of the kitten Completely customizing the matching and actions of the kitten
--------------------------------------------------------------- ---------------------------------------------------------------
The hints kitten supports writing simple python scripts that can be used to The hints kitten supports writing simple Python scripts that can be used to
completely customize how it finds matches and what happens when a match is completely customize how it finds matches and what happens when a match is
selected. This allows the hints kitten to provide the user interface, while selected. This allows the hints kitten to provide the user interface, while you
you can provide the logic for finding matches and performing actions on them. can provide the logic for finding matches and performing actions on them. This
This is best illustrated with an example. Create the file is best illustrated with an example. Create the file :file:`custom-hints.py` in
:file:`custom-hints.py` in the kitty config directory with the following the :ref:`kitty config directory <confloc>` with the following contents:
contents:
.. code-block:: python .. code-block:: python
@@ -98,9 +101,10 @@ look it up in the Google dictionary.
.. note:: .. note::
To avoid having to specify the same command line options on every invocation, To avoid having to specify the same command line options on every
you can use the :opt:`action_alias` option in :file:`kitty.conf`, creating aliases invocation, you can use the :opt:`action_alias` option in
that have common sets of options. For example:: :file:`kitty.conf`, creating aliases that have common sets of options.
For example::
action_alias myhints kitten hints --alphabet qfjdkslaureitywovmcxzpq1234567890 action_alias myhints kitten hints --alphabet qfjdkslaureitywovmcxzpq1234567890
map f1 myhints --customize-processing custom-hints.py map f1 myhints --customize-processing custom-hints.py

View File

@@ -1,11 +1,10 @@
Hyperlinked grep Hyperlinked grep
================= =================
This kitten allows you to search your files using `ripgrep This kitten allows you to search your files using `ripgrep
<https://github.com/BurntSushi/ripgrep>`_ and open the results <https://github.com/BurntSushi/ripgrep>`__ and open the results directly in your
directly in your favorite editor in the terminal, at the line containing favorite editor in the terminal, at the line containing the search result,
the search result, simply by clicking on the result you want. simply by clicking on the result you want.
.. versionadded:: 0.19.0 .. versionadded:: 0.19.0
@@ -25,19 +24,19 @@ following contents:
mime text/* mime text/*
action launch --type=overlay ${EDITOR} ${FILE_PATH} action launch --type=overlay ${EDITOR} ${FILE_PATH}
Now, run a search with:: Now, run a search with::
kitty +kitten hyperlinked_grep something kitty +kitten hyperlinked_grep something
Hold down the :kbd:`ctrl+shift` keys and click on any of the Hold down the :kbd:`Ctrl+Shift` keys and click on any of the result lines, to
result lines, to open the file in vim at the matching line. If open the file in :program:`vim` at the matching line. If you use some editor
you use some editor other than vim, you should adjust the other than :program:`vim`, you should adjust the :file:`open-actions.conf` file
:file:`open-actions.conf` file accordingly. accordingly.
Finally, add an alias to your shell's rc files to invoke the kitten as ``hg``:: Finally, add an alias to your shell's rc files to invoke the kitten as
:command:`hg`::
alias hg='kitty +kitten hyperlinked_grep' alias hg="kitty +kitten hyperlinked_grep"
You can now run searches with:: You can now run searches with::
@@ -45,13 +44,13 @@ You can now run searches with::
hg some-search-term hg some-search-term
If you want to enable completion, for the kitten, you can delegate completion If you want to enable completion, for the kitten, you can delegate completion
to rg. How to do that varies based on the shell: to :program:`rg`. How to do that varies based on the shell:
.. tab:: zsh .. tab:: zsh
Instead of using an alias create a simple wrapper script named Instead of using an alias, create a simple wrapper script named
:file:`hg` somewhere in your ``PATH``: :program:`hg` somewhere in your :envvar:`PATH`:
.. code-block:: sh .. code-block:: sh
@@ -64,22 +63,23 @@ to rg. How to do that varies based on the shell:
.. tab:: fish .. tab:: fish
You can combine both the aliasing/wrapping and pointing fish You can combine both the aliasing/wrapping and pointing fish to ripgrep's
to rg's autocompletion with a fish "wrapper" function in your :file:`config.fish`: autocompletion with a fish wrapper function in your :file:`config.fish`
or :file:`~/.config/fish/functions/hg.fish`:
.. code-block:: sh .. code-block:: fish
function hg --wraps rg; kitty +kitten hyperlinked_grep $argv; end function hg --wraps rg; kitty +kitten hyperlinked_grep $argv; end
To learn more about kitty's powerful framework for customizing URL click To learn more about kitty's powerful framework for customizing URL click
actions, :doc:`see here </open_actions>`. actions, see :doc:`here </open_actions>`.
Hopefully, someday this functionality will make it into some `upstream grep Hopefully, someday this functionality will make it into some `upstream grep
<https://github.com/BurntSushi/ripgrep/issues/665>`_ <https://github.com/BurntSushi/ripgrep/issues/665>`__ program directly removing
program directly removing the need for this kitten. the need for this kitten.
.. note:: .. note::
While you can pass any of ripgrep's comand line options to the kitten and While you can pass any of ripgrep's comand line options to the kitten and
they will be forwarded to rg, do not use options that change the output they will be forwarded to :program:`rg`, do not use options that change the
formatting as the kitten works by parsing the output from ripgrep. output formatting as the kitten works by parsing the output from ripgrep.

View File

@@ -9,8 +9,8 @@ terminal. Using it is as simple as::
kitty +kitten icat image.jpeg kitty +kitten icat image.jpeg
It supports all image types supported by `ImageMagick It supports all image types supported by `ImageMagick
<https://www.imagemagick.org>`_. It even works over SSH. For details, see <https://www.imagemagick.org>`__. It even works over SSH. For details, see the
the :doc:`kitty graphics protocol </graphics-protocol>`. :doc:`kitty graphics protocol </graphics-protocol>`.
You might want to create an alias in your shell's configuration files:: You might want to create an alias in your shell's configuration files::
@@ -20,14 +20,14 @@ Then you can simply use ``icat image.png`` to view images.
.. note:: .. note::
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to `ImageMagick <https://www.imagemagick.org>`__ must be installed for icat
work. kitten to work.
.. note:: .. note::
kitty's image display protocol may not work when used within a terminal kitty's image display protocol may not work when used within a terminal
multiplexer such as ``screen`` or ``tmux``, depending on whether the multiplexer such as :program:`screen` or :program:`tmux`, depending on
multiplexer has added support for it or not. whether the multiplexer has added support for it or not.
.. program:: kitty +kitten icat .. program:: kitty +kitten icat
@@ -35,18 +35,19 @@ 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 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`, from inside other programs to display images. In particular, :option:`--place`,
:option:`--detect-support`, :option:`--silent` and :option:`--print-window-size`. :option:`--detect-support`, :option:`--silent` and
:option:`--print-window-size`.
If you are trying to integrate icat into a complex program like a file If you are trying to integrate icat into a complex program like a file manager
manager or editor, there are a few things to keep in mind. icat works by or editor, there are a few things to keep in mind. icat works by communicating
communicating over the TTY device, it both writes to and reads from the TTY. over the TTY device, it both writes to and reads from the TTY. So it is
So it is imperative that while it is running the host program does not do imperative that while it is running the host program does not do any TTY I/O.
any TTY I/O. Any key presses or other input from the user on the TTY device Any key presses or other input from the user on the TTY device will be
will be discarded. At a minimum, you should use the :option:`--silent` and discarded. At a minimum, you should use the :option:`--silent` and
:option:`--transfer-mode` command line arguments. To be :option:`--transfer-mode` command line arguments. To be really robust you should
really robust you should consider writing proper support for the consider writing proper support for the :doc:`kitty graphics protocol
:doc:`../graphics-protocol` in the program instead. Nowadays there are many </graphics-protocol>` in the program instead. Nowadays there are many libraries
libraries that have support for it. that have support for it.
.. include:: /generated/cli-kitten-icat.rst .. include:: /generated/cli-kitten-icat.rst

View File

@@ -4,8 +4,8 @@ Draw a GPU accelerated dock panel on your desktop
.. highlight:: sh .. highlight:: sh
You can use this kitten to draw a GPU accelerated panel on the edge You can use this kitten to draw a GPU accelerated panel on the edge of your
of your screen, that shows the output from an arbitrary terminal program. screen, that shows the output from an arbitrary terminal program.
It is useful for showing status information or notifications on your desktop It is useful for showing status information or notifications on your desktop
using terminal programs instead of GUI toolkits. using terminal programs instead of GUI toolkits.
@@ -32,8 +32,8 @@ Using this kitten is simple, for example::
kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s' kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s'
This will show ``Hello, world.`` at the top edge of your screen for five This will show ``Hello, world.`` at the top edge of your screen for five
seconds. Here the terminal program we are running is ``sh`` with a script to seconds. Here the terminal program we are running is :program:`sh` with a script
print out ``Hello, world!``. You can make the terminal program as complex as to print out ``Hello, world!``. You can make the terminal program as complex as
you like, as demonstrated in the screenshot above. you like, as demonstrated in the screenshot above.

View File

@@ -1,18 +1,18 @@
Query terminal Query terminal
================= =================
Used to query kitty from terminal programs about version, values of various This kitten is used to query |kitty| from terminal programs about version, values
runtime options controlling its features, etc. of various runtime options controlling its features, etc.
The querying is done using the (*semi*) standard XTGETTCAP escape sequence The querying is done using the (*semi*) standard XTGETTCAP escape sequence
pioneered by XTerm, so it works over SSH as well. The downside is that it pioneered by xterm, so it works over SSH as well. The downside is that it is
is slow, since it requires a roundtrip to the terminal emulator and back. slow, since it requires a roundtrip to the terminal emulator and back.
If you want to do some of the same querying in your terminal program without If you want to do some of the same querying in your terminal program without
depending on the kitten, you can do so, by processing the same escape codes. depending on the kitten, you can do so, by processing the same escape codes.
Search `this page <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html>`_ Search `this page <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html>`__
for *XTGETTCAP* to see the syntax for the escape code and read the source for *XTGETTCAP* to see the syntax for the escape code and read the source of
of this kitten to find the values of the keys for the various queries. this kitten to find the values of the keys for the various queries.
.. include:: ../generated/cli-kitten-query_terminal.rst .. include:: ../generated/cli-kitten-query_terminal.rst

View File

@@ -1,12 +1,12 @@
Remote files Remote files
============== ==============
|kitty| has the ability to easily *Edit*, *Open* or *Download* files |kitty| has the ability to easily *Edit*, *Open* or *Download* files from a
from a computer into which you are SSHed. In your SSH session run:: computer into which you are SSHed. In your SSH session run::
ls --hyperlink=auto ls --hyperlink=auto
Then hold down :kbd:`ctrl+shift` and click the name of the file. Then hold down :kbd:`Ctrl+Shift` and click the name of the file.
.. figure:: ../screenshots/remote_file.png .. figure:: ../screenshots/remote_file.png
:alt: Remote file actions :alt: Remote file actions
@@ -19,23 +19,26 @@ Then hold down :kbd:`ctrl+shift` and click the name of the file.
to *Edit* it in which case kitty will download it and open it locally in your to *Edit* it in which case kitty will download it and open it locally in your
:envvar:`EDITOR`. As you make changes to the file, they are automatically :envvar:`EDITOR`. As you make changes to the file, they are automatically
transferred to the remote computer. Note that this happens without needing transferred to the remote computer. Note that this happens without needing
to install *any* special software on the server, beyond ``ls`` that supports to install *any* special software on the server, beyond :program:`ls` that
hyperlinks. supports hyperlinks.
.. seealso:: See the :doc:`transfer` kitten .. seealso:: See the :doc:`transfer` kitten
.. versionadded:: 0.19.0 .. versionadded:: 0.19.0
.. note:: .. note::
Nested SSH sessions are not supported. The kitten will always try to copy For best results, use this kitten with the :doc:`ssh kitten <./ssh>`.
remote files from the first SSH host. This is because there is no way for Otherwise, nested SSH sessions are not supported. The kitten will always try to copy
remote files from the first SSH host. This is because, without the ssh
kitten, there is no way for
|kitty| to detect and follow a nested SSH session robustly. Use the |kitty| to detect and follow a nested SSH session robustly. Use the
:doc:`transfer` kitten for such situations. :doc:`transfer` kitten for such situations.
.. note:: .. note::
If you have not setup automatic password-less SSH access, then, when If you have not setup automatic password-less SSH access, and are not using
editing starts you will be asked to enter your password just once, the ssh kitten, then, when editing
thereafter the SSH connection will be re-used. starts you will be asked to enter your password just once, thereafter the SSH
connection will be re-used.
Similarly, you can choose to save the file to the local computer or download Similarly, you can choose to save the file to the local computer or download
and open it in its default file handler. and open it in its default file handler.

View File

@@ -15,28 +15,27 @@ Truly convenient SSH
Automatic shell integration, file transfer and reuse of connections Automatic shell integration, file transfer and reuse of connections
The ssh kitten allows you to login easily to remote hosts, and automatically The ssh kitten allows you to login easily to remote hosts, and automatically
setup the environment there to be as comfortable as your local shell. You setup the environment there to be as comfortable as your local shell. You can
can specify environment variables to set on the remote host and specify environment variables to set on the remote host and files to copy there,
files to copy there, making your remote experience just like your making your remote experience just like your local shell. Additionally, it
local shell. Additionally, it automatically sets up :ref:`shell_integration` on automatically sets up :ref:`shell_integration` on the remote host and copies the
the remote host and copies the kitty terminfo database there. kitty terminfo database there.
The ssh kitten is a thin wrapper around the traditional `ssh <https://man.openbsd.org/ssh>`__ The ssh kitten is a thin wrapper around the traditional `ssh <https://man.openbsd.org/ssh>`__
command line program and supports all the same options and arguments and configuration. command line program and supports all the same options and arguments and configuration.
In interactive usage scenarios it is a drop in replacement for ``ssh``. To try it In interactive usage scenarios it is a drop in replacement for :program:`ssh`.
out, simply run: To try it out, simply run:
.. code-block:: sh .. code-block:: sh
kitty +kitten ssh some-hostname-to-connect-to kitty +kitten ssh some-hostname-to-connect-to
You should end up at a shell prompt on the remote host, with shell You should end up at a shell prompt on the remote host, with shell integration
integration enabled. If you like it you can add an alias to it in your shell's enabled. If you like it you can add an alias to it in your shell's rc files:
rc files:
.. code-block:: sh .. code-block:: sh
alias s=kitty +kitten ssh alias s="kitty +kitten ssh"
So now you can just type ``s hostname`` to connect. So now you can just type ``s hostname`` to connect.
@@ -44,13 +43,12 @@ If you define a mapping in :file:`kitty.conf` such as::
map f1 new_window_with_cwd map f1 new_window_with_cwd
Then, pressing :kbd:`F1` will open a new window automatically logged Then, pressing :kbd:`F1` will open a new window automatically logged into the
into the same host using the ssh kitten, at the same directory. same host using the ssh kitten, at the same directory.
The ssh kitten can be configured using the :file:`~/.config/kitty/ssh.conf` The ssh kitten can be configured using the :file:`~/.config/kitty/ssh.conf` file
file where you can specify environment variables to set on the remote host where you can specify environment variables to set on the remote host and files
and files to copy from the local to the remote host. Let's see a to copy from the local to the remote host. Let's see a quick example:
quick example:
.. code-block:: conf .. code-block:: conf
@@ -80,8 +78,9 @@ Additionally, you can pass config options on the command line:
The :code:`--kitten` argument can be specified multiple times, with directives The :code:`--kitten` argument can be specified multiple times, with directives
from :file:`ssh.conf`. These are merged with :file:`ssh.conf` as if they were from :file:`ssh.conf`. These are merged with :file:`ssh.conf` as if they were
appended to the end of that file. They apply only to the host being SSHed to appended to the end of that file. They apply only to the host being SSHed to by
by this invocation, so any :opt:`hostname <kitten-ssh.hostname>` directives are ignored. this invocation, so any :opt:`hostname <kitten-ssh.hostname>` directives are
ignored.
.. warning:: .. warning::
@@ -98,8 +97,8 @@ A real world example
Suppose you often SSH into a production server, and you would like to setup Suppose you often SSH into a production server, and you would like to setup
your shell and editor there using your custom settings. However, other people your shell and editor there using your custom settings. However, other people
could SSH in as well and you don't want to clobber their settings. Here is how could SSH in as well and you don't want to clobber their settings. Here is how
this could be achieved using the ssh kitten with zsh and vim as the shell and this could be achieved using the ssh kitten with :program:`zsh` and
editor, respectively: :program:`vim` as the shell and editor, respectively:
.. code-block:: conf .. code-block:: conf
@@ -125,23 +124,24 @@ How it works
The ssh kitten works by having SSH transmit and execute a POSIX sh (or The ssh kitten works by having SSH transmit and execute a POSIX sh (or
:opt:`optionally <kitten-ssh.interpreter>` Python) bootstrap script on the :opt:`optionally <kitten-ssh.interpreter>` Python) bootstrap script on the
remote host using an :opt:`interpreter <kitten-ssh.interpreter>`. This script remote host using an :opt:`interpreter <kitten-ssh.interpreter>`. This script
reads setup data over the tty device, which kitty sends as a base64 encoded reads setup data over the TTY device, which kitty sends as a Base64 encoded
compressed tarball. The script extracts it and places the :opt:`files <kitten-ssh.copy>` compressed tarball. The script extracts it and places the :opt:`files <kitten-ssh.copy>`
and sets the :opt:`environment variables <kitten-ssh.env>` before finally and sets the :opt:`environment variables <kitten-ssh.env>` before finally
launching the :opt:`login shell <kitten-ssh.login_shell>` with :opt:`shell launching the :opt:`login shell <kitten-ssh.login_shell>` with :opt:`shell
integration <kitten-ssh.shell_integration>` enabled. The data is requested by integration <kitten-ssh.shell_integration>` enabled. The data is requested by
the kitten over the TTY with a random one time password. kitty reads the request the kitten over the TTY with a random one time password. kitty reads the request
and if the password matches a password pre-stored in shared memory on the and if the password matches a password pre-stored in shared memory on the
localhost by the kitten, the transmission is allowed. If your OpenSSH version is localhost by the kitten, the transmission is allowed. If your local
>= 8.4 then the data is transmitted instantly without any roundtrip delay. `OpenSSH <https://www.openssh.com/>`__ version is >= 8.4 then the data is
transmitted instantly without any roundtrip delay.
.. note:: .. note::
When connecting to BSD hosts, it is possible the bootstrap script will When connecting to BSD hosts, it is possible the bootstrap script will fail
fail or run slowly, because the default shells are crippled in various ways. or run slowly, because the default shells are crippled in various ways.
Your best bet is to install Python on the remote, make sure the login shell Your best bet is to install Python on the remote, make sure the login shell
is something POSIX sh compliant, and use :code:`python` as the :opt:`interpreter is something POSIX sh compliant, and use :code:`python` as the
<kitten-ssh.interpreter>` in :file:`ssh.conf`. :opt:`interpreter <kitten-ssh.interpreter>` in :file:`ssh.conf`.
.. include:: /generated/conf-kitten-ssh.rst .. include:: /generated/conf-kitten-ssh.rst

View File

@@ -1,8 +1,8 @@
Changing kitty colors Changing kitty colors
======================== ========================
The themes kitten allows you to easily change color themes, from a collection The themes kitten allows you to easily change color themes, from a collection of
of almost two hundred pre-built themes available at `kitty-themes over two hundred pre-built themes available at `kitty-themes
<https://github.com/kovidgoyal/kitty-themes>`_. To use it, simply run:: <https://github.com/kovidgoyal/kitty-themes>`_. To use it, simply run::
kitty +kitten themes kitty +kitten themes
@@ -12,9 +12,9 @@ of almost two hundred pre-built themes available at `kitty-themes
:alt: The themes kitten in action :alt: The themes kitten in action
:width: 600 :width: 600
The kitten allows you to pick a theme, with live previews of the colors. You The kitten allows you to pick a theme, with live previews of the colors. You can
can choose between light and dark themes and search by theme name by just choose between light and dark themes and search by theme name by just typing a
typing a few characters from the name. few characters from the name.
The kitten maintains a list of recently used themes to allow quick switching. The kitten maintains a list of recently used themes to allow quick switching.
@@ -24,14 +24,15 @@ If you want to restore the colors to default, you can do so by choosing the
.. versionadded:: 0.23.0 .. versionadded:: 0.23.0
The themes kitten The themes kitten
How it works How it works
---------------- ----------------
A theme in kitty is just a :file:`.conf` file containing kitty settings. A theme in kitty is just a :file:`.conf` file containing kitty settings.
When you select a theme, the kitten simply copies the :file:`.conf` file When you select a theme, the kitten simply copies the :file:`.conf` file
to :file:`~/.config/kitty/current-theme.conf` and adds an include for to :file:`~/.config/kitty/current-theme.conf` and adds an include for
:file:`current-theme.conf` to :file:`kitty.conf`. It also comments out :file:`current-theme.conf` to :file:`kitty.conf`. It also comments out any
any existing color settings in :file:`kitty.conf` so they do not interfere. existing color settings in :file:`kitty.conf` so they do not interfere.
Once that's done, the kitten sends kitty a signal to make it reload its config. Once that's done, the kitten sends kitty a signal to make it reload its config.
@@ -39,9 +40,9 @@ Using your own themes
----------------------- -----------------------
You can also create your own themes as :file:`.conf` files. Put them in the You can also create your own themes as :file:`.conf` files. Put them in the
:file:`themes` sub-directory of the kitty config directory, usually, :file:`themes` sub-directory of the :ref:`kitty config directory <confloc>`,
:file:`~/.config/kitty/themes` and the kitten will automatically add them to usually, :file:`~/.config/kitty/themes`. The kitten will automatically add them
the list of themes. You can use this to modify the builtin themes, by giving to the list of themes. You can use this to modify the builtin themes, by giving
the conf file the name :file:`Some theme name.conf` to override the builtin the conf file the name :file:`Some theme name.conf` to override the builtin
theme of that name. Note that after doing so you have to run the kitten and theme of that name. Note that after doing so you have to run the kitten and
choose that theme once for your changes to be applied. choose that theme once for your changes to be applied.
@@ -52,13 +53,13 @@ Contributing new themes
If you wish to contribute a new theme to the kitty theme repository, start by If you wish to contribute a new theme to the kitty theme repository, start by
going to the `kitty-themes <https://github.com/kovidgoyal/kitty-themes>`__ going to the `kitty-themes <https://github.com/kovidgoyal/kitty-themes>`__
repository. `Fork it repository. `Fork it
<https://docs.github.com/en/get-started/quickstart/fork-a-repo>`_, and use the <https://docs.github.com/en/get-started/quickstart/fork-a-repo>`__, and use the
file :download:`template.conf file :download:`template.conf
<https://github.com/kovidgoyal/kitty-themes/raw/master/template.conf>` as a <https://github.com/kovidgoyal/kitty-themes/raw/master/template.conf>` as a
template when creating your theme. Once you are satisfied with how it looks, template when creating your theme. Once you are satisfied with how it looks,
`submit a pull request `submit a pull request
<https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request>`_ <https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request>`__
to have your theme merged into the `kitty-themes to have your theme merged into the `kitty-themes
<https://github.com/kovidgoyal/kitty-themes>`__ repository, which will make it <https://github.com/kovidgoyal/kitty-themes>`__ repository, which will make it
available in this kitten automatically. available in this kitten automatically.
@@ -67,12 +68,12 @@ available in this kitten automatically.
Changing the theme non-interactively Changing the theme non-interactively
--------------------------------------- ---------------------------------------
You can specify the theme name as an argument when invoking the kitten You can specify the theme name as an argument when invoking the kitten to have
to have it change to that theme instantly. For example:: it change to that theme instantly. For example::
kitty +kitten themes --reload-in=all Dimmed Monokai kitty +kitten themes --reload-in=all Dimmed Monokai
Will change the theme to ``Dimmed Monokai`` in all running kitty Will change the theme to ``Dimmed Monokai`` in all running kitty instances. See
instances. See below for more details on non-interactive operation. below for more details on non-interactive operation.
.. include:: ../generated/cli-kitten-themes.rst .. include:: ../generated/cli-kitten-themes.rst

View File

@@ -14,16 +14,16 @@ etc. Anywhere you have a terminal device, you can transfer files.
:alt: The transfer kitten at work :alt: The transfer kitten at work
This kitten supports transferring entire directory trees, preserving soft and This kitten supports transferring entire directory trees, preserving soft and
hard links, file permissions, times, etc. It even supports the rsync_ hard links, file permissions, times, etc. It even supports the rsync_ protocol
protocol to transfer only changes to large files. to transfer only changes to large files.
.. seealso:: See the :doc:`remote_file` kitten .. seealso:: See the :doc:`remote_file` kitten
.. note:: .. note::
This kitten (which practically means kitty) must be installed on the other This kitten (which practically means kitty) must be installed on the other
machine as well. If that is not possible you can use the :doc:`remote_file` machine as well. If that is not possible you can use the :doc:`remote_file`
kitten instead. Or write your own script to use the underlying :doc:`file transfer kitten instead. Or write your own script to use the underlying
protocol </file-transfer-protocol>`. :doc:`file transfer protocol </file-transfer-protocol>`.
.. versionadded:: 0.24.0 .. versionadded:: 0.24.0
@@ -32,7 +32,8 @@ Basic usage
--------------- ---------------
In what follows, the *local computer* is the computer running this kitten and In what follows, the *local computer* is the computer running this kitten and
the *remote computer* is the computer connected to the other end of the TTY pipe. the *remote computer* is the computer connected to the other end of the TTY
pipe.
To send a file from the local computer to the remote computer, simply run:: To send a file from the local computer to the remote computer, simply run::
@@ -42,7 +43,7 @@ You will be prompted by kitty for confirmation on allowing the transfer, and if
you grant permission, the file will be copied. you grant permission, the file will be copied.
Similarly, to get a file from the remote computer to the local computer, use Similarly, to get a file from the remote computer to the local computer, use
the :option:`kitty +kitten transfer --direction` option:: the :option:`--direction <kitty +kitten transfer --direction>` option::
kitty +kitten transfer --direction=receive /path/to/remote/file /path/to/destination/on/local/computer kitty +kitten transfer --direction=receive /path/to/remote/file /path/to/destination/on/local/computer
@@ -58,25 +59,25 @@ the fact that you are copying multiple things) it is good practice to always
use a trailing slash when the destination is supposed to be a directory. use a trailing slash when the destination is supposed to be a directory.
Also, when transferring multiple files/directories it is a good idea to Also, when transferring multiple files/directories it is a good idea to
use the :option:`kitty +kitten transfer --confirm-paths` option which will give use the :option:`--confirm-paths <kitty +kitten transfer --confirm-paths>`
you an opportunity to review and confirm the files that will be touched. option which will give you an opportunity to review and confirm the files that
will be touched.
Avoiding the confirmation prompt Avoiding the confirmation prompt
------------------------------------ ------------------------------------
Normally, when you start a file transfer kitty will prompt you for Normally, when you start a file transfer kitty will prompt you for confirmation.
confirmation. This is to ensure that hostile programs running on a remote This is to ensure that hostile programs running on a remote machine cannot
machine cannot read/write files on your computer without your permission. read/write files on your computer without your permission. If the remote machine
If the remote machine is trusted and the connection between your computer is trusted and the connection between your computer and the remote machine is
and the remote machine is secure, then you can disable the confirmation prompt secure, then you can disable the confirmation prompt by:
by:
#. Setting the :opt:`file_transfer_confirmation_bypass` option to some #. Setting the :opt:`file_transfer_confirmation_bypass` option to some password.
password.
#. When invoking the kitten use the :option:`kitty +kitten transfer --permissions-bypass` #. When invoking the kitten use the :option:`--permissions-bypass
to supply the password you set in step one. <kitty +kitten transfer --permissions-bypass>` to supply the password you set
in step one.
.. warning:: Using a password to bypass confirmation means any software running .. warning:: Using a password to bypass confirmation means any software running
on the remote machine could potentially learn that password and use it to on the remote machine could potentially learn that password and use it to
@@ -89,9 +90,10 @@ Delta transfers
----------------------------------- -----------------------------------
This kitten has the ability to use the rsync_ protocol to only transfer the This kitten has the ability to use the rsync_ protocol to only transfer the
differences between files. To turn it on use the :option:`kitty +kitten differences between files. To turn it on use the :option:`--transmit-deltas
transfer --transmit-deltas` option. Note that this will actually be slower when <kitty +kitten transfer --transmit-deltas>` option. Note that this will actually
transferring small files because of round trip overhead, so use with care. be slower when transferring small files because of round trip overhead, so use
with care.
.. include:: ../generated/cli-kitten-transfer.rst .. include:: ../generated/cli-kitten-transfer.rst

View File

@@ -1,27 +1,29 @@
Unicode input Unicode input
================ ================
You can input unicode characters by name, hex code, recently used and even an editable favorites list. You can input Unicode characters by name, hex code, recently used and even an
Press :sc:`input_unicode_character` to start the unicode input widget, shown below. editable favorites list. Press :sc:`input_unicode_character` to start the
unicode input kitten, shown below.
.. figure:: ../screenshots/unicode.png .. figure:: ../screenshots/unicode.png
:alt: A screenshot of the unicode input widget :alt: A screenshot of the unicode input kitten
:align: center :align: center
:width: 100% :width: 100%
A screenshot of the unicode input widget A screenshot of the unicode input kitten
In :guilabel:`Code` mode, you enter a unicode character by typing in the hex code for the In :guilabel:`Code` mode, you enter a Unicode character by typing in the hex
character and pressing enter, for example, type in ``2716`` and press enter to get code for the character and pressing :kbd:`Enter`. For example, type in ``2716``
. You can also choose a character from the list of recently used characters by and press :kbd:`Enter` to get ````. You can also choose a character from the
typing a leading period and then the two character index and pressing Enter. list of recently used characters by typing a leading period ``.`` and then the
The up and down arrow keys can be used to choose the previous and next unicode two character index and pressing :kbd:`Enter`.
symbol respectively. The :kbd:`Up` and :kbd:`Down` arrow keys can be used to choose the previous and
next Unicode symbol respectively.
In :guilabel:`Name` mode you instead type words from the character name and use In :guilabel:`Name` mode you instead type words from the character name and use
the arrow keys/tab to select the character from the displayed matches. You can the :kbd:`ArrowKeys` / :kbd:`Tab` to select the character from the displayed
also type a space followed by a period and the index for the match if you don't matches. You can also type a space followed by a period and the index for the
like to use arrow keys. match if you don't like to use arrow keys.
You can switch between modes using either the keys :kbd:`F1` ... :kbd:`F4` or You can switch between modes using either the keys :kbd:`F1` ... :kbd:`F4` or
:kbd:`Ctrl+1` ... :kbd:`Ctrl+4` or by pressing :kbd:`Ctrl+[` and :kbd:`Ctrl+]` :kbd:`Ctrl+1` ... :kbd:`Ctrl+4` or by pressing :kbd:`Ctrl+[` and :kbd:`Ctrl+]`

View File

@@ -20,8 +20,8 @@ Extend with kittens
kittens/* kittens/*
|kitty| has a framework for easily creating terminal programs that make use of |kitty| has a framework for easily creating terminal programs that make use of
its advanced features. These programs are called kittens. They are used both its advanced features. These programs are called kittens. They are used both to
to add features to |kitty| itself and to create useful standalone programs. add features to |kitty| itself and to create useful standalone programs.
Some prominent kittens: Some prominent kittens:
:doc:`icat <kittens/icat>` :doc:`icat <kittens/icat>`
@@ -33,8 +33,8 @@ Some prominent kittens:
images images
:doc:`Unicode Input <kittens/unicode_input>` :doc:`Unicode input <kittens/unicode_input>`
Easily input arbitrary unicode characters in |kitty| by name or hex code. Easily input arbitrary Unicode characters in |kitty| by name or hex code.
:doc:`Hints <kittens/hints>` :doc:`Hints <kittens/hints>`
@@ -48,29 +48,31 @@ Some prominent kittens:
:doc:`Transfer files <kittens/transfer>` :doc:`Transfer files <kittens/transfer>`
Transfer files and directories seamlessly and easily from remote machines over your existing Transfer files and directories seamlessly and easily from remote machines
SSH sessions with a simple command. over your existing SSH sessions with a simple command.
:doc:`Hyperlinked grep <kittens/hyperlinked_grep>` :doc:`Hyperlinked grep <kittens/hyperlinked_grep>`
Search your files using `ripgrep <https://github.com/BurntSushi/ripgrep>`_ Search your files using `ripgrep <https://github.com/BurntSushi/ripgrep>`__
and open the results directly in your favorite editor in the terminal, and open the results directly in your favorite editor in the terminal,
at the line containing the search result, simply by clicking on the result you want. at the line containing the search result, simply by clicking on the result
you want.
:doc:`Broadcast <kittens/broadcast>` :doc:`Broadcast <kittens/broadcast>`
Type in one :term:`kitty window <window>` and have it broadcast to all (or a subset) of Type in one :term:`kitty window <window>` and have it broadcast to all (or a
other :term:`kitty windows <window>`. subset) of other :term:`kitty windows <window>`.
:doc:`SSH <kittens/ssh>` :doc:`SSH <kittens/ssh>`
SSH with automatic shell integration, connection re-use for low latency and easy cloning SSH with automatic :ref:`shell integration <shell_integration>`, connection
of local shell and editor configuration to the remote machine. re-use for low latency and easy cloning of local shell and editor
configuration to the remote host.
:doc:`Panel <kittens/panel>` :doc:`Panel <kittens/panel>`
Draw a GPU accelerated dock panel on your desktop showing the output Draw a GPU accelerated dock panel on your desktop showing the output from an
from an arbitrary terminal program. arbitrary terminal program.
:doc:`Clipboard <kittens/clipboard>` :doc:`Clipboard <kittens/clipboard>`

View File

@@ -5,22 +5,21 @@ The :command:`launch` command
|kitty| has a :code:`launch` action that can be used to run arbitrary programs |kitty| has a :code:`launch` action that can be used to run arbitrary programs
in new windows/tabs. It can be mapped to user defined shortcuts in kitty.conf. in new windows/tabs. It can be mapped to user defined shortcuts in
It is very powerful and allows sending the contents of :file:`kitty.conf`. It is very powerful and allows sending the contents of the
the current window to the launched program, as well as many other options. current window to the launched program, as well as many other options.
In the simplest form, you can use it to open a new kitty window running the In the simplest form, you can use it to open a new kitty window running the
shell, as shown below:: shell, as shown below::
map f1 launch map f1 launch
To run a different program simply pass the command line as arguments to To run a different program simply pass the command line as arguments to launch::
launch::
map f1 launch vim path/to/some/file map f1 launch vim path/to/some/file
To open a new window with the same working directory as the currently To open a new window with the same working directory as the currently active
active window:: window::
map f1 launch --cwd=current map f1 launch --cwd=current
@@ -30,9 +29,10 @@ To open the new window in a new tab::
To run multiple commands in a shell, use:: To run multiple commands in a shell, use::
map f1 launch sh -c "ls && zsh" map f1 launch sh -c "ls && exec zsh"
To pass the contents of the current screen and scrollback to the started process:: To pass the contents of the current screen and scrollback to the started
process::
map f1 launch --stdin-source=@screen_scrollback less map f1 launch --stdin-source=@screen_scrollback less
@@ -46,16 +46,16 @@ There are many more powerful options, refer to the complete list below.
map f1 launch_tab vim map f1 launch_tab vim
map f2 launch_tab emacs map f2 launch_tab emacs
The :kbd:`F1` key will now open vim in a new tab with the current windows The :kbd:`F1` key will now open :program:`vim` in a new tab with the current
working directory windows working directory.
The piping environment The piping environment
-------------------------- --------------------------
When using :option:`launch --stdin-source`, the program to which the data is When using :option:`launch --stdin-source`, the program to which the data is
piped has a special environment variable declared, :envvar:`KITTY_PIPE_DATA` whose piped has a special environment variable declared, :envvar:`KITTY_PIPE_DATA`
contents are:: whose contents are::
KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns} KITTY_PIPE_DATA={scrolled_by}:{cursor_x},{cursor_y}:{lines},{columns}
@@ -73,33 +73,33 @@ the command line:
``@selection`` ``@selection``
replaced by the currently selected text Replaced by the currently selected text.
``@active-kitty-window-id`` ``@active-kitty-window-id``
replaced by the id of the currently active kitty window Replaced by the id of the currently active kitty window.
``@line-count`` ``@line-count``
replaced by the number of lines in STDIN. Only present when passing some Replaced by the number of lines in STDIN. Only present when passing some
data to STDIN data to STDIN.
``@input-line-number`` ``@input-line-number``
replaced the number of lines a pager should scroll to match the current Replaced the number of lines a pager should scroll to match the current
scroll position in kitty. See :opt:`scrollback_pager` for details scroll position in kitty. See :opt:`scrollback_pager` for details.
``@scrolled-by`` ``@scrolled-by``
replaced by the number of lines kitty is currently scrolled by Replaced by the number of lines kitty is currently scrolled by.
``@cursor-x`` ``@cursor-x``
replaced by the current cursor x position with 1 being the leftmost cell Replaced by the current cursor x position with 1 being the leftmost cell.
``@cursor-y`` ``@cursor-y``
replaced by the current cursor y position with 1 being the topmost cell Replaced by the current cursor y position with 1 being the topmost cell.
``@first-line-on-screen`` ``@first-line-on-screen``
replaced by the first line on screen. Can be used for pager positioning. Replaced by the first line on screen. Can be used for pager positioning.
``@last-line-on-screen`` ``@last-line-on-screen``
replaced by the last line on screen. Can be used for pager positioning. Replaced by the last line on screen. Can be used for pager positioning.
For example:: For example::
@@ -112,44 +112,51 @@ For example::
Watching launched windows Watching launched windows
--------------------------- ---------------------------
The :option:`launch --watcher` option allows you to specify python functions The :option:`launch --watcher` option allows you to specify Python functions
that will be called at specific events, such as when the window is resized or that will be called at specific events, such as when the window is resized or
closed. Simply specify the path to a python module that specifies callback closed. Simply specify the path to a Python module that specifies callback
functions for the events you are interested in, for example: functions for the events you are interested in, for example:
.. code-block:: python .. code-block:: python
def on_resize(boss, window, data): from typing import Any, Dict
from kitty.boss import Boss
from kitty.window import Window
def on_resize(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
# Here data will contain old_geometry and new_geometry # Here data will contain old_geometry and new_geometry
def on_focus_change(boss, window, data): def on_focus_change(boss: Boss, window: Window, data: Dict[str, Any])-> None:
# Here data will contain focused # Here data will contain focused
def on_close(boss, window, data): def on_close(boss: Boss, window: Window, data: Dict[str, Any])-> None:
# called when window is closed, typically when the program running in # called when window is closed, typically when the program running in
# it exits. # it exits.
Every callback is passed a reference to the global ``Boss`` object as well as Every callback is passed a reference to the global ``Boss`` object as well as
the ``Window`` object the action is occurring on. The ``data`` object is the ``Window`` object the action is occurring on. The ``data`` object is a dict
a dict that contains event dependent data. Some useful methods and attributes that contains event dependent data. Some useful methods and attributes for the
for the ``Window`` object are: ``as_text(as_ans=False, add_history=False, ``Window`` object are: ``as_text(as_ans=False, add_history=False,
add_wrap_markers=False, alternate_screen=False)`` with which you can get the add_wrap_markers=False, alternate_screen=False)`` with which you can get the
contents of the window and its scrollback buffer. Similarly, contents of the window and its scrollback buffer. Similarly,
``window.child.pid`` is the PID of the processes that was launched ``window.child.pid`` is the PID of the processes that was launched
in the window and ``window.id`` is the internal kitty ``id`` of the in the window and ``window.id`` is the internal kitty ``id`` of the window.
window.
Finding executables Finding executables
----------------------- -----------------------
When you specify a command to run as just a name rather than an absolute path, When you specify a command to run as just a name rather than an absolute path,
it is searched for in the system-wide ``PATH`` environment variable. Note that it is searched for in the system-wide :envvar:`PATH` environment variable. Note
this **may not** be the value of ``PATH`` inside a shell, as shell startup scripts that this **may not** be the value of :envvar:`PATH` inside a shell, as shell
often change the value of this variable. If it is not found there, then a startup scripts often change the value of this variable. If it is not found
system specific list of default paths is searched. If it is still not found, there, then a system specific list of default paths is searched. If it is still
then your shell is run and the value of ``PATH`` inside the shell is used. not found, then your shell is run and the value of :envvar:`PATH` inside the
shell is used.
See :opt:`exe_search_path` for details and how to control this. See :opt:`exe_search_path` for details and how to control this.
Syntax reference Syntax reference

View File

@@ -10,7 +10,8 @@ other in arbitrary arrangements, based on *Layouts*, see below for examples:
:align: center :align: center
:width: 100% :width: 100%
Screenshot, showing vim, tig and git running in |kitty| with the 'Tall' layout Screenshot, showing :program:`vim`, :program:`tig` and :program:`git`
running in |kitty| with the *Tall* layout
.. figure:: screenshots/splits.png .. figure:: screenshots/splits.png
@@ -18,21 +19,22 @@ other in arbitrary arrangements, based on *Layouts*, see below for examples:
:align: center :align: center
:width: 100% :width: 100%
Screenshot, showing windows with arbitrary arrangement in the 'Splits' Screenshot, showing windows with arbitrary arrangement in the *Splits*
layout layout
There are many different layouts available. They are all enabled by default, There are many different layouts available. They are all enabled by default, you
you can switch layouts using :sc:`next_layout`. To control which layouts can switch layouts using :ac:`next_layout` (:sc:`next_layout` by default). To
are available use :opt:`enabled_layouts`, the first listed layout becomes control which layouts are available use :opt:`enabled_layouts`, the first listed
the default. Individual layouts and how to use them are described below. layout becomes the default. Individual layouts and how to use them are described
below.
The Stack Layout The Stack Layout
------------------ ------------------
This is the simplest layout it displays a single window using all available This is the simplest layout. It displays a single window using all available
space, other windows are hidden behind it. It has no options:: space, other windows are hidden behind it. This layout has no options::
enabled_layouts stack enabled_layouts stack
@@ -40,14 +42,14 @@ space, other windows are hidden behind it. It has no options::
The Tall Layout The Tall Layout
------------------ ------------------
Displays one (or optionally more) full height windows on the left half of the Displays one (or optionally more) full-height windows on the left half of the
screen. Remaining windows are tiled vertically on the right half of the screen. screen. Remaining windows are tiled vertically on the right half of the screen.
There are options to control how the screen is split horizontally ``bias`` There are options to control how the screen is split horizontally ``bias``
(an integer between ``10`` and ``90``) and options to control how many (an integer between ``10`` and ``90``) and options to control how many
full-height windows there are ``full_size`` (a positive integer). The full-height windows there are ``full_size`` (a positive integer). The
``mirrored`` option when set to ``true`` will cause the short windows to be ``mirrored`` option when set to ``true`` will cause the full-height windows to
on the left side of the screen instead of the right. The syntax be on the right side of the screen instead of the left. The syntax
for the options is shown below:: for the options is::
enabled_layouts tall:bias=50;full_size=1;mirrored=false enabled_layouts tall:bias=50;full_size=1;mirrored=false
@@ -65,7 +67,7 @@ for the options is shown below::
│ │ │ │ │ │
└──────────────┴───────────────┘ └──────────────┴───────────────┘
In addition, you can map keys to increase or decrease the number of full size In addition, you can map keys to increase or decrease the number of full-height
windows, for example:: windows, for example::
map ctrl+[ layout_action decrease_num_full_size_windows map ctrl+[ layout_action decrease_num_full_size_windows
@@ -75,14 +77,13 @@ windows, for example::
The Fat Layout The Fat Layout
---------------- ----------------
Displays one (or optionally more) full width windows on the top half of the Displays one (or optionally more) full-width windows on the top half of the
screen. Remaining windows are tiled horizontally on the bottom half of the screen. screen. Remaining windows are tiled horizontally on the bottom half of the
There are options to control how the screen is split vertically ``bias`` screen. There are options to control how the screen is split vertically ``bias``
(an integer between ``10`` and ``90``) and options to control how many (an integer between ``10`` and ``90``) and options to control how many
full-height windows there are ``full_size`` (a positive integer). The full-width windows there are ``full_size`` (a positive integer). The
``mirrored`` option when set to ``true`` will cause the narrow windows to be ``mirrored`` option when set to ``true`` will cause the full-width windows to be
on the top of the screen instead of the bottom. The syntax for the options is on the bottom of the screen instead of the top. The syntax for the options is::
shown below::
enabled_layouts fat:bias=50;full_size=1;mirrored=false enabled_layouts fat:bias=50;full_size=1;mirrored=false
@@ -100,11 +101,16 @@ shown below::
└─────────┴──────────┴─────────┘ └─────────┴──────────┴─────────┘
This layout also supports ``decrease_num_full_size_windows`` layout action like
the *Tall* layout, shown above.
The Grid Layout The Grid Layout
-------------------- --------------------
Display windows in a balanced grid with all windows the same size except the Display windows in a balanced grid with all windows the same size except the
last column if there are not enough windows to fill the grid. Has no options:: last column if there are not enough windows to fill the grid. This layout has no
options::
enabled_layouts grid enabled_layouts grid
@@ -132,20 +138,20 @@ define a few extra key bindings in :file:`kitty.conf`::
# Create a new window splitting the space used by the existing one so that # Create a new window splitting the space used by the existing one so that
# the two windows are placed one above the other # the two windows are placed one above the other
map F5 launch --location=hsplit map f5 launch --location=hsplit
# Create a new window splitting the space used by the existing one so that # Create a new window splitting the space used by the existing one so that
# the two windows are placed side by side # the two windows are placed side by side
map F6 launch --location=vsplit map f6 launch --location=vsplit
# Create a new window splitting the space used by the existing one so that # Create a new window splitting the space used by the existing one so that
# the two windows are placed side by side if the existing window is wide or # the two windows are placed side by side if the existing window is wide or
# one above the other if the existing window is tall. # one above the other if the existing window is tall.
map F4 launch --location=split map f4 launch --location=split
# Rotate the current split, chaging its split axis from vertical to # Rotate the current split, chaging its split axis from vertical to
# horizontal or vice versa # horizontal or vice versa
map F7 layout_action rotate map f7 layout_action rotate
# Move the active window in the indicated direction # Move the active window in the indicated direction
map shift+up move_window up map shift+up move_window up
@@ -159,16 +165,16 @@ define a few extra key bindings in :file:`kitty.conf`::
map ctrl+up neighboring_window up map ctrl+up neighboring_window up
map ctrl+down neighboring_window down map ctrl+down neighboring_window down
Windows can be resized using :ref:`window_resizing`. You can swap the windows Windows can be resized using :ref:`window_resizing`. You can swap the windows
in a split using the ``rotate`` action with an argument of ``180`` and rotate in a split using the ``rotate`` action with an argument of ``180`` and rotate
and swap with an argument of ``270``. and swap with an argument of ``270``.
This layout takes one option, ``split_axis`` that controls whether new windows This layout takes one option, ``split_axis`` that controls whether new windows
are placed into vertical or horizontal splits when a ``--location`` is not are placed into vertical or horizontal splits when a :option:`--location <launch
specified. A value of ``horizontal`` (same as ``--location=vsplit``) --location>` is not specified. A value of ``horizontal`` (same as
means when a new split is created the two windows will be placed side by side ``--location=vsplit``) means when a new split is created the two windows will be
and a value of ``vertical`` (same as ``--location=hsplit``) means the two placed side by side and a value of ``vertical`` (same as ``--location=hsplit``)
windows will be placed one on top of the other. By default:: means the two windows will be placed one on top of the other. By default::
enabled_layouts splits:split_axis=horizontal enabled_layouts splits:split_axis=horizontal
@@ -193,7 +199,7 @@ windows will be placed one on top of the other. By default::
The Horizontal Layout The Horizontal Layout
------------------------ ------------------------
All windows are shown side by side. Has no options:: All windows are shown side by side. This layout has no options::
enabled_layouts horizontal enabled_layouts horizontal
@@ -213,7 +219,7 @@ All windows are shown side by side. Has no options::
The Vertical Layout The Vertical Layout
----------------------- -----------------------
All windows are shown one below the other. Has no options:: All windows are shown one below the other. This layout has no options::
enabled_layouts vertical enabled_layouts vertical
@@ -239,14 +245,14 @@ Resizing windows
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also You can resize windows inside layouts. Press :sc:`start_resizing_window` (also
:kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen :kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen
instructions. In a given window layout only some operations may be possible instructions. In a given window layout only some operations may be possible for
for a particular window. For example, in the Tall layout you can make the first a particular window. For example, in the *Tall* layout you can make the first
window wider/narrower, but not taller/shorter. Note that what you are resizing window wider/narrower, but not taller/shorter. Note that what you are resizing
is actually not a window, but a row/column in the layout, all windows in that is actually not a window, but a row/column in the layout, all windows in that
row/column will be resized. row/column will be resized.
You can also define shortcuts in :file:`kitty.conf` to make the active window You can also define shortcuts in :file:`kitty.conf` to make the active window
wider, narrower, taller, or shorter by mapping to the ``resize_window`` wider, narrower, taller, or shorter by mapping to the :ac:`resize_window`
action, for example:: action, for example::
map ctrl+left resize_window narrower map ctrl+left resize_window narrower
@@ -256,22 +262,21 @@ action, for example::
# reset all windows in the tab to default sizes # reset all windows in the tab to default sizes
map ctrl+home resize_window reset map ctrl+home resize_window reset
The ``resize_window`` action has a second, optional argument to control The :ac:`resize_window` action has a second optional argument to control
the resizing increment (a positive integer that defaults to 1). the resizing increment (a positive integer that defaults to 1).
Some layouts take options to control their behavior. For example, the *Fat*
Some layouts take options to control their behavior. For example, the ``fat`` and *Tall* layouts accept the ``bias`` and ``full_size`` options to control
and ``tall`` layouts accept the ``bias`` and ``full_size`` options to control how the available space is split up. To specify the option, in :opt:`kitty.conf
how the available space is split up. <enabled_layouts>` use::
To specify the option, in :opt:`kitty.conf <enabled_layouts>` use::
enabled_layouts tall:bias=70;full_size=2 enabled_layouts tall:bias=70;full_size=2
This will have ``2`` instead of a single tall window, that occupy ``70%`` This will have ``2`` instead of a single tall window, that occupy ``70%``
instead of ``50%`` of available width. ``bias`` can be any number between 10 instead of ``50%`` of available width. ``bias`` can be any number between ``10``
and 90. and ``90``.
Writing a new layout only requires about two hundred lines of code, so if there Writing a new layout only requires about two hundred lines of code, so if there
is some layout you want, take a look at one of the existing layouts in the is some layout you want, take a look at one of the existing layouts in the
`layout <https://github.com/kovidgoyal/kitty/tree/master/kitty/layout>`_ `layout <https://github.com/kovidgoyal/kitty/tree/master/kitty/layout>`__
package and submit a pull request! package and submit a pull request!

View File

@@ -9,12 +9,12 @@ running programs or similar. Lets start with a few examples:
Examples Examples
---------- ----------
Suppose we want to be able to highlight the word ERROR in the current window. Suppose we want to be able to highlight the word :code:`ERROR` in the current
Add the following to :file:`kitty.conf`:: window. Add the following to :file:`kitty.conf`::
map f1 toggle_marker text 1 ERROR map f1 toggle_marker text 1 ERROR
Now when you press :kbd:`F1` all instances of the word :code:`ERROR` will be Now when you press :kbd:`F1`, all instances of the word :code:`ERROR` will be
highlighted. To turn off the highlighting, press :kbd:`F1` again. highlighted. To turn off the highlighting, press :kbd:`F1` again.
If you want to make it case-insensitive, use:: If you want to make it case-insensitive, use::
@@ -39,41 +39,40 @@ can control the colors used for these groups in :file:`kitty.conf` with::
.. note:: .. note::
For performance reasons, matching is done per line only, and only when that line is For performance reasons, matching is done per line only, and only when that
altered in any way. So you cannot match text that stretches across multiple line is altered in any way. So you cannot match text that stretches across
lines. multiple lines.
Creating markers dynamically Creating markers dynamically
--------------------------------- ---------------------------------
If you want to create markers dynamically rather than pre-defining them in If you want to create markers dynamically rather than pre-defining them in
:file:`kitty.conf` you can do so as follows:: :file:`kitty.conf`, you can do so as follows::
map f1 create_marker map f1 create_marker
map f2 remove_marker map f2 remove_marker
Then pressing :kbd:`F1` will allow you to enter the marker definition and set Then pressing :kbd:`F1` will allow you to enter the marker definition and set it
it and pressing :kbd:`F2` will remove the marker. ``create_marker`` accepts and pressing :kbd:`F2` will remove the marker. :ac:`create_marker` accepts the
the same syntax as ``toggle_marker`` above. Note that while creating same syntax as :ac:`toggle_marker` above. Note that while creating markers, the
markers, the prompt has history so you can easily re-use previous marker prompt has history so you can easily re-use previous marker expressions.
expressions.
You can also use the facilities for :doc:`remote-control` to dynamically You can also use the facilities for :doc:`remote-control` to dynamically add or
add/remove markers. remove markers.
Scrolling to marks Scrolling to marks
-------------------- --------------------
kitty has an action to scroll to the next line that contains a mark. You can kitty has a :ac:`scroll_to_mark` action to scroll to the next line that contains
use it by mapping it to some shortcut in :file:`kitty.conf`:: a mark. You can use it by mapping it to some shortcut in :file:`kitty.conf`::
map ctrl+p scroll_to_mark prev map ctrl+p scroll_to_mark prev
map ctrl+n scroll_to_mark next map ctrl+n scroll_to_mark next
Then pressing :kbd:`ctrl+p` will scroll to the first line in the scrollback Then pressing :kbd:`Ctrl+P` will scroll to the first line in the scrollback
buffer above the current top line that contains a mark. Pressing :kbd:`ctrl+n` buffer above the current top line that contains a mark. Pressing :kbd:`Ctrl+N`
will scroll to show the first line below the current last line that contains will scroll to show the first line below the current last line that contains
a mark. If you wish to jump to a mark of a specific type, you can add that to a mark. If you wish to jump to a mark of a specific type, you can add that to
the mapping:: the mapping::
@@ -86,26 +85,26 @@ Which will scroll only to marks of type 1.
The full syntax for creating marks The full syntax for creating marks
------------------------------------- -------------------------------------
The syntax of the :code:`toggle_marker` command is:: The syntax of the :ac:`toggle_marker` action is::
toggle_marker <marker-type> <specification> toggle_marker <marker-type> <specification>
Here :code:`marker-type` is one of: Here :code:`marker-type` is one of:
* :code:`text` - simple substring matching * :code:`text` - Simple substring matching
* :code:`itext` - case-insensitive substring matching * :code:`itext` - Case-insensitive substring matching
* :code:`regex` - A python regular expression * :code:`regex` - A Python regular expression
* :code:`iregex` - A case-insensitive python regular expression * :code:`iregex` - A case-insensitive Python regular expression
* :code:`function` - An arbitrary function defined in a python file, see :ref:`marker_funcs`. * :code:`function` - An arbitrary function defined in a Python file, see :ref:`marker_funcs`.
.. _marker_funcs: .. _marker_funcs:
Arbitrary marker functions Arbitrary marker functions
----------------------------- -----------------------------
You can create your own marker functions. Create a python file named You can create your own marker functions. Create a Python file named
:file:`mymarker.py` and in it create a :code:`marker` function. This :file:`mymarker.py` and in it create a :code:`marker` function. This function
function receives the text of the line as input and must yield three numbers, receives the text of the line as input and must yield three numbers,
the starting character position, the ending character position and the mark the starting character position, the ending character position and the mark
group (1-3). For example: group (1-3). For example:
@@ -122,6 +121,7 @@ Save this file somewhere and in :file:`kitty.conf`, use::
map f1 toggle_marker function /path/to/mymarker.py map f1 toggle_marker function /path/to/mymarker.py
If you save the file in the kitty config directory, you can use:: If you save the file in the :ref:`kitty config directory <confloc>`, you can
use::
map f1 toggle_marker function mymarker.py map f1 toggle_marker function mymarker.py

View File

@@ -1,15 +1,14 @@
Scripting the mouse click Scripting the mouse click
====================================================== ======================================================
|kitty| has support for `terminal hyperlinks |kitty| has support for :term:`terminal hyperlinks <hyperlinks>`. These are
<https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda>`_. These generated by many terminal programs, such as ``ls``, ``gcc``, ``systemd``,
are generated by many terminal programs, such as ``ls``, ``gcc``, ``systemd``, :ref:`tool_mdcat`, etc. You can customize exactly what happens when clicking on
:ref:`tool_mdcat`, etc. You can customize exactly what happens when clicking on these these hyperlinks in |kitty|.
hyperlinks in |kitty|.
You can tell kitty to take arbitrarily many, complex actions You can tell kitty to take arbitrarily many, complex actions when a link is
when a link is clicked. Let us illustrate with some examples, first. Create clicked. Let us illustrate with some examples, first. Create the file
the file :file:`~/.config/kitty/open-actions.conf` with the following: :file:`~/.config/kitty/open-actions.conf` with the following:
.. code:: conf .. code:: conf
@@ -22,6 +21,13 @@ Now, run ``ls --hyperlink=auto`` in kitty and click on the filename of an
image, holding down :kbd:`ctrl+shift`. It will be opened over the current image, holding down :kbd:`ctrl+shift`. It will be opened over the current
window. Press any key to close it. window. Press any key to close it.
.. note::
The :program:`ls` comes with macOS does not support hyperlink, you need to
install `GNU Coreutils <https://www.gnu.org/software/coreutils/>`__. If you
install it via `Homebrew <https://formulae.brew.sh/formula/coreutils>`__, it
will be :program:`gls`.
Each entry in :file:`open-actions.conf` consists of one or more Each entry in :file:`open-actions.conf` consists of one or more
:ref:`matching_criteria`, such as ``protocol`` and ``mime`` and one or more :ref:`matching_criteria`, such as ``protocol`` and ``mime`` and one or more
``action`` entries. In the example above kitty uses the :doc:`launch <launch>` ``action`` entries. In the example above kitty uses the :doc:`launch <launch>`
@@ -29,8 +35,8 @@ action which can be used to run external programs. Entries are separated by
blank lines. blank lines.
Actions are very powerful, anything that you can map to a key combination in Actions are very powerful, anything that you can map to a key combination in
`kitty.conf` can be used as an action. You can specify more than one action per :file:`kitty.conf` can be used as an action. You can specify more than one
entry if you like, for example: action per entry if you like, for example:
.. code:: conf .. code:: conf
@@ -60,7 +66,7 @@ some special variables, documented below:
.. note:: .. note::
You can use the :opt:`action_alias` option just as in kitty.conf to You can use the :opt:`action_alias` option just as in :file:`kitty.conf` to
define aliases for frequently used actions. define aliases for frequently used actions.
@@ -77,7 +83,7 @@ lines. The various available criteria are:
``protocol`` ``protocol``
A comma separated list of protocols, for example: ``http, https``. If A comma separated list of protocols, for example: ``http, https``. If
absent, there is no constraint on protocol absent, there is no constraint on protocol.
``url`` ``url``
A regular expression that must match against the entire (unquoted) URL A regular expression that must match against the entire (unquoted) URL
@@ -88,11 +94,12 @@ lines. The various available criteria are:
``mime`` ``mime``
A comma separated list of MIME types, for example: ``text/*, image/*, A comma separated list of MIME types, for example: ``text/*, image/*,
application/pdf``. You can add MIME types to kitty by creating the application/pdf``. You can add MIME types to kitty by creating a file named
:file:`mime.types` in the kitty configuration directory. Useful if your :file:`mime.types` in the :ref:`kitty configuration directory <confloc>`.
system MIME database does not have definitions you need. This file is Useful if your system MIME database does not have definitions you need. This
in the standard format of one definition per line, like: ``text/plain rst file is in the standard format of one definition per line, like:
md``. Note that the MIME type for directories is ``inode/directory``. ``text/plain rst md``. Note that the MIME type for directories is
``inode/directory``.
``ext`` ``ext``
A comma separated list of file extensions, for example: ``jpeg, tar.gz`` A comma separated list of file extensions, for example: ``jpeg, tar.gz``
@@ -116,9 +123,10 @@ URLs onto the kitty dock icon to open them with kitty. The default actions are:
These actions can also be executed from the command line by running:: These actions can also be executed from the command line by running::
open -a kitty.app file_or_url ... (on macOS only) kitty +open file_or_url another_url ...
or
kitty +open file_or_url ... # macOS only
open -a kitty.app file_or_url another_url ...
Since macOS lacks an official interface to set default URL scheme handlers, Since macOS lacks an official interface to set default URL scheme handlers,
kitty has a command you can use for it. The first argument for is the URL kitty has a command you can use for it. The first argument for is the URL
@@ -133,8 +141,8 @@ defaults to kitty, if not specified. For example:
kitty +runpy 'from kitty.fast_data_types import cocoa_set_url_handler; import sys; cocoa_set_url_handler(*sys.argv[1:]); print("OK")' xyz someapp.bundle.identifier kitty +runpy 'from kitty.fast_data_types import cocoa_set_url_handler; import sys; cocoa_set_url_handler(*sys.argv[1:]); print("OK")' xyz someapp.bundle.identifier
You can customize these actions by creating a :file:`launch-actions.conf` file You can customize these actions by creating a :file:`launch-actions.conf` file
in the kitty config directory, just like in the :ref:`kitty config directory <confloc>`, just like the
the :file:`open-actions.conf` file above. For example: :file:`open-actions.conf` file above. For example:
.. code:: conf .. code:: conf

View File

@@ -4,23 +4,22 @@ Overview
Design philosophy Design philosophy
------------------- -------------------
|kitty| is designed for power keyboard users. To that end all its controls |kitty| is designed for power keyboard users. To that end all its controls work
work with the keyboard (although it fully supports mouse interactions as with the keyboard (although it fully supports mouse interactions as well). Its
well). Its configuration is a simple, human editable, single file for configuration is a simple, human editable, single file for easy reproducibility
easy reproducibility (I like to store configuration in source control). (I like to store configuration in source control).
The code in |kitty| is designed to be simple, modular and hackable. It is The code in |kitty| is designed to be simple, modular and hackable. It is
written in a mix of C (for performance sensitive parts) and Python (for written in a mix of C (for performance sensitive parts) and Python (for easy
easy hackability of the UI). It does not depend on any large and complex hackability of the UI). It does not depend on any large and complex UI toolkit,
UI toolkit, using only OpenGL for rendering everything. using only OpenGL for rendering everything.
Finally, |kitty| is designed from the ground up to support all modern Finally, |kitty| is designed from the ground up to support all modern terminal
terminal features, such as unicode, true color, bold/italic fonts, text features, such as Unicode, true color, bold/italic fonts, text formatting, etc.
formatting, etc. It even extends existing text formatting escape codes, It even extends existing text formatting escape codes, to add support for
to add support for features not available elsewhere, such as colored and features not available elsewhere, such as colored and styled (curly) underlines.
styled (curly) underlines. One of the design goals of |kitty| is to be One of the design goals of |kitty| is to be easily extensible so that new
easily extensible so that new features can be added in the future with features can be added in the future with relatively little effort.
relatively little effort.
.. include:: basic.rst .. include:: basic.rst
@@ -28,10 +27,10 @@ relatively little effort.
Configuring kitty Configuring kitty
------------------- -------------------
|kitty| is highly configurable, everything from keyboard shortcuts to |kitty| is highly configurable, everything from keyboard shortcuts to painting
painting frames-per-second. Press :sc:`edit_config_file` in kitty frames-per-second. Press :sc:`edit_config_file` in kitty to open its fully
to open its fully commented sample config file in your text editor. commented sample config file in your text editor. For details see the
For details see the :doc:`configuration docs <conf>`. :doc:`configuration docs <conf>`.
.. toctree:: .. toctree::
:hidden: :hidden:
@@ -51,17 +50,26 @@ windows automatically, resizing and moving them as needed. You can create a new
Currently, there are seven layouts available: Currently, there are seven layouts available:
* **Fat** -- One (or optionally more) windows are shown full width on the top, the rest of the windows are shown side-by-side on the bottom * **Fat** -- One (or optionally more) windows are shown full width on the top,
the rest of the windows are shown side-by-side on the bottom
* **Grid** -- All windows are shown in a grid * **Grid** -- All windows are shown in a grid
* **Horizontal** -- All windows are shown side-by-side * **Horizontal** -- All windows are shown side-by-side
* **Splits** -- Windows arranged in arbitrary patterns created using horizontal and vertical splits
* **Splits** -- Windows arranged in arbitrary patterns created using horizontal
and vertical splits
* **Stack** -- Only a single maximized window is shown at a time * **Stack** -- Only a single maximized window is shown at a time
* **Tall** -- One (or optionally more) windows are shown full height on the left, the rest of the windows are shown one below the other on the right
* **Tall** -- One (or optionally more) windows are shown full height on the
left, the rest of the windows are shown one below the other on the right
* **Vertical** -- All windows are shown one below the other * **Vertical** -- All windows are shown one below the other
By default, all layouts are enabled and you can switch between layouts using By default, all layouts are enabled and you can switch between layouts using
the :sc:`next_layout` key combination. You can also create shortcuts to select the :sc:`next_layout` key combination. You can also create shortcuts to select
particular layouts, and choose which layouts you want to enable/disable, see particular layouts, and choose which layouts you want to enable, see
:ref:`conf-kitty-shortcuts.layout` for examples. The first layout listed in :ref:`conf-kitty-shortcuts.layout` for examples. The first layout listed in
:opt:`enabled_layouts` becomes the default layout. :opt:`enabled_layouts` becomes the default layout.
@@ -79,9 +87,9 @@ Extending kitty
kitty has a powerful framework for scripting. You can create small terminal 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 used to add features
to kitty, for example, :doc:`editing remote files <kittens/remote_file>` or to kitty, for example, :doc:`editing remote files <kittens/remote_file>` or
:doc:`inputting unicode characters <kittens/unicode_input>`. They can also be :doc:`inputting Unicode characters <kittens/unicode_input>`. They can also be
used to create programs that leverage kitty's powerful features, for example, used to create programs that leverage kitty's powerful features, for example,
:doc:`viewing images <kittens/icat>` or :doc:`diffing files with images :doc:`viewing images <kittens/icat>` or :doc:`diffing files with image support
<kittens/diff>`. <kittens/diff>`.
You can :doc:`create your own kittens to scratch your own itches You can :doc:`create your own kittens to scratch your own itches
@@ -101,9 +109,9 @@ Remote control
|kitty| has a very powerful system that allows you to control it from the |kitty| has a very powerful system that allows you to control it from the
:doc:`shell prompt, even over SSH <remote-control>`. You can change colors, :doc:`shell prompt, even over SSH <remote-control>`. You can change colors,
fonts, open new :term:`windows <window>`, :term:`tabs <tab>`, set their titles, fonts, open new :term:`windows <window>`, :term:`tabs <tab>`, set their titles,
change window layout, get text change window layout, get text from one window and send text to another, etc.
from one window and send text to another, etc, etc. The possibilities are The possibilities are endless. See the :doc:`tutorial <remote-control>` to get
endless. See the :doc:`tutorial <remote-control>` to get started. started.
.. toctree:: .. toctree::
:hidden: :hidden:
@@ -117,10 +125,9 @@ Startup Sessions
------------------ ------------------
You can control the :term:`tabs <tab>`, :term:`kitty window <window>` layout, You can control the :term:`tabs <tab>`, :term:`kitty window <window>` layout,
working directory, startup programs, working directory, startup programs, etc. by creating a *session* file and using
etc. by creating a "session" file and using the :option:`kitty --session` the :option:`kitty --session` command line flag or the :opt:`startup_session`
command line flag or the :opt:`startup_session` option in :file:`kitty.conf`. option in :file:`kitty.conf`. For example:
For example:
.. code-block:: session .. code-block:: session
@@ -130,28 +137,28 @@ For example:
cd ~ cd ~
# Create a window and run the specified command in it # Create a window and run the specified command in it
launch zsh launch zsh
# Create a window with some environment variables set and run # Create a window with some environment variables set and run vim in it
# vim in it
launch --env FOO=BAR vim launch --env FOO=BAR vim
# Set the title for the next window # Set the title for the next window
launch --title "Chat with x" irssi --profile x launch --title "Chat with x" irssi --profile x
# Create a new tab (the part after new_tab is the optional tab # Create a new tab
# name which will be displayed in the tab bar, if omitted, the # The part after new_tab is the optional tab title which will be displayed in
# title of the active window will be used instead) # the tab bar, if omitted, the title of the active window will be used instead.
new_tab my tab new_tab my tab
cd ~/somewhere cd ~/somewhere
# Set the layouts allowed in this tab # Set the layouts allowed in this tab
enabled_layouts tall, stack enabled_layouts tall,stack
# Set the current layout # Set the current layout
layout stack layout stack
launch zsh launch zsh
# Create a new OS window # Create a new OS window
# Any definitions specifed before the first new_os_window will apply to first OS window.
new_os_window new_os_window
# set new window size to 80x25 cells # Set new window size to 80x24 cells
os_window_size 80c 25c os_window_size 80c 24c
# set the --class for the new OS window # Set the --class for the new OS window
os_window_class mywindow os_window_class mywindow
launch sh launch sh
# Make the current window the active (focused) window # Make the current window the active (focused) window
@@ -159,8 +166,8 @@ For example:
launch emacs launch emacs
.. note:: .. note::
The :doc:`launch <launch>` command when used in a session file The :doc:`launch <launch>` command when used in a session file cannot create
cannot create new OS windows, or tabs. new OS windows, or tabs.
Creating tabs/windows Creating tabs/windows
@@ -182,25 +189,25 @@ Mouse features
* You can click on a URL to open it in a browser. * You can click on a URL to open it in a browser.
* You can double click to select a word and then drag to select more words. * You can double click to select a word and then drag to select more words.
* You can triple click to select a line and then drag to select more lines. * You can triple click to select a line and then drag to select more lines.
* You can triple click while holding :kbd:`ctrl+alt` to select from clicked * You can triple click while holding :kbd:`Ctrl+Alt` to select from clicked
point to end of line. point to end of line.
* You can right click to extend a previous selection. * You can right click to extend a previous selection.
* You can hold down :kbd:`ctrl+alt` and drag with the mouse to select in * You can hold down :kbd:`Ctrl+Alt` and drag with the mouse to select in
columns. columns.
* Selecting text automatically copies it to the primary clipboard (on * Selecting text automatically copies it to the primary clipboard (on platforms
platforms with a primary clipboard).
* You can middle click to paste from the primary clipboard (on platforms
with a primary clipboard). with a primary clipboard).
* You can right click while holding :kbd:`ctrl+shift` to open the output * You can middle click to paste from the primary clipboard (on platforms with a
of the clicked on command in a pager (requires :ref:`shell_integration`) primary clipboard).
* You can select text with kitty even when a terminal program has grabbed * You can right click while holding :kbd:`Ctrl+Shift` to open the output of the
the mouse by holding down the :kbd:`shift` key clicked on command in a pager (requires :ref:`shell_integration`)
* You can select text with kitty even when a terminal program has grabbed the
mouse by holding down the :kbd:`Shift` key
All these actions can be customized in :file:`kitty.conf` as described All these actions can be customized in :file:`kitty.conf` as described
:ref:`here <conf-kitty-mouse.mousemap>`. :ref:`here <conf-kitty-mouse.mousemap>`.
You can also customize what happens when clicking on :term:`hyperlinks` in kitty, You can also customize what happens when clicking on :term:`hyperlinks` in
having it open files in your editor, download remote files, open things kitty, having it open files in your editor, download remote files, open things
in your browser, etc. in your browser, etc.
For details, see :doc:`here <open_actions>`. For details, see :doc:`here <open_actions>`.
@@ -214,12 +221,11 @@ Font control
----------------- -----------------
|kitty| has extremely flexible and powerful font selection features. You can |kitty| has extremely flexible and powerful font selection features. You can
specify individual families for the regular, bold, italic and bold+italic specify individual families for the regular, bold, italic and bold+italic fonts.
fonts. You can even specify specific font families for specific ranges of You can even specify specific font families for specific ranges of Unicode
unicode characters. This allows precise control over text rendering. It can characters. This allows precise control over text rendering. It can comein handy
come in handy for applications like powerline, without the need to use patched for applications like powerline, without the need to use patched fonts. See the
fonts. See the various font related configuration directives in various font related configuration directives in :ref:`conf-kitty-fonts`.
:ref:`conf-kitty-fonts`.
.. _scrollback: .. _scrollback:
@@ -228,29 +234,29 @@ The scrollback buffer
----------------------- -----------------------
|kitty| supports scrolling back to view history, just like most terminals. You |kitty| supports scrolling back to view history, just like most terminals. You
can use either keyboard shortcuts or the mouse scroll wheel to do so. However, can use either keyboard shortcuts or the mouse scroll wheel to do so. However,
|kitty| has an extra, neat feature. Sometimes you need to explore the |kitty| has an extra, neat feature. Sometimes you need to explore the scrollback
scrollback buffer in more detail, maybe search for some text or refer to it buffer in more detail, maybe search for some text or refer to it side-by-side
side-by-side while typing in a follow-up command. |kitty| allows you to do this while typing in a follow-up command. |kitty| allows you to do this by pressing
by pressing the :sc:`show_scrollback` key-combination, which will open the the :sc:`show_scrollback` shortcut, which will open the scrollback buffer in
scrollback buffer in your favorite pager program (which is ``less`` by default). your favorite pager program (which is :program:`less` by default). Colors and
Colors and text formatting are preserved. You can explore the scrollback buffer text formatting are preserved. You can explore the scrollback buffer comfortably
comfortably within the pager. within the pager.
Additionally, you can pipe the contents of the scrollback buffer to an Additionally, you can pipe the contents of the scrollback buffer to an
arbitrary, command running in a new :term:`window`, :term:`tab` or :term:`overlay`, arbitrary, command running in a new :term:`window`, :term:`tab` or
for example:: :term:`overlay`. For example::
map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting less +G -R map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting less +G -R
Would open the scrollback buffer in a new :term:`window` when you press the :kbd:`F1` Would open the scrollback buffer in a new :term:`window` when you press the
key. See :sc:`show_scrollback <show_scrollback>` for details. :kbd:`F1` key. See :sc:`show_scrollback <show_scrollback>` for details.
If you want to use it with an editor such as vim to get more powerful features, If you want to use it with an editor such as :program:`vim` to get more powerful
you can see tips for doing so, in :iss:`this thread <719>`. features, you can see tips for doing so, in :iss:`this thread <719>`.
If you wish to store very large amounts of scrollback to view using the piping or If you wish to store very large amounts of scrollback to view using the piping
:sc:`show_scrollback <show_scrollback>` features, you can use the or :sc:`show_scrollback <show_scrollback>` features, you can use the
:opt:`scrollback_pager_history_size` option. :opt:`scrollback_pager_history_size` option.
@@ -258,8 +264,8 @@ Integration with shells
--------------------------------- ---------------------------------
kitty has the ability to integrate closely within common shells, such as `zsh kitty has the ability to integrate closely within common shells, such as `zsh
<https://www.zsh.org/>`_, `fish <https://fishshell.com>`_ and `bash <https://www.zsh.org/>`__, `fish <https://fishshell.com>`__ and `bash
<https://www.gnu.org/software/bash/>`_ to enable features such as jumping to <https://www.gnu.org/software/bash/>`__ to enable features such as jumping to
previous prompts in the scrollback, viewing the output of the last command in previous prompts in the scrollback, viewing the output of the last command in
:program:`less`, using the mouse to move the cursor while editing prompts, etc. :program:`less`, using the mouse to move the cursor while editing prompts, etc.
See :doc:`shell-integration` for details. See :doc:`shell-integration` for details.
@@ -274,17 +280,16 @@ See :doc:`shell-integration` for details.
Multiple copy/paste buffers Multiple copy/paste buffers
----------------------------- -----------------------------
In addition to being able to copy/paste from the system clipboard, in |kitty| you In addition to being able to copy/paste from the system clipboard, in |kitty|
can also setup an arbitrary number of copy paste buffers. To do so, simply add you can also setup an arbitrary number of copy paste buffers. To do so, simply
something like the following to your :file:`kitty.conf`:: add something like the following to your :file:`kitty.conf`::
map f1 copy_to_buffer a map f1 copy_to_buffer a
map f2 paste_from_buffer a map f2 paste_from_buffer a
This will allow you to press :kbd:`F1` to copy the current selection to an This will allow you to press :kbd:`F1` to copy the current selection to an
internal buffer named ``a`` and :kbd:`F2` to paste from that buffer. The buffer internal buffer named ``a`` and :kbd:`F2` to paste from that buffer. The buffer
names are arbitrary strings, so you can define as many such buffers as you names are arbitrary strings, so you can define as many such buffers as you need.
need.
Marks Marks

View File

@@ -2,30 +2,31 @@ Performance
=================== ===================
The main goals for |kitty| performance are user perceived latency while typing The main goals for |kitty| performance are user perceived latency while typing
and "smoothness" while scrolling as well as CPU usage. |kitty| tries hard to find and "smoothness" while scrolling as well as CPU usage. |kitty| tries hard to
an optimum balance for these. To that end it keeps a cache of each rendered find an optimum balance for these. To that end it keeps a cache of each rendered
glyph in video RAM so that font rendering is not a bottleneck. Interaction glyph in video RAM so that font rendering is not a bottleneck. Interaction with
with child programs takes place in a separate thread from rendering, to improve child programs takes place in a separate thread from rendering, to improve
smoothness. smoothness.
There are two parameters you can tune to adjust the performance. :opt:`repaint_delay` There are two config options you can tune to adjust the performance,
and :opt:`input_delay`. These control the artificial delays introduced into the :opt:`repaint_delay` and :opt:`input_delay`. These control the artificial delays
render loop to reduce CPU usage. See :ref:`conf-kitty-performance` for details. introduced into the render loop to reduce CPU usage. See
See also the :opt:`sync_to_monitor` option to further decrease latency at the cost :ref:`conf-kitty-performance` for details. See also the :opt:`sync_to_monitor`
of some `tearing <https://en.wikipedia.org/wiki/Screen_tearing>`_ while scrolling. option to further decrease latency at the cost of some `screen tearing
<https://en.wikipedia.org/wiki/Screen_tearing>`__ while scrolling.
You can generate detailed per-function performance data using `gperftools You can generate detailed per-function performance data using
<https://github.com/gperftools/gperftools>`_. Build |kitty| with `make `gperftools <https://github.com/gperftools/gperftools>`__. Build |kitty| with
profile`. Run kitty and perform the task you want to analyse, for example, ``make profile``. Run kitty and perform the task you want to analyse, for
scrolling a large file with `less`. After you quit, function call statistics example, scrolling a large file with :program:`less`. After you quit, function
will be printed to `stdout` and you can use tools like *kcachegrind* for more call statistics will be printed to STDOUT and you can use tools like
detailed analysis. *KCachegrind* for more detailed analysis.
Here are some CPU usage numbers for the task of scrolling a file continuously Here are some CPU usage numbers for the task of scrolling a file continuously in
in less. The CPU usage is for the terminal process and X together and is :program:`less`. The CPU usage is for the terminal process and X together and is
measured using htop. The measurements are taken at the same font and window measured using :program:`htop`. The measurements are taken at the same font and
size for all terminals on a ``Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz`` CPU window size for all terminals on a ``Intel(R) Core(TM) i7-4820K CPU @ 3.70GHz``
with a ``Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD CPU with a ``Advanced Micro Devices, Inc. [AMD/ATI] Cape Verde XT [Radeon HD
7770/8760 / R7 250X]`` GPU. 7770/8760 / R7 250X]`` GPU.
============== ========================= ============== =========================
@@ -49,11 +50,11 @@ admittedly biased, eyes).
.. note:: .. note::
Some people have asked why kitty does not perform better than terminal XXX in Some people have asked why kitty does not perform better than terminal XXX
the test of sinking large amounts of data, such as catting a large text in the test of sinking large amounts of data, such as catting a large text
file. The answer is because this is not a goal for kitty. kitty file. The answer is because this is not a goal for kitty. kitty deliberately
deliberately throttles input parsing and output rendering to minimize throttles input parsing and output rendering to minimize resource usage
resource usage while still being able to sink output faster than any real while still being able to sink output faster than any real world program can
world program can produce it. Reducing CPU usage, and hence battery drain produce it. Reducing CPU usage, and hence battery drain while achieving
while achieving instant response times and smooth scrolling to a human eye instant response times and smooth scrolling to a human eye is a far more
is a far more important goal. important goal.

View File

@@ -1,23 +1,24 @@
Terminal protocol extensions Terminal protocol extensions
=================================== ===================================
|kitty| has extensions to the legacy terminal protocol, to enable advanced features. |kitty| has extensions to the legacy terminal protocol, to enable advanced
These are typically in the form of new or re-purposed escape codes. While these features. These are typically in the form of new or re-purposed escape codes.
extensions are currently |kitty| specific, it would be nice to get some of them While these extensions are currently |kitty| specific, it would be nice to get
adopted more broadly, to push the state of terminal emulators forward. some of them adopted more broadly, to push the state of terminal emulators
forward.
The goal of these extensions is to be as small and unobtrusive as possible, The goal of these extensions is to be as small and unobtrusive as possible,
while filling in some gaps in the existing xterm protocol. In particular, one while filling in some gaps in the existing xterm protocol. In particular, one of
of the goals of this specification is explicitly not to "re-imagine" the tty. the goals of this specification is explicitly not to "re-imagine" the TTY. The
The tty should remain what it is -- a device for efficiently processing text TTY should remain what it is -- a device for efficiently processing text
received as a simple byte stream. Another objective is to only move the minimum received as a simple byte stream. Another objective is to only move the minimum
possible amount of extra functionality into the terminal program itself. This possible amount of extra functionality into the terminal program itself. This is
is to make it as easy to implement these protocol extensions as possible, to make it as easy to implement these protocol extensions as possible, thereby
thereby hopefully encouraging their widespread adoption. hopefully encouraging their widespread adoption.
If you wish to discuss these extensions, propose additions/changes to them If you wish to discuss these extensions, propose additions or changes to them,
please do so by opening issues in the `GitHub please do so by opening issues in the `GitHub bug tracker
<https://github.com/kovidgoyal/kitty/issues>`_ bug tracker. <https://github.com/kovidgoyal/kitty/issues>`__.
.. toctree:: .. toctree::

View File

@@ -9,9 +9,9 @@ Quickstart
binary binary
build build
Pre-built binaries of |kitty| are available for both macOS and Linux. Pre-built binaries of |kitty| are available for both macOS and Linux. See the
See the :doc:`binary install instructions </binary>`. You can also :doc:`binary install instructions </binary>`. You can also :doc:`build from
:doc:`build from source </build>`. source </build>`.
Additionally, you can use your favorite package manager to install the |kitty| Additionally, you can use your favorite package manager to install the |kitty|
package, but note that some Linux distribution packages are woefully outdated. package, but note that some Linux distribution packages are woefully outdated.
@@ -25,4 +25,4 @@ and Linux.
See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and
:doc:`Invocation <invocation>` for the command line arguments |kitty| supports. :doc:`Invocation <invocation>` for the command line arguments |kitty| supports.
For a tour of kitty's design and features, see the :doc:`/overview`. For a tour of kitty's design and features, see the :doc:`overview`.

View File

@@ -16,25 +16,26 @@ Where ``<ESC>`` is the byte ``0x1b``. The JSON object has the form::
"payload": <Optional JSON object>, "payload": <Optional JSON object>,
} }
The ``version`` above is an array of the form :code:`[0, 14, 2]`. If you are developing a The ``version`` above is an array of the form :code:`[0, 14, 2]`. If you are
standalone client, use the kitty version that you are developing against. Using developing a standalone client, use the kitty version that you are developing
a version greater than the version of the kitty instance you are talking to, against. Using a version greater than the version of the kitty instance you are
will cause a failure. talking to, will cause a failure.
Set ``no_response`` to ``true`` if you don't want a response from kitty. Set ``no_response`` to ``true`` if you don't want a response from kitty.
The optional payload is a JSON object that is specific to the actual command being sent. The optional payload is a JSON object that is specific to the actual command
The fields in the object for every command are documented below. being sent. The fields in the object for every command are documented below.
As a quick example showing how easy to use this protocol is, we will implement As a quick example showing how easy to use this protocol is, we will implement
the ``@ ls`` command from the shell using only shell tools. First, run kitty the ``@ ls`` command from the shell using only shell tools.
as::
First, run kitty as::
kitty -o allow_remote_control=socket-only --listen-on unix:/tmp/test kitty -o allow_remote_control=socket-only --listen-on unix:/tmp/test
Now, in a different terminal, you can get the pretty printed ``@ ls`` output Now, in a different terminal, you can get the pretty printed ``@ ls`` output
with the following command line:: 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 . 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 .
.. include:: generated/rc.rst .. include:: generated/rc.rst

View File

@@ -4,9 +4,12 @@ Control kitty from scripts
.. highlight:: sh .. highlight:: sh
|kitty| can be controlled from scripts or the shell prompt. You can open new |kitty| can be controlled from scripts or the shell prompt. You can open new
windows, send arbitrary text input to any window, name windows and tabs, etc. windows, send arbitrary text input to any window, change the title of windows
and tabs, etc.
Let's walk through a few examples of controlling |kitty|. Let's walk through a few examples of controlling |kitty|.
Tutorial Tutorial
------------ ------------
@@ -21,43 +24,44 @@ Now, in the new |kitty| window, enter the command::
kitty @ launch --title Output --keep-focus cat kitty @ launch --title Output --keep-focus cat
This will open a new window, running the ``cat`` program that will appear next This will open a new window, running the :program:`cat` program that will appear
to the current window. next to the current window.
Let's send some text to this new window:: Let's send some text to this new window::
kitty @ send-text --match cmdline:cat Hello, World kitty @ send-text --match cmdline:cat Hello, World
This will make ``Hello, World`` show up in the window running the ``cat`` program. This will make ``Hello, World`` show up in the window running the :program:`cat`
The :option:`kitty @ send-text --match` option is very powerful, it allows selecting windows by their program. The :option:`kitty @ send-text --match` option is very powerful, it
titles, the command line of the program running in the window, the working allows selecting windows by their titles, the command line of the program
directory of the program running in the window, etc. See ``kitty @ send-text running in the window, the working directory of the program running in the
--help`` for details. window, etc. See :ref:`kitty @ send-text --help <at_send-text>` for details.
More usefully, you can pipe the output of a command running in one window to More usefully, you can pipe the output of a command running in one window to
another window, for example:: another window, for example::
ls | kitty @ send-text --match title:Output --stdin ls | kitty @ send-text --match title:^Output --stdin
This will show the output of ls in the output window instead of the current This will show the output of :program:`ls` in the output window instead of the
window. You can use this technique to, for example, show the output of running current window. You can use this technique to, for example, show the output of
``make`` in your editor in a different window. The possibilities are endless. running :program:`make` in your editor in a different window. The possibilities
are endless.
You can even have things you type show up in a different window. Run:: You can even have things you type show up in a different window. Run::
kitty @ send-text --match title:Output --stdin kitty @ send-text --match title:^Output --stdin
And type some text, it will show up in the output window, instead of the current And type some text, it will show up in the output window, instead of the current
window. Type ``Ctrl+D`` when you are ready to stop. window. Type :kbd:`Ctrl+D` when you are ready to stop.
Now, let's open a new tab:: Now, let's open a new tab::
kitty @ launch --type=tab --tab-title "My Tab" --keep-focus bash kitty @ launch --type=tab --tab-title "My Tab" --keep-focus bash
This will open a new tab running the bash shell with the title "My Tab". This will open a new tab running the bash shell with the title "My Tab".
We can change the title of the tab with:: We can change the title of the tab to "New Title" with::
kitty @ set-tab-title --match title:My New Title kitty @ set-tab-title --match title:^My New Title
Let's change the title of the current tab:: Let's change the title of the current tab::
@@ -65,79 +69,83 @@ Let's change the title of the current tab::
Now lets switch to the newly opened tab:: Now lets switch to the newly opened tab::
kitty @ focus-tab --match title:New kitty @ focus-tab --match title:^New
Similarly, to focus the previously opened output window (which will also switch Similarly, to focus the previously opened output window (which will also switch
back to the old tab, automatically):: back to the old tab, automatically)::
kitty @ focus-window --match title:Output kitty @ focus-window --match title:^Output
You can get a listing of available tabs and windows, by running:: You can get a listing of available tabs and windows, by running::
kitty @ ls kitty @ ls
This outputs a tree of data in JSON format. The top level of the tree is all This outputs a tree of data in JSON format. The top level of the tree is all
operating system kitty windows. Each OS window has an id and a list of tabs. :term:`OS windows <os_window>`. Each OS window has an id and a list of
Each tab has its own id, a title and a list of windows. Each window has an id, :term:`tabs <tab>`. Each tab has its own id, a title and a list of :term:`kitty
title, current working directory, process id (PID) and command-line of the windows <window>`. Each window has an id, title, current working directory,
process running in the window. You can use this information with :option:`kitty @ focus-window --match` process id (PID) and command-line of the process running in the window. You can
to control individual windows. use this information with :option:`kitty @ focus-window --match` to control
individual windows.
As you can see, it is very easy to control |kitty| using the As you can see, it is very easy to control |kitty| using the ``kitty @``
``kitty @`` messaging system. This tutorial touches only the messaging system. This tutorial touches only the surface of what is possible.
surface of what is possible. See ``kitty @ --help`` for more details. See ``kitty @ --help`` for more details.
Note that in the example's above, ``kitty @`` messaging works only when run inside a |kitty| window, Note that in the example's above, ``kitty @`` messaging works only when run
not anywhere. But, within a |kitty| window it even works over SSH. If you want to control inside a |kitty| window, not anywhere. But, within a |kitty| window it even
|kitty| from programs/scripts not running inside a |kitty| window, you have to implement a couple of works over SSH. If you want to control |kitty| from programs/scripts not running
extra steps. First start |kitty| as:: inside a |kitty| window, you have to implement a couple of extra steps. First
start |kitty| as::
kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty
The :option:`kitty --listen-on` option tells |kitty| to listen for control messages at the The :option:`kitty --listen-on` option tells |kitty| to listen for control
specified path. See ``kitty --help`` for details. Now you can control this messages at the specified UNIX-domain socket. See ``kitty --help`` for details.
instance of |kitty| using the :option:`kitty @ --to` command line argument to ``kitty @``. For example:: Now you can control this instance of |kitty| using the :option:`kitty @ --to`
command line argument to ``kitty @``. For example::
kitty @ --to unix:/tmp/mykitty ls kitty @ --to unix:/tmp/mykitty ls
Note that if all you want to do is run a single |kitty| "daemon" and have subsequent Note that if all you want to do is run a single |kitty| "daemon" and have
|kitty| invocations appear as new top-level windows, you can use the simpler :option:`kitty --single-instance` subsequent |kitty| invocations appear as new top-level windows, you can use the
option, see ``kitty --help`` for that. simpler :option:`kitty --single-instance` option, see ``kitty --help`` for that.
The builtin kitty shell The builtin kitty shell
-------------------------- --------------------------
You can explore the |kitty| command language more easily using the builtin |kitty| You can explore the |kitty| command language more easily using the builtin
shell. Run ``kitty @`` with no arguments and you will be dropped into the |kitty| |kitty| shell. Run ``kitty @`` with no arguments and you will be dropped into
shell with completion for |kitty| command names and options. the |kitty| shell with completion for |kitty| command names and options.
You can even open the |kitty| shell inside a running |kitty| using a simple You can even open the |kitty| shell inside a running |kitty| using a simple
keyboard shortcut (:sc:`kitty_shell` by default). keyboard shortcut (:sc:`kitty_shell` by default).
.. note:: This has the added advantage that you don't need to use .. note:: This has the added advantage that you don't need to use
``allow_remote_control`` to make it work. :opt:`allow_remote_control` to make it work.
Allowing only some windows to control kitty Allowing only some windows to control kitty
---------------------------------------------- ----------------------------------------------
If you do not want to allow all programs running in |kitty| to control it, you can selectively If you do not want to allow all programs running in |kitty| to control it, you
enable remote control for only some |kitty| windows. Simply create a shortcut can selectively enable remote control for only some |kitty| windows. Simply
such as:: create a shortcut such as::
map ctrl+k launch --allow-remote-control some_program map ctrl+k launch --allow-remote-control some_program
Then programs running in windows created with that shortcut can use ``kitty @`` Then programs running in windows created with that shortcut can use ``kitty @``
to control kitty. Note that any program with the right level of permissions can to control kitty. Note that any program with the right level of permissions can
still write to the pipes of any other program on the same computer and still write to the pipes of any other program on the same computer and therefore
therefore can control |kitty|. It can, however, be useful to block programs can control |kitty|. It can, however, be useful to block programs running on
running on other computers (for example, over ssh) or as other users. other computers (for example, over SSH) or as other users.
.. note:: You dont need ``allow_remote_control`` to make this work as it is .. note:: You don't need :opt:`allow_remote_control` to make this work as it is
limited to only programs running in that specific window. Be careful with limited to only programs running in that specific window. Be careful with
what programs you run in such windows, since they can effectively control what programs you run in such windows, since they can effectively control
kitty, as if you were running with ``allow_remote_control`` turned on. kitty, as if you were running with :opt:`allow_remote_control` turned on.
.. _rc_mapping: .. _rc_mapping:
@@ -148,15 +156,15 @@ Mapping key presses to remote control commands
If you wish to trigger a remote control command easily with just a keypress, If you wish to trigger a remote control command easily with just a keypress,
you can map it in :file:`kitty.conf`. For example:: you can map it in :file:`kitty.conf`. For example::
map F1 remote_control set-spacing margin=30 map f1 remote_control set-spacing margin=30
Then pressing the :kbd:`F1` key will set the active window margins to 30. Then pressing the :kbd:`F1` key will set the active window margins to
The syntax for what follows :code:`remote_control` is exactly the same :code:`30`. The syntax for what follows :ac:`remote_control` is exactly the same
as the syntax for what follows :code:`kitty @` above. as the syntax for what follows :code:`kitty @` above.
.. note:: You do not need ``allow_remote_control`` to use these mappings, .. note:: You do not need :opt:`allow_remote_control` to use these mappings,
as they are not actual remote programs, but are simply a way to resuse as they are not actual remote programs, but are simply a way to resuse the
the remote control infrastructure via keybings. remote control infrastructure via keybings.
Broadcasting what you type to all kitty windows Broadcasting what you type to all kitty windows
@@ -166,17 +174,36 @@ As a simple illustration of the power of remote control, lets
have what we type sent to all open kitty windows. To do that define the have what we type sent to all open kitty windows. To do that define the
following mapping in :file:`kitty.conf`:: following mapping in :file:`kitty.conf`::
map F1 launch --allow-remote-control kitty +kitten broadcast map f1 launch --allow-remote-control kitty +kitten broadcast
Now press, F1 and start typing, what you type will be sent to all windows, Now press :kbd:`F1` and start typing, what you type will be sent to all windows,
live, as you type it. live, as you type it.
The remote control protocol The remote control protocol
----------------------------------------------- -----------------------------------------------
If you wish to develop your own client to talk to |kitty|, you If you wish to develop your own client to talk to |kitty|, you can use the
can use the :doc:`protocol specification <rc_protocol>`. :doc:`remote control protocol specification <rc_protocol>`.
.. _search_syntax:
Matching windows and tabs
----------------------------
Many remote control operations operate on windows or tabs. To select these, the
:code:`--match` option is often used. This allows matching using various
sophisticated criteria such as title, ids, cmdlines, etc. These criteria are
expressions of the form :code:`field:query`. Where :italic:`field` is the field
against which to match and :italic:`query` is the expression to match. They can
be further combined using Boolean operators, best illustrated with some
examples::
title:"My special window" or id:43
title:bash and env:USER=kovid
not id:1
(id:2 or id:3) and title:something
.. toctree:: .. toctree::
:hidden: :hidden:

View File

@@ -4,8 +4,8 @@ Shell integration
------------------- -------------------
kitty has the ability to integrate closely within common shells, such as `zsh kitty has the ability to integrate closely within common shells, such as `zsh
<https://www.zsh.org/>`_, `fish <https://fishshell.com>`_ and `bash <https://www.zsh.org/>`__, `fish <https://fishshell.com>`__ and `bash
<https://www.gnu.org/software/bash/>`_ to enable features such as jumping to <https://www.gnu.org/software/bash/>`__ to enable features such as jumping to
previous prompts in the scrollback, viewing the output of the last command in previous prompts in the scrollback, viewing the output of the last command in
:program:`less`, using the mouse to move the cursor while editing prompts, etc. :program:`less`, using the mouse to move the cursor while editing prompts, etc.
@@ -22,7 +22,7 @@ Features
* Click with the mouse anywhere in the current command to move the cursor there * Click with the mouse anywhere in the current command to move the cursor there
* Hold :kbd:`ctrl+shift` and right-click on any command output in the scrollback * Hold :kbd:`Ctrl+Shift` and right-click on any command output in the scrollback
to view it in a pager to view it in a pager
* The current working directory or the command being executed are automatically * The current working directory or the command being executed are automatically
@@ -30,6 +30,9 @@ Features
* The text cursor is changed to a bar when editing commands at the shell prompt * The text cursor is changed to a bar when editing commands at the shell prompt
* :ref:`clone_shell` with all environment variables and the working directory
copied
* Glitch free window resizing even with complex prompts. Achieved by erasing * Glitch free window resizing even with complex prompts. Achieved by erasing
the prompt on resize and allowing the shell to redraw it cleanly. the prompt on resize and allowing the shell to redraw it cleanly.
@@ -43,7 +46,7 @@ Configuration
--------------- ---------------
Shell integration is controlled by the :opt:`shell_integration` option. By Shell integration is controlled by the :opt:`shell_integration` option. By
default, all shell integration is enabled. Individual features can be turned default, all integration features are enabled. Individual features can be turned
off or it can be disabled entirely as well. The :opt:`shell_integration` option off or it can be disabled entirely as well. The :opt:`shell_integration` option
takes a space separated list of keywords: takes a space separated list of keywords:
@@ -53,26 +56,28 @@ disabled
:ref:`manual integration <manual_shell_integration>`. :ref:`manual integration <manual_shell_integration>`.
no-rc no-rc
Do not modify the shell's launch environment to enable integration. Useful if you prefer Do not modify the shell's launch environment to enable integration. Useful
to load the kitty shell integration code yourself, either as part of if you prefer to load the kitty shell integration code yourself, either as
:ref:`manually integration <manual_shell_integration>` or because you have part of :ref:`manually integration <manual_shell_integration>` or because
some other software that sets up shell integration. you have some other software that sets up shell integration.
This will still set the :envvar:`KITTY_SHELL_INTEGRATION` environment variable when kitty runs the shell. This will still set the :envvar:`KITTY_SHELL_INTEGRATION` environment
variable when kitty runs the shell.
no-cursor no-cursor
Turn off changing of the text cursor to a bar when editing text Turn off changing of the text cursor to a bar when editing shell command
line.
no-title no-title
Turn off setting the kitty window/tab title based on shell state. Turn off setting the kitty window/tab title based on shell state.
Note that for the ``fish`` shell kitty relies on fish's native title Note that for the fish shell kitty relies on fish's native title setting
setting functionality instead. functionality instead.
no-cwd no-cwd
Turn off reporting the current working directory. This is used to allow Turn off reporting the current working directory. This is used to allow
:ac:`new_window_with_cwd` and similar to open windows logged :ac:`new_window_with_cwd` and similar to open windows logged into remote
into remote machines using the :doc:`ssh kitten <kittens/ssh>` machines using the :doc:`ssh kitten <kittens/ssh>` automatically with the
automatically with the same working directory as the current window. same working directory as the current window.
Note that for the ``fish`` shell this will not disable its built-in current Note that for the fish shell this will not disable its built-in current
working directory reporting. working directory reporting.
no-prompt-mark no-prompt-mark
@@ -81,16 +86,16 @@ no-prompt-mark
no-complete no-complete
Turn off completion for the kitty command. Turn off completion for the kitty command.
Note that for the ``fish`` shell this does not take effect, since fish Note that for the fish shell this does not take effect, since fish already
already comes with a kitty completion script. comes with a kitty completion script.
More ways to browse command output More ways to browse command output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can add further key and mouse bindings to browse the output of commands You can add further key and mouse bindings to browse the output of commands
easily. For example to select the output of a command by right clicking the mouse easily. For example to select the output of a command by right clicking the
on the output, define the following in :file:`kitty.conf`: mouse on the output, define the following in :file:`kitty.conf`:
.. code:: conf .. code:: conf
@@ -101,8 +106,8 @@ to be copied.
The feature to jump to previous prompts ( The feature to jump to previous prompts (
:sc:`scroll_to_previous_prompt` and :sc:`scroll_to_next_prompt`) and mouse :sc:`scroll_to_previous_prompt` and :sc:`scroll_to_next_prompt`) and mouse
actions (:ac:`mouse_select_command_output` and :ac:`mouse_show_command_output`) can actions (:ac:`mouse_select_command_output` and :ac:`mouse_show_command_output`)
be integrated with browsing command output as well. For example, define the can be integrated with browsing command output as well. For example, define the
following mapping in :file:`kitty.conf`: following mapping in :file:`kitty.conf`:
.. code:: conf .. code:: conf
@@ -134,34 +139,34 @@ How it works
----------------- -----------------
At startup, kitty detects if the shell you have configured (either system wide At startup, kitty detects if the shell you have configured (either system wide
or in kitty.conf) is a supported shell. If so, kitty injects some shell specific or the :opt:`shell` option in :file:`kitty.conf`) is a supported shell. If so,
code into the shell, to enable shell integration. How it does so varies for kitty injects some shell specific code into the shell, to enable shell
different shells. integration. How it does so varies for different shells.
.. tab:: zsh .. tab:: zsh
For zsh, kitty sets the ``ZDOTDIR`` environment variable to make zsh load For zsh, kitty sets the :envvar:`ZDOTDIR` environment variable to make zsh
kitty's :file:`.zshenv` which restores the original value of ``ZDOTDIR`` load kitty's :file:`.zshenv` which restores the original value of
and sources the original :file:`.zshenv`. It then loads the shell integration code. :envvar:`ZDOTDIR` and sources the original :file:`.zshenv`. It then loads
The remainder of zsh's startup process proceeds as normal. the shell integration code. The remainder of zsh's startup process proceeds
as normal.
.. tab:: fish .. tab:: fish
For fish, to make it automatically load the integration code provided by For fish, to make it automatically load the integration code provided by
kitty, the integration script directory path is prepended to the kitty, the integration script directory path is prepended to the
``XDG_DATA_DIRS`` environment variable. This is only applied to the fish :envvar:`XDG_DATA_DIRS` environment variable. This is only applied to the
process and will be cleaned up by the integration script after startup. No files fish process and will be cleaned up by the integration script after startup.
are added or modified. No files are added or modified.
.. tab:: bash .. tab:: bash
For bash, kitty starts bash in POSIX mode, using the environment variable For bash, kitty starts bash in POSIX mode, using the environment variable
``ENV`` to load the shell integration script. This prevents bash from :envvar:`ENV` to load the shell integration script. This prevents bash from
loading any startup files itself. The loading of the startup files is done loading any startup files itself. The loading of the startup files is done
by the integration script, after disabling POSIX mode. From the by the integration script, after disabling POSIX mode. From the perspective
perspective of those scripts there should be no difference to running of those scripts there should be no difference to running vanilla bash.
vanilla bash.
Then, when launching the shell, kitty sets the environment variable Then, when launching the shell, kitty sets the environment variable
@@ -215,6 +220,49 @@ shell integration. Alternately, you can :ref:`setup shell integration manually
the remote server and editing the shell rc files there, as described below. the remote server and editing the shell rc files there, as described below.
.. _clone_shell:
Clone the current shell into a new window
-----------------------------------------------
You can clone the current shell into a new kitty window by simply running the
:command:`clone-in-kitty` command, for example:
.. code-block:: sh
clone-in-kitty
clone-in-kitty --type=tab
clone-in-kitty --title "I am a clone"
This will open a new window running a new shell instance but with all
environment variables and the current working directory copied. This even works
over SSH when using :doc:`kittens/ssh`.
The :command:`clone-in-kitty` command takes almost all the same arguments as the
:doc:`launch <launch>` command, so you can open a new tab instead or a new OS
window, etc. Arguments of launch that can cause code execution or that don't
make sense when cloning are ignored. Most prominently, the following options are
ignored: :option:`--allow-remote-control <launch --allow-remote-control>`,
:option:`--copy-cmdline <launch --copy-cmdline>`, :option:`--copy-env <launch
--copy-env>`, :option:`--stdin-source <launch --stdin-source>`,
:option:`--marker <launch --marker>` and :option:`--watcher <launch --watcher>`.
:command:`clone-in-kitty` can be configured to source arbitrary code in the
cloned window using environment variables. It will automatically clone virtual
environments created by the :link:`Python venv module
<https://docs.python.org/3/library/venv.html>` or :link:`Conda
<https://conda.io/>`. In addition, setting the
env var :envvar:`KITTY_CLONE_SOURCE_CODE` to some shell code will cause that
code to be run in the cloned window with :code:`eval`. Similarly, setting
:envvar:`KITTY_CLONE_SOURCE_PATH` to the path of a file will cause that file to
be sourced in the cloned window. This can be controlled by
:opt:`clone_source_strategies`.
:command:`clone-in-kitty` works by asking the shell to serialize its internal
state (mainly CWD and env vars) and this state is transmitted to kitty and
restored by the shell integration scripts in the cloned window.
.. _manual_shell_integration: .. _manual_shell_integration:
Manual shell integration Manual shell integration
@@ -276,9 +324,10 @@ to point to the location of the scripts.
Integration with other shells Integration with other shells
------------------------------- -------------------------------
There exist third-party integrations to use these features for various other shells: There exist third-party integrations to use these features for various other
shells:
* Jupyter console via a patch (:iss:`4475`) * Jupyter console and IPython via a patch (:iss:`4475`)
* `xonsh <https://github.com/xonsh/xonsh/issues/4623>`__ * `xonsh <https://github.com/xonsh/xonsh/issues/4623>`__

View File

@@ -1,24 +1,25 @@
Colored and styled underlines Colored and styled underlines
================================ ================================
|kitty| supports colored and styled (wavy) underlines. This is of particular |kitty| supports colored and styled (wavy) underlines. This is of particular use
use in terminal editors such as vim and emacs to display red, wavy underlines in terminal based text editors such as :program:`vim` and :program:`emacs` to
under mis-spelled words and/or syntax errors. This is done by re-purposing some display red, wavy underlines under mis-spelled words and/or syntax errors. This
SGR escape codes that are not used in modern terminals (`CSI codes is done by re-purposing some SGR escape codes that are not used in modern
<https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences>`_) terminals (`CSI codes <https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_(Control_Sequence_Introducer)_sequences>`__)
To set the underline style:: To set the underline style::
<ESC>[4:0m # this is no underline <ESC>[4:0m # no underline
<ESC>[4:1m # this is a straight underline <ESC>[4:1m # straight underline
<ESC>[4:2m # this is a double underline <ESC>[4:2m # double underline
<ESC>[4:3m # this is a curly underline <ESC>[4:3m # curly underline
<ESC>[4:4m # this is a dotted underline <ESC>[4:4m # dotted underline
<ESC>[4:5m # this is a dashed underline <ESC>[4:5m # dashed underline
<ESC>[4m # this is a straight underline (for backwards compat) <ESC>[4m # straight underline (for backwards compat)
<ESC>[24m # this is no underline (for backwards compat) <ESC>[24m # no underline (for backwards compat)
To set the underline color (this is reserved and as far as I can tell not actually used for anything):: To set the underline color (this is reserved and as far as I can tell not
actually used for anything)::
<ESC>[58...m <ESC>[58...m
@@ -29,8 +30,8 @@ To reset the underline color (also previously reserved and unused)::
<ESC>[59m <ESC>[59m
The underline color must remain the same under reverse video, if it has a The underline color must remain the same under reverse video, if it has a color,
color, if not, it should follow the foreground color. if not, it should follow the foreground color.
To detect support for this feature in a terminal emulator, query the terminfo database To detect support for this feature in a terminal emulator, query the terminfo
for the ``Su`` boolean capability. database for the ``Su`` boolean capability.

View File

@@ -4,10 +4,10 @@ Unscrolling the screen
======================== ========================
This is a small extension to the `SD (Pan up) escape code This is a small extension to the `SD (Pan up) escape code
<https://vt100.net/docs/vt510-rm/SD.html>`_ from the VT-420 terminal. The <https://vt100.net/docs/vt510-rm/SD.html>`_ from the VT-420 terminal. The ``SD``
``SD`` escape code normally causes the text on screen to scroll down by the escape code normally causes the text on screen to scroll down by the specified
specified number of lines, with empty lines appearing at the top of the screen. number of lines, with empty lines appearing at the top of the screen. This
This extension allows the new lines to be filled in from the scrollback buffer extension allows the new lines to be filled in from the scrollback buffer
instead of being blank. instead of being blank.
The motivation for this is that many modern shells will show completions in a The motivation for this is that many modern shells will show completions in a
@@ -22,17 +22,17 @@ scrolled down is implementation defined, but must be at least one screen worth.
The syntax of the escape code is identical to that of ``SD`` except that it has The syntax of the escape code is identical to that of ``SD`` except that it has
a trailing ``+`` modifier. This is legal under the `ECMA 48 standard a trailing ``+`` modifier. This is legal under the `ECMA 48 standard
<https://www.ecma-international.org/publications-and-standards/standards/ecma-48/>`_ <https://www.ecma-international.org/publications-and-standards/standards/ecma-48/>`__
and unused for any other purpose as far as I can tell. So for example, to and unused for any other purpose as far as I can tell. So for example, to
unscroll three lines, the escape code would be:: unscroll three lines, the escape code would be::
CSI 3 + T CSI 3 + T
See `discussion here See `discussion here
<https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/30>`_. <https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/30>`__.
.. versionadded:: 0.20.2 .. versionadded:: 0.20.2
Also supported by the terminals: Also supported by the terminals:
* `mintty <https://github.com/mintty/mintty/releases/tag/3.5.2>`_ * `mintty <https://github.com/mintty/mintty/releases/tag/3.5.2>`__

View File

@@ -1731,7 +1731,11 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (!createNativeWindow(window, wndconfig, fbconfig)) if (!createNativeWindow(window, wndconfig, fbconfig))
return false; return false;
[window->ns.object setColorSpace:[NSColorSpace sRGBColorSpace]]; switch((GlfwCocoaColorSpaces)wndconfig->ns.color_space) {
case SRGB_COLORSPACE: [window->ns.object setColorSpace:[NSColorSpace sRGBColorSpace]]; break;
case DISPLAY_P3_COLORSPACE: [window->ns.object setColorSpace:[NSColorSpace displayP3ColorSpace]]; break;
case DEFAULT_COLORSPACE: break;
}
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {

13
glfw/glfw3.h vendored
View File

@@ -1024,6 +1024,16 @@ typedef enum GLFWMouseButton {
* [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint).
*/ */
#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003
/*! @brief macOS specific
* [window hint](@ref GLFW_COCOA_COLOR_SPACE_hint).
*/
#define GLFW_COCOA_COLOR_SPACE 0x00023004
typedef enum {
DEFAULT_COLORSPACE = 0,
SRGB_COLORSPACE = 1,
DISPLAY_P3_COLORSPACE = 2,
} GlfwCocoaColorSpaces;
/*! @brief X11 specific /*! @brief X11 specific
* [window hint](@ref GLFW_X11_CLASS_NAME_hint). * [window hint](@ref GLFW_X11_CLASS_NAME_hint).
*/ */
@@ -1206,7 +1216,8 @@ typedef enum {
typedef enum { typedef enum {
GLFW_IME_NONE, GLFW_IME_NONE,
GLFW_IME_PREEDIT_CHANGED, GLFW_IME_PREEDIT_CHANGED,
GLFW_IME_COMMIT_TEXT GLFW_IME_COMMIT_TEXT,
GLFW_IME_WAYLAND_DONE_EVENT,
} GLFWIMEState; } GLFWIMEState;
typedef enum { typedef enum {

1
glfw/internal.h vendored
View File

@@ -307,6 +307,7 @@ struct _GLFWwndconfig
bool scaleToMonitor; bool scaleToMonitor;
struct { struct {
bool retina; bool retina;
int color_space;
char frameName[256]; char frameName[256];
} ns; } ns;
struct { struct {

5
glfw/window.c vendored
View File

@@ -332,6 +332,8 @@ void glfwDefaultWindowHints(void)
// The default is to use full Retina resolution framebuffers // The default is to use full Retina resolution framebuffers
_glfw.hints.window.ns.retina = true; _glfw.hints.window.ns.retina = true;
// use the default colorspace assigned by the system
_glfw.hints.window.ns.color_space = 0;
} }
GLFWAPI void glfwWindowHint(int hint, int value) GLFWAPI void glfwWindowHint(int hint, int value)
@@ -412,6 +414,9 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_COCOA_RETINA_FRAMEBUFFER: case GLFW_COCOA_RETINA_FRAMEBUFFER:
_glfw.hints.window.ns.retina = value ? true : false; _glfw.hints.window.ns.retina = value ? true : false;
return; return;
case GLFW_COCOA_COLOR_SPACE:
_glfw.hints.window.ns.color_space = value;
return;
case GLFW_COCOA_GRAPHICS_SWITCHING: case GLFW_COCOA_GRAPHICS_SWITCHING:
_glfw.hints.context.nsgl.offline = value ? true : false; _glfw.hints.context.nsgl.offline = value ? true : false;
return; return;

5
glfw/wl_init.c vendored
View File

@@ -143,10 +143,15 @@ static void setCursor(GLFWCursorShape shape, _GLFWwindow* window)
if (!image) if (!image)
return; return;
if (image->width % scale || image->height % scale) {
_glfwInputError(GLFW_PLATFORM_ERROR, "WARNING: Cursor image size: %dx%d is not a multiple of window scale: %d. This will"
" cause some compositors such as GNOME to crash. See https://github.com/kovidgoyal/kitty/issues/4878", image->width, image->height, scale);
}
buffer = wl_cursor_image_get_buffer(image); buffer = wl_cursor_image_get_buffer(image);
if (!buffer) if (!buffer)
return; return;
debug("Calling wl_pointer_set_cursor in setCursor with surface: %p\n", (void*)surface);
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
surface, surface,
image->hotspot_x / scale, image->hotspot_x / scale,

View File

@@ -84,7 +84,7 @@ text_input_delete_surrounding_text(
} }
static void static void
text_input_done(void *data UNUSED, struct zwp_text_input_v3 *txt_input UNUSED, uint32_t serial UNUSED) { text_input_done(void *data UNUSED, struct zwp_text_input_v3 *txt_input UNUSED, uint32_t serial) {
debug("text-input: done event: serial: %u current_commit_serial: %u\n", serial, commit_serial); debug("text-input: done event: serial: %u current_commit_serial: %u\n", serial, commit_serial);
if (serial != commit_serial) { if (serial != commit_serial) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: text_input_done serial mismatch, expected=%u got=%u\n", commit_serial, serial); _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: text_input_done serial mismatch, expected=%u got=%u\n", commit_serial, serial);
@@ -95,7 +95,7 @@ text_input_done(void *data UNUSED, struct zwp_text_input_v3 *txt_input UNUSED, u
free(pending_pre_edit); pending_pre_edit = NULL; free(pending_pre_edit); pending_pre_edit = NULL;
} else { } else {
// Clear pre-edit text // Clear pre-edit text
send_text(NULL, GLFW_IME_PREEDIT_CHANGED); send_text(NULL, GLFW_IME_WAYLAND_DONE_EVENT);
} }
if (pending_commit) { if (pending_commit) {
send_text(pending_commit, GLFW_IME_COMMIT_TEXT); send_text(pending_commit, GLFW_IME_COMMIT_TEXT);

3
glfw/wl_window.c vendored
View File

@@ -147,6 +147,7 @@ setCursorImage(_GLFWwindow* window, bool on_theme_change) {
cursorWayland->yhot = image->hotspot_y; cursorWayland->yhot = image->hotspot_y;
} }
debug("Calling wl_pointer_set_cursor in setCursorImage with surface: %p\n", (void*)surface);
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
surface, surface,
cursorWayland->xhot / scale, cursorWayland->xhot / scale,
@@ -1397,6 +1398,7 @@ static void lockPointer(_GLFWwindow* window)
window->wl.pointerLock.relativePointer = relativePointer; window->wl.pointerLock.relativePointer = relativePointer;
window->wl.pointerLock.lockedPointer = lockedPointer; window->wl.pointerLock.lockedPointer = lockedPointer;
debug("Calling wl_pointer_set_cursor in lockPointer with surface: %p\n", NULL);
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
NULL, 0, 0); NULL, 0, 0);
} }
@@ -1433,6 +1435,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
} }
else if (window->cursorMode == GLFW_CURSOR_HIDDEN) else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
{ {
debug("Calling wl_pointer_set_cursor in _glfwPlatformSetCursor with surface: %p\n", NULL);
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0); wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial, NULL, 0, 0);
} }
} }

View File

@@ -92,17 +92,17 @@ be used for completions and via the browse history readline bindings.
--choice -c --choice -c
type=list type=list
dest=choices dest=choices
A choice for the choices type. Every choice has the syntax: letter:text Where A choice for the choices type. Can be specified multiple times. Every choice has
letter is the accelerator key and text is the corresponding text. There can be the syntax: ``letter[;color]:text``. Where :italic:`letter` is the accelerator key
an optional color specification after the letter to indicate what color it should and :italic:`text` is the corresponding text. There can be an optional color
be. specification after the letter to indicate what color it should be.
For example: y:Yes and n;red:No For example: :code:`y:Yes` and :code:`n;red:No`
--default -d --default -d
A default choice or text. If unspecified, it is "y" for :code:`yesno`, the first choice A default choice or text. If unspecified, it is :code:`y` for the type
for :code:`choices` and empty for others. The default choice is selected when the user :code:`yesno`, the first choice for :code:`choices` and empty for others types.
presses the Enter key. The default choice is selected when the user presses the :kbd:`Enter` key.
--prompt -p --prompt -p
@@ -406,7 +406,7 @@ def main(args: List[str]) -> Response:
except SystemExit as e: except SystemExit as e:
if e.code != 0: if e.code != 0:
print(e.args[0]) print(e.args[0])
input('Press enter to quit...') input('Press Enter to quit')
raise SystemExit(e.code) raise SystemExit(e.code)
if cli_opts.type in ('yesno', 'choices'): if cli_opts.type in ('yesno', 'choices'):

View File

@@ -99,7 +99,7 @@ class Broadcast(Handler):
OPTIONS = (MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format OPTIONS = (MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')).format
help_text = 'Broadcast typed text to all kitty windows. By default text is sent to all windows, unless one of the matching options is specified' 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 ...]' usage = '[initial text to send ...]'

View File

@@ -57,7 +57,7 @@ OPTIONS = r'''
default=False default=False
type=bool-set type=bool-set
Output the current contents of the clipboard to STDOUT. Note that by default Output the current contents of the clipboard to STDOUT. Note that by default
kitty will prompt you asking to allow access to the clipboard. Can be controlled kitty will prompt for permission to access the clipboard. Can be controlled
by :opt:`clipboard_control`. by :opt:`clipboard_control`.
@@ -93,7 +93,10 @@ def main(args: List[str]) -> NoReturn:
data: Optional[bytes] = None data: Optional[bytes] = None
if not sys.stdin.isatty(): if not sys.stdin.isatty():
data = sys.stdin.buffer.read() data = sys.stdin.buffer.read()
sys.stdin = open(os.ctermid()) try:
sys.stdin = open(os.ctermid())
except FileNotFoundError:
raise SystemExit('Not connected to a controlling terminal device, no /dev/tty')
loop = Loop() loop = Loop()
handler = Clipboard(data, cli_opts) handler = Clipboard(data, cli_opts)
loop.loop(handler) loop.loop(handler)

View File

@@ -161,7 +161,7 @@ def highlight_collection(collection: Collection, aliases: Optional[Dict[str, str
if p: if p:
is_binary = isinstance(data_for_path(p), bytes) is_binary = isinstance(data_for_path(p), bytes)
if not is_binary: if not is_binary:
jobs[executor.submit(highlight_for_diff, p, aliases)] = p jobs[executor.submit(highlight_for_diff, p, aliases or {})] = p
for future in concurrent.futures.as_completed(jobs): for future in concurrent.futures.as_completed(jobs):
path = jobs[future] path = jobs[future]
try: try:

View File

@@ -571,8 +571,8 @@ OPTIONS = partial('''\
--context --context
type=int type=int
default=-1 default=-1
Number of lines of context to show between changes. Negative values Number of lines of context to show between changes. Negative values use the
use the number set in diff.conf number set in :file:`diff.conf`.
--config --config
@@ -599,7 +599,7 @@ class ShowWarning:
showwarning = ShowWarning() showwarning = ShowWarning()
help_text = 'Show a side-by-side diff of the specified files/directories. You can also use ssh:hostname:remote-file-path to diff remote files.' help_text = 'Show a side-by-side diff of the specified files/directories. You can also use :italic:`ssh:hostname:remote-file-path` to diff remote files.'
usage = 'file_or_directory_left file_or_directory_right' usage = 'file_or_directory_left file_or_directory_right'

View File

@@ -24,8 +24,8 @@ agr('diff', 'Diffing')
opt('syntax_aliases', 'pyj:py pyi:py recipe:py', opt('syntax_aliases', 'pyj:py pyi:py recipe:py',
option_type='syntax_aliases', option_type='syntax_aliases',
long_text=''' long_text='''
File extension aliases for syntax highlight For example, to syntax highlight File extension aliases for syntax highlight. For example, to syntax highlight
:file:`file.xyz` as :file:`file.abc` use a setting of :code:`xyz:abc` :file:`file.xyz` as :file:`file.abc` use a setting of :code:`xyz:abc`.
''' '''
) )
@@ -37,8 +37,9 @@ opt('num_context_lines', '3',
opt('diff_cmd', 'auto', opt('diff_cmd', 'auto',
long_text=''' long_text='''
The diff command to use. Must contain the placeholder :code:`_CONTEXT_` which The diff command to use. Must contain the placeholder :code:`_CONTEXT_` which
will be replaced by the number of lines of context. The default is to search the will be replaced by the number of lines of context. The default special value
system for either git or diff and use that, if found. :code:`auto` is to search the system for either :program:`git` or
:program:`diff` and use that, if found.
''' '''
) )

View File

@@ -153,7 +153,7 @@ class Hunk:
if c.left_start + c.left_count != self.left_start + self.left_count: if c.left_start + c.left_count != self.left_start + self.left_count:
raise ValueError(f'Left side line mismatch {c.left_start + c.left_count} != {self.left_start + self.left_count}') raise ValueError(f'Left side line mismatch {c.left_start + c.left_count} != {self.left_start + self.left_count}')
if c.right_start + c.right_count != self.right_start + self.right_count: if c.right_start + c.right_count != self.right_start + self.right_count:
raise ValueError(f'Left side line mismatch {c.right_start + c.right_count} != {self.right_start + self.right_count}') raise ValueError(f'Right side line mismatch {c.right_start + c.right_count} != {self.right_start + self.right_count}')
for c in self.chunks: for c in self.chunks:
c.finalize() c.finalize()
@@ -200,7 +200,7 @@ def parse_patch(raw: str) -> Patch:
else: else:
if current_hunk is None: if current_hunk is None:
continue continue
q = line[0] q = line[0] if line else ''
if q == '+': if q == '+':
current_hunk.add_line() current_hunk.add_line()
elif q == '-': elif q == '-':

View File

@@ -36,6 +36,8 @@ def images_supported() -> bool:
class Ref: class Ref:
__slots__: Tuple[str, ...] = ()
def __setattr__(self, name: str, value: object) -> None: def __setattr__(self, name: str, value: object) -> None:
raise AttributeError("can't set attribute") raise AttributeError("can't set attribute")

View File

@@ -525,10 +525,10 @@ OPTIONS = r'''
--program --program
type=list type=list
What program to use to open matched text. Defaults to the default open program What program to use to open matched text. Defaults to the default open program
for the operating system. Use a value of :file:`-` to paste the match into the for the operating system. Use a value of :code:`-` to paste the match into the
terminal window instead. A value of :file:`@` will copy the match to the terminal window instead. A value of :code:`@` will copy the match to the
clipboard. A value of :file:`*` will copy the match to the primary selection clipboard. A value of :code:`*` will copy the match to the primary selection
(on systems that support primary selections). A value of :file:`default` will (on systems that support primary selections). A value of :code:`default` will
run the default open program. Can be specified multiple times to run multiple run the default open program. Can be specified multiple times to run multiple
programs. programs.
@@ -538,22 +538,22 @@ default=url
choices=url,regex,path,line,hash,word,linenum,hyperlink,ip choices=url,regex,path,line,hash,word,linenum,hyperlink,ip
The type of text to search for. A value of :code:`linenum` is special, it looks The type of text to search for. A value of :code:`linenum` is special, it looks
for error messages using the pattern specified with :option:`--regex`, which for error messages using the pattern specified with :option:`--regex`, which
must have the named groups, :code:`path` and :code:`line`. If not specified, must have the named groups: :code:`path` and :code:`line`. If not specified,
will look for :code:`path:line`. The :option:`--linenum-action` option will look for :code:`path:line`. The :option:`--linenum-action` option
controls where to display the selected error message, other options are ignored. controls where to display the selected error message, other options are ignored.
--regex --regex
default={default_regex} default={default_regex}
The regular expression to use when :option:`kitty +kitten hints --type`=regex. The regular expression to use when option :option:`--type` is set to
The regular expression is in python syntax. If you specify a numbered group in :code:`regex`, in python syntax. If you specify a numbered group in the regular
the regular expression only the group will be matched. This allow you to match expression, only the group will be matched. This allow you to match text
text ignoring a prefix/suffix, as needed. The default expression matches lines. ignoring a prefix/suffix, as needed. The default expression matches lines. To
To match text over multiple lines you should prefix the regular expression with match text over multiple lines, you should prefix the regular expression with
:code:`(?ms)`, which turns on MULTILINE and DOTALL modes for the regex engine. :code:`(?ms)`, which turns on MULTILINE and DOTALL modes for the regex engine.
If you specify named groups and a :option:`kitty +kitten hints --program` then If you specify named groups and a :option:`--program`, then the program will be
the program will be passed arguments corresponding to each named group of passed arguments corresponding to each named group of the form
the form key=value. :code:`key=value`.
--linenum-action --linenum-action
@@ -565,22 +565,22 @@ window, :code:`window` a new kitty window, :code:`tab` a new tab,
:code:`os_window` a new OS window and :code:`background` run in the background. :code:`os_window` a new OS window and :code:`background` run in the background.
The actual action is whatever arguments are provided to the kitten, for The actual action is whatever arguments are provided to the kitten, for
example: example:
:code:`kitty + kitten hints --type=linenum --linenum-action=tab vim +{line} {path}` :code:`kitty +kitten hints --type=linenum --linenum-action=tab vim +{line} {path}`
will open the matched path at the matched line number in vim in will open the matched path at the matched line number in vim in
a new kitty tab. Note that only when using :code:`self` are the special values for a new kitty tab. Note that in order to use :option:`--program` to copy or paste
:option:`kitty +kitten hints --program` to copy/paste the text respected. text, you need to use the special value :code:`self`.
--url-prefixes --url-prefixes
default=default default=default
Comma separated list of recognized URL prefixes. Defaults, to Comma separated list of recognized URL prefixes. Defaults to the list of
the list of prefixes defined in kitty.conf. prefixes defined by the :opt:`url_prefixes` option in :file:`kitty.conf`.
--word-characters --word-characters
Characters to consider as part of a word. In addition, all characters marked as Characters to consider as part of a word. In addition, all characters marked as
alphanumeric in the unicode database will be considered as word characters. alphanumeric in the Unicode database will be considered as word characters.
Defaults to the select_by_word_characters setting from kitty.conf. Defaults to the :opt:`select_by_word_characters` option from :file:`kitty.conf`.
--minimum-match-length --minimum-match-length
@@ -591,26 +591,26 @@ The minimum number of characters to consider a match.
--multiple --multiple
type=bool-set type=bool-set
Select multiple matches and perform the action on all of them together at the end. Select multiple matches and perform the action on all of them together at the
In this mode, press :kbd:`Esc` to finish selecting. end. In this mode, press :kbd:`Esc` to finish selecting.
--multiple-joiner --multiple-joiner
default=auto default=auto
String to use to join multiple selections when copying to the clipboard or String for joining multiple selections when copying to the clipboard or
inserting into the terminal. The special strings: "space", "newline", "empty", inserting into the terminal. The special values are: :code:`space` - a space
"json" and "auto" are interpreted as a space character, a newline an empty character, :code:`newline` - a newline, :code:`empty` - an empty joiner,
joiner, a JSON serialized list and an automatic choice, based on the type of :code:`json` - a JSON serialized list, :code:`auto` - an automatic choice, based
text being selected. In addition, integers are interpreted as zero-based on the type of text being selected. In addition, integers are interpreted as
indices into the list of selections. You can use 0 for the first selection and zero-based indices into the list of selections. You can use :code:`0` for the
-1 for the last. first selection and :code:`-1` for the last.
--add-trailing-space --add-trailing-space
default=auto default=auto
choices=auto,always,never choices=auto,always,never
Add trailing space after matched text. Defaults to auto, which adds the space Add trailing space after matched text. Defaults to :code:`auto`, which adds the
when used together with :option:`--multiple`. space when used together with :option:`--multiple`.
--hints-offset --hints-offset
@@ -621,45 +621,47 @@ greater than or equal to zero are respected.
--alphabet --alphabet
The list of characters to use for hints. The default is to use numbers and lowercase The list of characters to use for hints. The default is to use numbers and
English alphabets. Specify your preference as a string of characters. Note that lowercase English alphabets. Specify your preference as a string of characters.
unless you specify the hints offset as zero the first match will be highlighted with Note that you need to specify the :option:`--hints-offset` as zero to use the
the second character you specify. first character to highlight the first match, otherwise it will start with the
second character by default.
--ascending --ascending
type=bool-set type=bool-set
Have the hints increase from top to bottom instead of decreasing from top to bottom. Make the hints increase from top to bottom, instead of decreasing from top to
bottom.
--hints-foreground-color --hints-foreground-color
default=black default=black
type=str type=str
The foreground color for hints The foreground color for hints.
--hints-background-color --hints-background-color
default=green default=green
type=str type=str
The background color for hints The background color for hints.
--hints-text-color --hints-text-color
default=gray default=gray
type=str type=str
The foreground color for text pointed to by the hints The foreground color for text pointed to by the hints.
--customize-processing --customize-processing
Name of a python file in the kitty config directory which will be imported to provide Name of a python file in the kitty config directory which will be imported to
custom implementations for pattern finding and performing actions provide custom implementations for pattern finding and performing actions
on selected matches. See {hints_url} on selected matches. You can also specify absolute paths to load the script from
for details. You can also specify absolute paths to load the script from elsewhere. elsewhere. See {hints_url} for details.
--window-title --window-title
The window title for the hints window, default title is selected based on The title for the hints window, default title is based on the type of text being
the type of text being hinted. hinted.
'''.format( '''.format(
default_regex=DEFAULT_REGEX, default_regex=DEFAULT_REGEX,
line='{{line}}', path='{{path}}', line='{{line}}', path='{{path}}',

View File

@@ -20,7 +20,7 @@ def write_hyperlink(write: Callable[[bytes], None], url: bytes, line: bytes, fra
def main() -> None: def main() -> None:
if not sys.stdout.isatty() and '--pretty' not in sys.argv: if not sys.stdout.isatty() and '--pretty' not in sys.argv and '-p' not in sys.argv:
os.execlp('rg', 'rg', *sys.argv[1:]) os.execlp('rg', 'rg', *sys.argv[1:])
cmdline = ['rg', '--pretty', '--with-filename'] + sys.argv[1:] cmdline = ['rg', '--pretty', '--with-filename'] + sys.argv[1:]
try: try:
@@ -59,7 +59,7 @@ def main() -> None:
write(line) write(line)
except KeyboardInterrupt: except KeyboardInterrupt:
p.send_signal(signal.SIGINT) p.send_signal(signal.SIGINT)
except EOFError: except (EOFError, BrokenPipeError):
pass pass
finally: finally:
p.stdout.close() p.stdout.close()

View File

@@ -42,24 +42,24 @@ Horizontal alignment for the displayed image.
--place --place
Choose where on the screen to display the image. The image will Choose where on the screen to display the image. The image will be scaled to fit
be scaled to fit into the specified rectangle. The syntax for into the specified rectangle. The syntax for specifying rectangles is
specifying rectangles is <:italic:`width`>x<:italic:`height`>@<:italic:`left`>x<:italic:`top`>. <:italic:`width`>x<:italic:`height`>@<:italic:`left`>x<:italic:`top`>.
All measurements are in cells (i.e. cursor positions) with the All measurements are in cells (i.e. cursor positions) with the origin
origin :italic:`(0, 0)` at the top-left corner of the screen. :italic:`(0, 0)` at the top-left corner of the screen.
--scale-up --scale-up
type=bool-set type=bool-set
When used in combination with :option:`--place` it will cause images that When used in combination with :option:`--place` it will cause images that are
are smaller than the specified area to be scaled up to use as much smaller than the specified area to be scaled up to use as much of the specified
of the specified area as possible. area as possible.
--background --background
default=none default=none
Specify a background color, this will cause transparent images to be composited on Specify a background color, this will cause transparent images to be composited
top of the specified color. on top of the specified color.
--mirror --mirror
@@ -79,17 +79,18 @@ type=choices
choices=detect,file,stream choices=detect,file,stream
default=detect default=detect
Which mechanism to use to transfer images to the terminal. The default is to 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 auto-detect. :italic:`file` means to use a temporary file and :italic:`stream`
send the data via terminal escape codes. Note that if you use the :italic:`file` means to send the data via terminal escape codes. Note that if you use the
transfer mode and you are connecting over a remote session then image display :italic:`file` transfer mode and you are connecting over a remote session then
will not work. image display will not work.
--detect-support --detect-support
type=bool-set type=bool-set
Detect support for image display in the terminal. If not supported, will exit Detect support for image display in the terminal. If not supported, will exit
with exit code 1, otherwise will exit with code 0 and print the supported with exit code 1, otherwise will exit with code 0 and print the supported
transfer mode to stderr, which can be used with the :option:`--transfer-mode` option. transfer mode to stderr, which can be used with the :option:`--transfer-mode`
option.
--detection-timeout --detection-timeout
@@ -101,17 +102,17 @@ detecting image display support.
--print-window-size --print-window-size
type=bool-set type=bool-set
Print out the window size as :italic:`widthxheight` (in pixels) and quit. This is a Print out the window size as <:italic:`width`>x<:italic:`height`> (in pixels) and quit. This is a
convenience method to query the window size if using :code:`kitty +kitten icat` from a convenience method to query the window size if using :code:`kitty +kitten icat`
scripting language that cannot make termios calls. from a scripting language that cannot make termios calls.
--stdin --stdin
type=choices type=choices
choices=detect,yes,no choices=detect,yes,no
default=detect default=detect
Read image data from stdin. The default is to do it automatically, when STDIN is not a terminal, Read image data from STDIN. The default is to do it automatically, when STDIN is
but you can turn it off or on explicitly, if needed. not a terminal, but you can turn it off or on explicitly, if needed.
--silent --silent
@@ -121,9 +122,9 @@ Do not print out anything to STDOUT during operation.
--z-index -z --z-index -z
default=0 default=0
Z-index of the image. When negative, text will be displayed on top of the image. Use Z-index of the image. When negative, text will be displayed on top of the image.
a double minus for values under the threshold for drawing images under cell background Use a double minus for values under the threshold for drawing images under cell
colors. For example, :code:`--1` evaluates as -1,073,741,825. background colors. For example, :code:`--1` evaluates as -1,073,741,825.
--loop -l --loop -l

View File

@@ -66,7 +66,7 @@ def query(cls: Type[Query]) -> Type[Query]:
class TerminalName(Query): class TerminalName(Query):
name: str = 'name' name: str = 'name'
override_query_name: str = 'name' override_query_name: str = 'name'
help_text: str = f'Terminal name ({names[0]})' help_text: str = f'Terminal name (e.g. :code:`{names[0]}`)'
@staticmethod @staticmethod
def get_result(opts: Options) -> str: def get_result(opts: Options) -> str:
@@ -76,7 +76,7 @@ class TerminalName(Query):
@query @query
class TerminalVersion(Query): class TerminalVersion(Query):
name: str = 'version' name: str = 'version'
help_text: str = 'Terminal version, for e.g.: 0.19.2' help_text: str = f'Terminal version (e.g. :code:`{str_version}`)'
@staticmethod @staticmethod
def get_result(opts: Options) -> str: def get_result(opts: Options) -> str:
@@ -86,7 +86,7 @@ class TerminalVersion(Query):
@query @query
class AllowHyperlinks(Query): class AllowHyperlinks(Query):
name: str = 'allow_hyperlinks' name: str = 'allow_hyperlinks'
help_text: str = 'The :opt:`setting <allow_hyperlinks>` for allowing hyperlinks can be yes, no or ask' help_text: str = 'The config option :opt:`allow_hyperlinks` in :file:`kitty.conf` for allowing hyperlinks can be :code:`yes`, :code:`no` or :code:`ask`'
@staticmethod @staticmethod
def get_result(opts: Options) -> str: def get_result(opts: Options) -> str:
@@ -154,7 +154,7 @@ class FontSize(Query):
@query @query
class ClipboardControl(Query): class ClipboardControl(Query):
name: str = 'clipboard_control' name: str = 'clipboard_control'
help_text: str = 'The :opt:`setting <clipboard_control>` for allowing reads/writes to/from the clipboard' help_text: str = 'The config option :opt:`clipboard_control` in :file:`kitty.conf` for allowing reads/writes to/from the clipboard'
@staticmethod @staticmethod
def get_result(opts: Options) -> str: def get_result(opts: Options) -> str:
@@ -173,17 +173,22 @@ def do_queries(queries: Iterable[str], cli_opts: QueryTerminalCLIOptions) -> Dic
actions = tuple(all_queries[x]() for x in queries) actions = tuple(all_queries[x]() for x in queries)
qstring = ''.join(a.query_code() for a in actions) qstring = ''.join(a.query_code() for a in actions)
received = b'' received = b''
pat = re.compile(rb'\x1b\[\?.+?c')
def more_needed(data: bytes) -> bool: def more_needed(data: bytes) -> bool:
nonlocal received nonlocal received
received += data received += data
has_da1_response = pat.search(received) is not None
if has_da1_response:
return False
for a in actions: for a in actions:
if a.more_needed(received): if a.more_needed(received):
return True return True
return False return has_da1_response
with TTYIO() as ttyio: with TTYIO() as ttyio:
ttyio.send(qstring) ttyio.send(qstring)
ttyio.send('\x1b[c') # DA1 query https://vt100.net/docs/vt510-rm/DA1.html
ttyio.recv(more_needed, timeout=cli_opts.wait_for) ttyio.recv(more_needed, timeout=cli_opts.wait_for)
return {a.name: a.output_line() for a in actions} return {a.name: a.output_line() for a in actions}
@@ -200,30 +205,28 @@ querying it.
help_text = '''\ help_text = '''\
Query the terminal this kitten is run in for various Query the terminal this kitten is run in for various capabilities. This sends
capabilities. This sends escape codes to the terminal escape codes to the terminal and based on its response prints out data about
and based on its response prints out data about supported supported capabilities. Note that this is a blocking operation, since it has to
capabilities. Note that this is a blocking operation, since wait for a response from the terminal. You can control the maximum wait time via
it has to wait for a response from the terminal. You can control the :code:`--wait-for` option.
the maximum wait time via the ``--wait-for`` option.
The output is lines of the form:: The output is lines of the form::
query: data query: data
If a particular query is unsupported by the running kitty version, If a particular :italic:`query` is unsupported by the running kitty version, the
the data will be blank. :italic:`data` will be blank.
Note that when calling this from another program, be very Note that when calling this from another program, be very careful not to perform
careful not to perform any I/O on the terminal device any I/O on the terminal device until this kitten exits.
until the kitten exits.
Available queries are: Available queries are:
{} {}
'''.format('\n'.join( '''.format('\n'.join(
f'``{name}``\n {c.help_text}\n' for name, c in all_queries.items())) f':code:`{name}`:\n {c.help_text}\n' for name, c in all_queries.items()))
usage = '[query1 query2 ...]' usage = '[query1 query2 ...]'

View File

@@ -27,6 +27,9 @@ from ..tui.operations import (
from ..tui.utils import get_key_press from ..tui.utils import get_key_press
is_ssh_kitten_sentinel = '!#*&$#($ssh-kitten)(##$'
def key(x: str) -> str: def key(x: str) -> str:
return styled(x, bold=True, fg='green') return styled(x, bold=True, fg='green')
@@ -53,10 +56,9 @@ The data used to connect over ssh.
def show_error(msg: str) -> None: def show_error(msg: str) -> None:
print(styled(msg, fg='red')) print(styled(msg, fg='red'), file=sys.stderr)
print() print()
print('Press any key to exit...') print('Press any key to quit', flush=True)
sys.stdout.flush()
with raw_mode(): with raw_mode():
while True: while True:
try: try:
@@ -112,15 +114,25 @@ class ControlMaster:
self.remote_path = remote_path self.remote_path = remote_path
self.dest = dest self.dest = dest
self.tdir = '' self.tdir = ''
self.last_error_log = ''
self.cmd_prefix = cmd = [ self.cmd_prefix = cmd = [
conn_data.binary, '-o', f'ControlPath=~/.ssh/kitty-master-{os.getpid()}-%r@%h:%p', conn_data.binary, '-o', f'ControlPath=~/.ssh/kitty-master-{os.getpid()}-%r@%h:%p',
'-o', 'TCPKeepAlive=yes', '-o', 'ControlPersist=yes' '-o', 'TCPKeepAlive=yes', '-o', 'ControlPersist=yes'
] ]
if conn_data.port: self.is_ssh_kitten = conn_data.binary is is_ssh_kitten_sentinel
cmd.extend(['-p', str(conn_data.port)]) if self.is_ssh_kitten:
if conn_data.identity_file: del cmd[:]
cmd.extend(['-i', conn_data.identity_file]) self.batch_cmd_prefix = cmd
self.batch_cmd_prefix = cmd + ['-o', 'BatchMode=yes'] sk_cmdline = json.loads(conn_data.identity_file)
while '-t' in sk_cmdline:
sk_cmdline.remove('-t')
cmd.extend(sk_cmdline[:-2])
else:
if conn_data.port:
cmd.extend(['-p', str(conn_data.port)])
if conn_data.identity_file:
cmd.extend(['-i', conn_data.identity_file])
self.batch_cmd_prefix = cmd + ['-o', 'BatchMode=yes']
def check_call(self, cmd: List[str]) -> None: def check_call(self, cmd: List[str]) -> None:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL)
@@ -130,31 +142,37 @@ class ControlMaster:
raise Exception(f'The ssh command: {shlex.join(cmd)} failed with exit code {p.returncode} and output: {out}') raise Exception(f'The ssh command: {shlex.join(cmd)} failed with exit code {p.returncode} and output: {out}')
def __enter__(self) -> 'ControlMaster': def __enter__(self) -> 'ControlMaster':
self.check_call( if not self.is_ssh_kitten:
self.cmd_prefix + ['-o', 'ControlMaster=auto', '-fN', self.conn_data.hostname]) self.check_call(
self.check_call( self.cmd_prefix + ['-o', 'ControlMaster=auto', '-fN', self.conn_data.hostname])
self.batch_cmd_prefix + ['-O', 'check', self.conn_data.hostname]) self.check_call(
self.batch_cmd_prefix + ['-O', 'check', self.conn_data.hostname])
if not self.dest: if not self.dest:
self.tdir = tempfile.mkdtemp() self.tdir = tempfile.mkdtemp()
self.dest = os.path.join(self.tdir, os.path.basename(self.remote_path)) self.dest = os.path.join(self.tdir, os.path.basename(self.remote_path))
return self return self
def __exit__(self, *a: Any) -> None: def __exit__(self, *a: Any) -> None:
subprocess.Popen( if not self.is_ssh_kitten:
self.batch_cmd_prefix + ['-O', 'exit', self.conn_data.hostname], subprocess.Popen(
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL self.batch_cmd_prefix + ['-O', 'exit', self.conn_data.hostname],
).wait() stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL
).wait()
if self.tdir: if self.tdir:
shutil.rmtree(self.tdir) shutil.rmtree(self.tdir)
@property @property
def is_alive(self) -> bool: def is_alive(self) -> bool:
if self.is_ssh_kitten:
return True
return subprocess.Popen( return subprocess.Popen(
self.batch_cmd_prefix + ['-O', 'check', self.conn_data.hostname], self.batch_cmd_prefix + ['-O', 'check', self.conn_data.hostname],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL
).wait() == 0 ).wait() == 0
def check_hostname_matches(self) -> bool: def check_hostname_matches(self) -> bool:
if self.is_ssh_kitten:
return True
cp = subprocess.run(self.batch_cmd_prefix + [self.conn_data.hostname, 'hostname', '-f'], stdout=subprocess.PIPE, cp = subprocess.run(self.batch_cmd_prefix + [self.conn_data.hostname, 'hostname', '-f'], stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
if cp.returncode == 0: if cp.returncode == 0:
@@ -181,21 +199,35 @@ class ControlMaster:
return response == 'y' return response == 'y'
return True return True
def show_error(self, msg: str) -> None:
if self.last_error_log:
print(self.last_error_log, file=sys.stderr)
self.last_error_log = ''
show_error(msg)
def download(self) -> bool: def download(self) -> bool:
cmdline = self.batch_cmd_prefix + [self.conn_data.hostname, 'cat', self.remote_path]
with open(self.dest, 'wb') as f: with open(self.dest, 'wb') as f:
return subprocess.run( cp = subprocess.run(cmdline, stdout=f, stderr=subprocess.PIPE, stdin=subprocess.DEVNULL)
self.batch_cmd_prefix + [self.conn_data.hostname, 'cat', self.remote_path], if cp.returncode != 0:
stdout=f, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL self.last_error_log = f'The command: {shlex.join(cmdline)} failed\n' + cp.stderr.decode()
).returncode == 0 return False
return True
def upload(self, suppress_output: bool = True) -> bool: def upload(self, suppress_output: bool = True) -> bool:
cmd_prefix = self.cmd_prefix if suppress_output else self.batch_cmd_prefix cmd_prefix = self.cmd_prefix if suppress_output else self.batch_cmd_prefix
cmd = cmd_prefix + [self.conn_data.hostname, 'cat', '>', self.remote_path] cmd = cmd_prefix + [self.conn_data.hostname, 'cat', '>', self.remote_path]
if not suppress_output: if not suppress_output:
print(' '.join(map(shlex.quote, cmd))) print(shlex.join(cmd))
redirect = subprocess.DEVNULL if suppress_output else None
with open(self.dest, 'rb') as f: with open(self.dest, 'rb') as f:
return subprocess.run(cmd, stdout=redirect, stderr=redirect, stdin=f).returncode == 0 if suppress_output:
cp = subprocess.run(cmd, stdin=f, capture_output=True)
if cp.returncode == 0:
return True
self.last_error_log = f'The command: {shlex.join(cmd)} failed\n' + cp.stdout.decode()
else:
return subprocess.run(cmd, stdin=f).returncode == 0
return False
Result = Optional[str] Result = Optional[str]
@@ -208,7 +240,7 @@ def main(args: List[str]) -> Result:
except SystemExit as e: except SystemExit as e:
if e.code != 0: if e.code != 0:
print(e.args[0]) print(e.args[0])
input('Press enter to quit...') input('Press Enter to quit')
raise SystemExit(e.code) raise SystemExit(e.code)
try: try:
@@ -236,7 +268,7 @@ def save_as(conn_data: SSHConnectionData, remote_path: str, cli_opts: RemoteFile
last_used_path = tempfile.gettempdir() last_used_path = tempfile.gettempdir()
last_used_file = os.path.join(last_used_path, os.path.basename(remote_path)) last_used_file = os.path.join(last_used_path, os.path.basename(remote_path))
print( print(
'Where do you wish to save the file? Leaving it blank will save it as:', 'Where do you want to save the file? Leaving it blank will save it as:',
styled(last_used_file, fg='yellow') styled(last_used_file, fg='yellow')
) )
print('Relative paths will be resolved from:', styled(os.getcwd(), fg_intense=True, bold=True)) print('Relative paths will be resolved from:', styled(os.getcwd(), fg_intense=True, bold=True))
@@ -278,11 +310,15 @@ def save_as(conn_data: SSHConnectionData, remote_path: str, cli_opts: RemoteFile
with ControlMaster(conn_data, remote_path, cli_opts, dest=dest) as master: with ControlMaster(conn_data, remote_path, cli_opts, dest=dest) as master:
if master.check_hostname_matches(): if master.check_hostname_matches():
if not master.download(): if not master.download():
show_error('Failed to copy file from remote machine') master.show_error('Failed to copy file from remote machine')
def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result: def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result:
conn_data = SSHConnectionData(*json.loads(cli_opts.ssh_connection_data or '')) cli_data = json.loads(cli_opts.ssh_connection_data or '')
if cli_data and cli_data[0] == is_ssh_kitten_sentinel:
conn_data = SSHConnectionData(is_ssh_kitten_sentinel, cli_data[-1], -1, identity_file=json.dumps(cli_data[1:]))
else:
conn_data = SSHConnectionData(*cli_data)
remote_path = cli_opts.path or '' remote_path = cli_opts.path or ''
if action == 'open': if action == 'open':
print('Opening', cli_opts.path, 'from', cli_opts.hostname) print('Opening', cli_opts.path, 'from', cli_opts.hostname)
@@ -291,7 +327,7 @@ def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result:
if master.check_hostname_matches(): if master.check_hostname_matches():
if master.download(): if master.download():
return dest return dest
show_error('Failed to copy file from remote machine') master.show_error('Failed to copy file from remote machine')
elif action == 'edit': elif action == 'edit':
print('Editing', cli_opts.path, 'from', cli_opts.hostname) print('Editing', cli_opts.path, 'from', cli_opts.hostname)
editor = get_editor() editor = get_editor()
@@ -299,7 +335,7 @@ def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result:
if not master.check_hostname_matches(): if not master.check_hostname_matches():
return None return None
if not master.download(): if not master.download():
show_error(f'Failed to download {remote_path}') master.show_error(f'Failed to download {remote_path}')
return None return None
mtime = os.path.getmtime(master.dest) mtime = os.path.getmtime(master.dest)
print(reset_terminal(), end='', flush=True) print(reset_terminal(), end='', flush=True)
@@ -314,9 +350,9 @@ def handle_action(action: str, cli_opts: RemoteFileCLIOptions) -> Result:
print(reset_terminal(), end='', flush=True) print(reset_terminal(), end='', flush=True)
if master.is_alive: if master.is_alive:
if not master.upload(suppress_output=False): if not master.upload(suppress_output=False):
show_error(f'Failed to upload {remote_path}') master.show_error(f'Failed to upload {remote_path}')
else: else:
show_error(f'Failed to upload {remote_path}, SSH master process died') master.show_error(f'Failed to upload {remote_path}, SSH master process died')
elif action == 'save': elif action == 'save':
print('Saving', cli_opts.path, 'from', cli_opts.hostname) print('Saving', cli_opts.path, 'from', cli_opts.hostname)
save_as(conn_data, remote_path, cli_opts) save_as(conn_data, remote_path, cli_opts)

View File

@@ -175,4 +175,4 @@ def main() -> None:
print('Unhandled exception running kitten:') print('Unhandled exception running kitten:')
import traceback import traceback
traceback.print_exc() traceback.print_exc()
input('Press Enter to quit...') input('Press Enter to quit')

View File

@@ -1,13 +1,17 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import json
import os import os
import sys import sys
import termios
from contextlib import suppress from contextlib import suppress
from typing import List from typing import List
from kitty.cli import parse_args from kitty.cli import parse_args
from kitty.cli_stub import ErrorCLIOptions from kitty.cli_stub import ErrorCLIOptions
from kitty.fast_data_types import open_tty
from kitty.utils import hold_till_enter, no_echo, write_all
from ..tui.operations import styled from ..tui.operations import styled
@@ -21,14 +25,35 @@ The title for the error message.
def real_main(args: List[str]) -> None: def real_main(args: List[str]) -> None:
msg = 'Show an error message' msg = 'Show an error message'
cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'hints', result_class=ErrorCLIOptions) cli_opts, items = parse_args(args[1:], OPTIONS, '', msg, 'hints', result_class=ErrorCLIOptions)
error_message = sys.stdin.buffer.read().decode('utf-8') data = json.loads(sys.stdin.buffer.read())
sys.stdin = open(os.ctermid()) error_message = data['msg']
if cli_opts.title: if cli_opts.title:
print(styled(cli_opts.title, fg_intense=True, fg='red', bold=True)) print(styled(cli_opts.title, fg_intense=True, fg='red', bold=True))
print() print()
print(error_message) print(error_message, flush=True)
print() if data.get('tb'):
input('\x1b[1;32mPress Enter to close\x1b[m') 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'
write_all(fd, msg)
write_all(fd, init_state(alternate_screen=False, kitty_keyboard_mode=False) + set_cursor_visible(False))
with no_echo(fd):
termios.tcdrain(fd)
while True:
rd = select.select([fd], [], [])[0]
if not rd:
break
q = os.read(fd, 1)
if q in b'eE':
break
return
if data.get('tb'):
tb = data['tb']
for ln in tb.splitlines():
print('\r\n', ln, sep='', end='')
print(flush=True)
hold_till_enter()
def main(args: List[str]) -> None: def main(args: List[str]) -> None:

View File

@@ -24,7 +24,7 @@ def print_key(raw: bytearray) -> None:
unix += chr(ch) unix += chr(ch)
print(unix + '\t\t', end='') print(unix + '\t\t', end='')
for ch in raw: for ch in raw:
x = chr(ch).encode('ascii') x = chr(ch).encode('utf-8')
print(styled(repr(x)[2:-1], fg='yellow'), end='') print(styled(repr(x)[2:-1], fg='yellow'), end='')
print(end='\r\n', flush=True) print(end='\r\n', flush=True)
@@ -57,13 +57,15 @@ OPTIONS = r'''
default=normal default=normal
type=choices type=choices
choices=normal,application,kitty,unchanged choices=normal,application,kitty,unchanged
The keyboard mode to use when showing keys. "normal" mode is with DECCKM reset and "application" mode is with The keyboard mode to use when showing keys. :code:`normal` mode is with DECCKM
DECCKM set. "kitty" is the full kitty extended keyboard protocol. reset and :code:`application` mode is with DECCKM set. :code:`kitty` is the full
kitty extended keyboard protocol.
'''.format '''.format
help_text = 'Show the codes generated by the terminal for key presses in various keyboard modes'
def main(args: List[str]) -> None: def main(args: List[str]) -> None:
cli_opts, items = parse_args(args[1:], OPTIONS, '', '', 'kitty +kitten show_key', result_class=ShowKeyCLIOptions) cli_opts, items = parse_args(args[1:], OPTIONS, '', help_text, 'kitty +kitten show_key', result_class=ShowKeyCLIOptions)
if cli_opts.key_mode == 'kitty': if cli_opts.key_mode == 'kitty':
from .kitty_mode import main as kitty_main from .kitty_mode import main as kitty_main
return kitty_main() return kitty_main()

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
import atexit
import fnmatch import fnmatch
import glob import glob
import io import io
@@ -24,8 +23,8 @@ from contextlib import contextmanager, suppress
from getpass import getuser from getpass import getuser
from select import select from select import select
from typing import ( from typing import (
Callable, Dict, Iterator, List, NoReturn, Optional, Sequence, Set, Tuple, Any, Callable, Dict, Iterator, List, NoReturn, Optional, Sequence, Set,
Union Tuple, Union, cast
) )
from kittens.tui.operations import restore_colors, save_colors from kittens.tui.operations import restore_colors, save_colors
@@ -34,15 +33,20 @@ from kitty.constants import (
str_version, terminfo_dir str_version, terminfo_dir
) )
from kitty.options.types import Options from kitty.options.types import Options
from kitty.shell_integration import as_str_literal
from kitty.shm import SharedMemory from kitty.shm import SharedMemory
from kitty.types import run_once from kitty.types import run_once
from kitty.utils import SSHConnectionData, set_echo as turn_off_echo, expandvars, resolve_abs_or_config_path from kitty.utils import (
SSHConnectionData, expandvars, resolve_abs_or_config_path,
set_echo as turn_off_echo, suppress_error_logging
)
from .completion import complete, ssh_options from .completion import complete, ssh_options
from .config import init_config from .config import init_config
from .copy import CopyInstruction from .copy import CopyInstruction
from .options.types import Options as SSHOptions from .options.types import Options as SSHOptions
from .options.utils import DELETE_ENV_VAR from .options.utils import DELETE_ENV_VAR
from .utils import create_shared_memory
@run_once @run_once
@@ -50,46 +54,54 @@ def ssh_exe() -> str:
return shutil.which('ssh') or 'ssh' return shutil.which('ssh') or 'ssh'
def is_kitten_cmdline(q: List[str]) -> bool: def read_data_from_shared_memory(shm_name: str) -> Any:
if len(q) < 4: with SharedMemory(shm_name, readonly=True) as shm:
return False shm.unlink()
if os.path.basename(q[0]).lower() != 'kitty': if shm.stats.st_uid != os.geteuid() or shm.stats.st_gid != os.getegid():
return False raise ValueError('Incorrect owner on pwfile')
return q[1:3] == ['+kitten', 'ssh'] or q[1:4] == ['+', 'kitten', 'ssh'] mode = stat.S_IMODE(shm.stats.st_mode)
if mode != stat.S_IREAD:
raise ValueError('Incorrect permissions on pwfile')
def set_cwd_in_cmdline(cwd: str, argv: List[str]) -> None: return json.loads(shm.read_data_with_size())
for i, arg in enumerate(tuple(argv)):
if arg.startswith('--kitten=cwd'):
argv[i] = f'--kitten=cwd={cwd}'
return
elif i > 0 and argv[i-1] == '--kitten' and (arg.startswith('cwd=') or arg.startswith('cwd ')):
argv[i] = cwd
return
idx = argv.index('ssh')
argv.insert(idx + 1, f'--kitten=cwd={cwd}')
# See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html # See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
quote_pat = re.compile('([\\`"\n])') quote_pat = re.compile('([\\`"])')
def quote_env_val(x: str) -> str: def quote_env_val(x: str, literal_quote: bool = False) -> str:
if literal_quote:
return as_str_literal(x)
x = quote_pat.sub(r'\\\1', x) x = quote_pat.sub(r'\\\1', x)
x = x.replace('$(', r'\$(') # prevent execution with $() x = x.replace('$(', r'\$(') # prevent execution with $()
return f'"{x}"' return f'"{x}"'
def serialize_env(env: Dict[str, str], base_env: Dict[str, str]) -> bytes: def serialize_env(literal_env: Dict[str, str], env: Dict[str, str], base_env: Dict[str, str], for_python: bool = False) -> bytes:
lines = [] lines = []
literal_quote = True
def a(k: str, val: str) -> None: if for_python:
lines.append(f'export {shlex.quote(k)}={quote_env_val(val)}') def a(k: str, val: str = '', prefix: str = 'export') -> None:
if val:
lines.append(f'{prefix} {json.dumps((k, val, literal_quote))}')
else:
lines.append(f'{prefix} {json.dumps((k,))}')
else:
def a(k: str, val: str = '', prefix: str = 'export') -> None:
if val:
lines.append(f'{prefix} {shlex.quote(k)}={quote_env_val(val, literal_quote)}')
else:
lines.append(f'{prefix} {shlex.quote(k)}')
for k, v in literal_env.items():
a(k, v)
literal_quote = False
for k in sorted(env): for k in sorted(env):
v = env[k] v = env[k]
if v == DELETE_ENV_VAR: if v == DELETE_ENV_VAR:
lines.append(f'unset {shlex.quote(k)}') a(k, prefix='unset')
elif v == '_kitty_copy_env_var_': elif v == '_kitty_copy_env_var_':
q = base_env.get(k) q = base_env.get(k)
if q is not None: if q is not None:
@@ -102,10 +114,11 @@ def serialize_env(env: Dict[str, str], base_env: Dict[str, str]) -> bytes:
@run_once @run_once
def kitty_opts() -> Options: def kitty_opts() -> Options:
from kitty.cli import create_default_opts from kitty.cli import create_default_opts
return create_default_opts() with suppress_error_logging():
return create_default_opts()
def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str], compression: str = 'gz') -> bytes: def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str], compression: str = 'gz', literal_env: Dict[str, str] = {}) -> bytes:
def normalize_tarinfo(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo: def normalize_tarinfo(tarinfo: tarfile.TarInfo) -> tarfile.TarInfo:
tarinfo.uname = tarinfo.gname = '' tarinfo.uname = tarinfo.gname = ''
@@ -146,11 +159,11 @@ def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str], compression: st
'TERM': os.environ.get('TERM') or kitty_opts().term, 'TERM': os.environ.get('TERM') or kitty_opts().term,
'COLORTERM': 'truecolor', 'COLORTERM': 'truecolor',
} }
env.update(ssh_opts.env)
for q in ('KITTY_WINDOW_ID', 'WINDOWID'): for q in ('KITTY_WINDOW_ID', 'WINDOWID'):
val = os.environ.get(q) val = os.environ.get(q)
if val is not None: if val is not None:
env[q] = val env[q] = val
env.update(ssh_opts.env)
env['KITTY_SHELL_INTEGRATION'] = ksi or DELETE_ENV_VAR env['KITTY_SHELL_INTEGRATION'] = ksi or DELETE_ENV_VAR
env['KITTY_SSH_KITTEN_DATA_DIR'] = ssh_opts.remote_dir env['KITTY_SSH_KITTEN_DATA_DIR'] = ssh_opts.remote_dir
if ssh_opts.login_shell: if ssh_opts.login_shell:
@@ -159,7 +172,7 @@ def make_tarfile(ssh_opts: SSHOptions, base_env: Dict[str, str], compression: st
env['KITTY_LOGIN_CWD'] = ssh_opts.cwd env['KITTY_LOGIN_CWD'] = ssh_opts.cwd
if ssh_opts.remote_kitty != 'no': if ssh_opts.remote_kitty != 'no':
env['KITTY_REMOTE'] = ssh_opts.remote_kitty env['KITTY_REMOTE'] = ssh_opts.remote_kitty
env_script = serialize_env(env, base_env) env_script = serialize_env(literal_env, env, base_env, for_python=compression != 'gz')
buf = io.BytesIO() buf = io.BytesIO()
with tarfile.open(mode=f'w:{compression}', fileobj=buf, encoding='utf-8') as tf: with tarfile.open(mode=f'w:{compression}', fileobj=buf, encoding='utf-8') as tf:
rd = ssh_opts.remote_dir.rstrip('/') rd = ssh_opts.remote_dir.rstrip('/')
@@ -196,18 +209,11 @@ def get_ssh_data(msg: str, request_id: str) -> Iterator[bytes]:
yield b'invalid ssh data request message\n' yield b'invalid ssh data request message\n'
else: else:
try: try:
with SharedMemory(pwfilename, readonly=True) as shm: env_data = read_data_from_shared_memory(pwfilename)
shm.unlink() if pw != env_data['pw']:
if shm.stats.st_uid != os.geteuid() or shm.stats.st_gid != os.getegid(): raise ValueError('Incorrect password')
raise ValueError('Incorrect owner on pwfile') if rq_id != request_id:
mode = stat.S_IMODE(shm.stats.st_mode) raise ValueError('Incorrect request id')
if mode != stat.S_IREAD:
raise ValueError('Incorrect permissions on pwfile')
env_data = json.loads(shm.read_data_with_size())
if pw != env_data['pw']:
raise ValueError('Incorrect password')
if rq_id != request_id:
raise ValueError('Incorrect request id')
except Exception as e: except Exception as e:
traceback.print_exc() traceback.print_exc()
yield f'{e}\n'.encode('utf-8') yield f'{e}\n'.encode('utf-8')
@@ -267,8 +273,8 @@ def prepare_export_home_cmd(ssh_opts: SSHOptions, is_python: bool) -> str:
def bootstrap_script( def bootstrap_script(
ssh_opts: SSHOptions, script_type: str = 'sh', remote_args: Sequence[str] = (), ssh_opts: SSHOptions, script_type: str = 'sh', remote_args: Sequence[str] = (),
test_script: str = '', request_id: Optional[str] = None, cli_hostname: str = '', cli_uname: str = '', test_script: str = '', request_id: Optional[str] = None, cli_hostname: str = '', cli_uname: str = '',
request_data: bool = False, echo_on: bool = True request_data: bool = False, echo_on: bool = True, literal_env: Dict[str, str] = {}
) -> Tuple[str, Dict[str, str], SharedMemory]: ) -> Tuple[str, Dict[str, str], str]:
if request_id is None: if request_id is None:
request_id = os.environ['KITTY_PID'] + '-' + os.environ['KITTY_WINDOW_ID'] request_id = os.environ['KITTY_PID'] + '-' + os.environ['KITTY_WINDOW_ID']
is_python = script_type == 'py' is_python = script_type == 'py'
@@ -277,14 +283,10 @@ def bootstrap_script(
with open(os.path.join(shell_integration_dir, 'ssh', f'bootstrap.{script_type}')) as f: with open(os.path.join(shell_integration_dir, 'ssh', f'bootstrap.{script_type}')) as f:
ans = f.read() ans = f.read()
pw = secrets.token_hex() pw = secrets.token_hex()
tfd = standard_b64encode(make_tarfile(ssh_opts, dict(os.environ), 'gz' if script_type == 'sh' else 'bz2')).decode('ascii') tfd = standard_b64encode(make_tarfile(ssh_opts, dict(os.environ), 'gz' if script_type == 'sh' else 'bz2', literal_env=literal_env)).decode('ascii')
data = {'pw': pw, 'opts': ssh_opts._asdict(), 'hostname': cli_hostname, 'uname': cli_uname, 'tarfile': tfd} data = {'pw': pw, 'opts': ssh_opts._asdict(), 'hostname': cli_hostname, 'uname': cli_uname, 'tarfile': tfd}
db = json.dumps(data) shm_name = create_shared_memory(data, prefix=f'kssh-{os.getpid()}-')
with SharedMemory(size=len(db) + SharedMemory.num_bytes_for_size, mode=stat.S_IREAD, prefix=f'kssh-{os.getpid()}-') as shm: sensitive_data = {'REQUEST_ID': request_id, 'DATA_PASSWORD': pw, 'PASSWORD_FILENAME': shm_name}
shm.write_data_with_size(db)
shm.flush()
atexit.register(shm.unlink)
sensitive_data = {'REQUEST_ID': request_id, 'DATA_PASSWORD': pw, 'PASSWORD_FILENAME': shm.name}
replacements = { replacements = {
'EXPORT_HOME_CMD': export_home_cmd, 'EXPORT_HOME_CMD': export_home_cmd,
'EXEC_CMD': exec_cmd, 'TEST_SCRIPT': test_script, 'EXEC_CMD': exec_cmd, 'TEST_SCRIPT': test_script,
@@ -294,7 +296,7 @@ def bootstrap_script(
if request_data: if request_data:
sd.update(sensitive_data) sd.update(sensitive_data)
replacements.update(sensitive_data) replacements.update(sensitive_data)
return prepare_script(ans, sd, script_type), replacements, shm return prepare_script(ans, sd, script_type), replacements, shm_name
def get_ssh_cli() -> Tuple[Set[str], Set[str]]: def get_ssh_cli() -> Tuple[Set[str], Set[str]]:
@@ -499,15 +501,15 @@ def wrap_bootstrap_script(sh_script: str, interpreter: str) -> List[str]:
def get_remote_command( def get_remote_command(
remote_args: List[str], ssh_opts: SSHOptions, cli_hostname: str = '', cli_uname: str = '', remote_args: List[str], ssh_opts: SSHOptions, cli_hostname: str = '', cli_uname: str = '',
echo_on: bool = True, request_data: bool = False echo_on: bool = True, request_data: bool = False, literal_env: Dict[str, str] = {}
) -> Tuple[List[str], Dict[str, str], str]: ) -> Tuple[List[str], Dict[str, str], str]:
interpreter = ssh_opts.interpreter interpreter = ssh_opts.interpreter
q = os.path.basename(interpreter).lower() q = os.path.basename(interpreter).lower()
is_python = 'python' in q is_python = 'python' in q
sh_script, replacements, shm = bootstrap_script( sh_script, replacements, shm_name = bootstrap_script(
ssh_opts, script_type='py' if is_python else 'sh', remote_args=remote_args, ssh_opts, script_type='py' if is_python else 'sh', remote_args=remote_args, literal_env=literal_env,
cli_hostname=cli_hostname, cli_uname=cli_uname, echo_on=echo_on, request_data=request_data) cli_hostname=cli_hostname, cli_uname=cli_uname, echo_on=echo_on, request_data=request_data)
return wrap_bootstrap_script(sh_script, interpreter), replacements, shm.name return wrap_bootstrap_script(sh_script, interpreter), replacements, shm_name
def connection_sharing_args(opts: SSHOptions, kitty_pid: int) -> List[str]: def connection_sharing_args(opts: SSHOptions, kitty_pid: int) -> List[str]:
@@ -602,7 +604,9 @@ def drain_potential_tty_garbage(p: 'subprocess.Popen[bytes]', data_request: str)
def change_colors(color_scheme: str) -> bool: def change_colors(color_scheme: str) -> bool:
if not color_scheme: if not color_scheme:
return False return False
from kittens.themes.collection import load_themes, NoCacheFound, text_as_opts from kittens.themes.collection import (
NoCacheFound, load_themes, text_as_opts
)
from kittens.themes.main import colors_as_escape_codes from kittens.themes.main import colors_as_escape_codes
if color_scheme.endswith('.conf'): if color_scheme.endswith('.conf'):
conf_file = resolve_abs_or_config_path(color_scheme) conf_file = resolve_abs_or_config_path(color_scheme)
@@ -627,6 +631,14 @@ def change_colors(color_scheme: str) -> bool:
return True return True
def add_cloned_env(shm_name: str) -> Dict[str, str]:
try:
return cast(Dict[str, str], read_data_from_shared_memory(shm_name))
except FileNotFoundError:
pass
return {}
def run_ssh(ssh_args: List[str], server_args: List[str], found_extra_args: Tuple[str, ...]) -> NoReturn: def run_ssh(ssh_args: List[str], server_args: List[str], found_extra_args: Tuple[str, ...]) -> NoReturn:
cmd = [ssh_exe()] + ssh_args cmd = [ssh_exe()] + ssh_args
hostname, remote_args = server_args[0], server_args[1:] hostname, remote_args = server_args[0], server_args[1:]
@@ -646,12 +658,16 @@ def run_ssh(ssh_args: List[str], server_args: List[str], found_extra_args: Tuple
else: else:
hostname_for_match = hostname hostname_for_match = hostname
hostname_for_match = hostname_for_match.split('@', 1)[-1].split(':', 1)[0] hostname_for_match = hostname_for_match.split('@', 1)[-1].split(':', 1)[0]
overrides = [] overrides: List[str] = []
literal_env: Dict[str, str] = {}
pat = re.compile(r'^([a-zA-Z0-9_]+)[ \t]*=') pat = re.compile(r'^([a-zA-Z0-9_]+)[ \t]*=')
for i, a in enumerate(found_extra_args): for i, a in enumerate(found_extra_args):
if i % 2 == 1: if i % 2 == 1:
aq = pat.sub(r'\1 ', a.lstrip()) aq = pat.sub(r'\1 ', a.lstrip())
if aq.split(maxsplit=1)[0] != 'hostname': key = aq.split(maxsplit=1)[0]
if key == 'clone_env':
literal_env = add_cloned_env(aq.split(maxsplit=1)[1])
elif key != 'hostname':
overrides.append(aq) overrides.append(aq)
if overrides: if overrides:
overrides.insert(0, f'hostname {uname}@{hostname_for_match}') overrides.insert(0, f'hostname {uname}@{hostname_for_match}')
@@ -677,7 +693,7 @@ def run_ssh(ssh_args: List[str], server_args: List[str], found_extra_args: Tuple
need_to_request_data = False need_to_request_data = False
with restore_terminal_state() as echo_on: with restore_terminal_state() as echo_on:
rcmd, replacements, shm_name = get_remote_command( rcmd, replacements, shm_name = get_remote_command(
remote_args, host_opts, hostname_for_match, uname, echo_on, request_data=need_to_request_data) remote_args, host_opts, hostname_for_match, uname, echo_on, request_data=need_to_request_data, literal_env=literal_env)
cmd += rcmd cmd += rcmd
colors_changed = change_colors(host_opts.color_scheme) colors_changed = change_colors(host_opts.color_scheme)
try: try:

View File

@@ -24,26 +24,26 @@ opt = definition.add_option
agr('bootstrap', 'Host bootstrap configuration') # {{{ agr('bootstrap', 'Host bootstrap configuration') # {{{
opt('hostname', '*', option_type='hostname', long_text=''' opt('hostname', '*', option_type='hostname', long_text='''
The hostname that the following options apply to. A glob pattern to match multiple The hostname that the following options apply to. A glob pattern to match
hosts can be used. Multiple hostnames can also be specified separated by spaces. multiple hosts can be used. Multiple hostnames can also be specified, separated
The hostname can include an optional username in the form :code:`user@host`. by spaces. The hostname can include an optional username in the form
When not specified options apply to all hosts, until the :code:`user@host`. When not specified options apply to all hosts, until the
first hostname specification is found. Note that matching of hostname is done against first hostname specification is found. Note that matching of hostname is done
the name you specify on the command line to connect to the remote host. against the name you specify on the command line to connect to the remote host.
If you wish to include the same basic configuration for many If you wish to include the same basic configuration for many different hosts,
different hosts, you can do so with the :ref:`include <include>` directive. you can do so with the :ref:`include <include>` directive.
''') ''')
opt('interpreter', 'sh', long_text=''' opt('interpreter', 'sh', long_text='''
The interpreter to use on the remote host. Must be either a POSIX complaint shell The interpreter to use on the remote host. Must be either a POSIX complaint
or a python executable. If the default sh is not available or broken, using shell or a :program:`python` executable. If the default :program:`sh` is not
an alternate interpreter can be useful. available or broken, using an alternate interpreter can be useful.
''') ''')
opt('remote_dir', '.local/share/kitty-ssh-kitten', option_type='relative_dir', long_text=''' opt('remote_dir', '.local/share/kitty-ssh-kitten', option_type='relative_dir', long_text='''
The location on the remote host where the files needed for this kitten The location on the remote host where the files needed for this kitten are
are installed. The location is relative to the HOME directory. Absolute paths or paths installed. The location is relative to the HOME directory. Absolute paths or
that resolve to a location outside the HOME are not allowed. paths that resolve to a location outside the HOME are not allowed.
''') ''')
opt('+copy', '', option_type='copy', add_to_default=False, long_text=f''' opt('+copy', '', option_type='copy', add_to_default=False, long_text=f'''
@@ -51,8 +51,7 @@ opt('+copy', '', option_type='copy', add_to_default=False, long_text=f'''
copy .vimrc .zshrc .config/some-dir copy .vimrc .zshrc .config/some-dir
If a file should be copied to some other destination on the remote host, Use :code:`--dest` to copy a file to some other destination on the remote host::
use :code:`--dest`::
copy --dest some-other-name some-file copy --dest some-other-name some-file
@@ -79,51 +78,54 @@ integration on a per-host basis.
''') ''')
opt('login_shell', '', long_text=''' opt('login_shell', '', long_text='''
The login shell to execute on the remote host. By default, the remote user account's The login shell to execute on the remote host. By default, the remote user
login shell is used. account's login shell is used.
''') ''')
opt('+env', '', option_type='env', add_to_default=False, long_text=''' opt('+env', '', option_type='env', add_to_default=False, long_text='''
Specify environment variables to set on the remote host. Note that Specify the environment variables to be set on the remote host. Using the
environment variables can refer to each other, so if you use:: name with an equal sign (e.g. :code:`env VAR=`) will set it to the empty string.
Specifying only the name (e.g. :code:`env VAR`) will remove the variable from
env MYVAR1=a the remote shell environment. The special value :code:`_kitty_copy_env_var_`
env MYVAR2=$MYVAR1/$HOME/b
The value of MYVAR2 will be :code:`a/<path to home directory>/b`. Using
:code:`VAR=` will set it to the empty string and using just :code:`VAR`
will delete the variable from the child process' environment. The definitions
are processed alphabetically. The special value :code:`_kitty_copy_env_var_`
will cause the value of the variable to be copied from the local environment. will cause the value of the variable to be copied from the local environment.
The definitions are processed alphabetically. Note that environment variables
are expanded recursively, for example::
env VAR1=a
env VAR2=${HOME}/${VAR1}/b
The value of :code:`VAR2` will be :code:`<path to home directory>/a/b`.
''') ''')
opt('cwd', '', long_text=''' opt('cwd', '', long_text='''
The working directory on the remote host to change to. Env vars in this The working directory on the remote host to change to. Environment variables in
value are expanded. The default is empty so no changing is done, which this value are expanded. The default is empty so no changing is done, which
usually means the home directory is used. usually means the HOME directory is used.
''') ''')
opt('color_scheme', '', long_text=''' opt('color_scheme', '', long_text='''
Specify a color scheme to use when connecting to the remote host. If the Specify a color scheme to use when connecting to the remote host. If this option
color_scheme ends with :code:`.conf` it is assumed to be the name of a config ends with :code:`.conf`, it is assumed to be the name of a config file to load
file to load from the kitty config directory, otherwise it is assumed to be the from the kitty config directory, otherwise it is assumed to be the name of a
name of a color theme to load via the themes kitten. Note that only colors color theme to load via the :doc:`themes kitten </kittens/themes>`. Note that
applying to the text/background are changed, other config settings in the .conf only colors applying to the text/background are changed, other config settings
files/themes are ignored. in the .conf files/themes are ignored.
''') ''')
opt('remote_kitty', 'if-needed', choices=('if-needed', 'no', 'yes'), long_text=''' opt('remote_kitty', 'if-needed', choices=('if-needed', 'no', 'yes'), long_text='''
Make kitty available on the remote server. Useful to run kittens such as the Make :program:`kitty` available on the remote host. Useful to run kittens such
icat kitten to display images or the transfer file kitten to transfer files. as the :doc:`icat kitten </kittens/icat>` to display images or the
Only works if the remote server has an architecture for which pre-compiled :doc:`transfer file kitten </kittens/transfer>` to transfer files. Only works if
kitty binaries are available. Note that kitty is not actually copied to the the remote host has an architecture for which :link:`pre-compiled kitty binaries
remote server, instead a small bootstrap script is copied which will download <https://github.com/kovidgoyal/kitty/releases>` are available. Note that kitty
and run kitty when kitty is first executed on the remote server. A value of is not actually copied to the remote host, instead a small bootstrap script is
:code:`if-needed` means kitty is installed only if not already present in the copied which will download and run kitty when kitty is first executed on the
system-wide PATH. A value of :code:`yes` means that kitty is installed even if remote host. A value of :code:`if-needed` means kitty is installed only if not
already present, and the installed kitty takes precedence. Finally, :code:`no` already present in the system-wide PATH. A value of :code:`yes` means that kitty
means no kitty is installed on the remote machine. The installed kitty is installed even if already present, and the installed kitty takes precedence.
can be updated by running: :code:`kitty +update-kitty` on the remote machine. Finally, :code:`no` means no kitty is installed on the remote host. The
installed kitty can be updated by running: :code:`kitty +update-kitty` on the
remote host.
''') ''')
egr() # }}} egr() # }}}
@@ -131,20 +133,23 @@ agr('ssh', 'SSH configuration') # {{{
opt('share_connections', 'yes', option_type='to_bool', long_text=''' opt('share_connections', 'yes', option_type='to_bool', long_text='''
Within a single kitty instance, all connections to a particular server can be Within a single kitty instance, all connections to a particular server can be
shared. This reduces startup latency for subsequent connections and means that you have shared. This reduces startup latency for subsequent connections and means that
to enter the password only once. Under the hood, it uses SSH ControlMasters and you have to enter the password only once. Under the hood, it uses SSH
these are automatically cleaned up by kitty when it quits. ControlMasters and these are automatically cleaned up by kitty when it quits.
You can map a shortcut to :ac:`close_shared_ssh_connections` to disconnect all
active shared connections.
''') ''')
opt('askpass', 'unless-set', choices=('unless-set', 'ssh', 'native'), long_text=''' opt('askpass', 'unless-set', choices=('unless-set', 'ssh', 'native'), long_text='''
Control the program SSH uses to ask for passwords or confirmation of host keys Control the program SSH uses to ask for passwords or confirmation of host keys
etc. The default is to use kitty's native askpass, unless the SSH_ASKPASS etc. The default is to use kitty's native :program:`askpass`, unless the
environment variable is set. Set it to :code:`ssh` to not interfere with the :envvar:`SSH_ASKPASS` environment variable is set. Set this option to
normal ssh askpass mechanism at all, which typically means that ssh will prompt :code:`ssh` to not interfere with the normal ssh askpass mechanism at all, which
at the terminal. Set it to :code:`native` to always use kitty's native, typically means that ssh will prompt at the terminal. Set it to :code:`native`
built-in askpass implementation. Note that not using the kitty askpass implementation to always use kitty's native, built-in askpass implementation. Note that not
means that SSH might need to use the terminal before the connection is established using the kitty askpass implementation means that SSH might need to use the
so the kitten cannot use the terminal to send data without an extra roundtrip, terminal before the connection is established, so the kitten cannot use the
adding to initial connection latency. terminal to send data without an extra roundtrip, adding to initial connection
latency.
''') ''')
egr() # }}} egr() # }}}

48
kittens/ssh/utils.py Normal file
View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
import os
from typing import Any, Dict, List
def is_kitten_cmdline(q: List[str]) -> bool:
if len(q) < 4:
return False
if os.path.basename(q[0]).lower() != 'kitty':
return False
return q[1:3] == ['+kitten', 'ssh'] or q[1:4] == ['+', 'kitten', 'ssh']
def patch_cmdline(key: str, val: str, argv: List[str]) -> None:
for i, arg in enumerate(tuple(argv)):
if arg.startswith(f'--kitten={key}='):
argv[i] = f'--kitten={key}={val}'
return
elif i > 0 and argv[i-1] == '--kitten' and (arg.startswith(f'{key}=') or arg.startswith(f'{key} ')):
argv[i] = val
return
idx = argv.index('ssh')
argv.insert(idx + 1, f'--kitten={key}={val}')
def set_cwd_in_cmdline(cwd: str, argv: List[str]) -> None:
patch_cmdline('cwd', cwd, argv)
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:
shm.write_data_with_size(db)
shm.flush()
atexit.register(shm.unlink)
return shm.name
def set_env_in_cmdline(env: Dict[str, str], argv: List[str]) -> None:
patch_cmdline('clone_env', create_shared_memory(env, 'ksse-'), argv)

View File

@@ -35,26 +35,28 @@ destination path on the receiving computer.
--permissions-bypass -p --permissions-bypass -p
The password to use to skip the transfer confirmation popup in kitty. Must match the The password to use to skip the transfer confirmation popup in kitty. Must match
password set for the :opt:`file_transfer_confirmation_bypass` option in kitty.conf. Note that the password set for the :opt:`file_transfer_confirmation_bypass` option in
leading and trailing whitespace is removed from the password. A password starting with :file:`kitty.conf`. Note that leading and trailing whitespace is removed from
., / or ~ characters is assumed to be a file name to read the password from. A value the password. A password starting with :code:`.`, :code:`/` or :code:`~`
of - means read the password from STDIN. A password that is purely a number less than 256 characters is assumed to be a file name to read the password from. A value of
is assumed to be the number of a file descriptor from which to read the actual password. :code:`-` means read the password from STDIN. A password that is purely a number
less than 256 is assumed to be the number of a file descriptor from which to
read the actual password.
--confirm-paths -c --confirm-paths -c
type=bool-set type=bool-set
Before actually transferring files, show a mapping of local file names to remote file names Before actually transferring files, show a mapping of local file names to remote
and ask for confirmation. file names and ask for confirmation.
--transmit-deltas -x --transmit-deltas -x
type=bool-set type=bool-set
If a file on the receiving side already exists, use the rsync algorithm to update it to match If a file on the receiving side already exists, use the rsync algorithm to
the file on the sending side, potentially saving lots of bandwidth and also automatically resuming update it to match the file on the sending side, potentially saving lots of
partial transfers. Note that this will actually degrade performance on fast links with small bandwidth and also automatically resuming partial transfers. Note that this will
files, so use with care. actually degrade performance on fast links with small files, so use with care.
''' '''

View File

@@ -546,7 +546,7 @@ class UnicodeInput(Handler):
self.refresh() self.refresh()
help_text = 'Input a unicode character' help_text = 'Input a Unicode character'
usage = '' usage = ''
OPTIONS = ''' OPTIONS = '''
--emoji-variation --emoji-variation
@@ -554,7 +554,7 @@ type=choices
default=none default=none
choices=none,graphic,text choices=none,graphic,text
Whether to use the textual or the graphical form for emoji. By default the Whether to use the textual or the graphical form for emoji. By default the
default form specified in the unicode standard for the symbol is used. default form specified in the Unicode standard for the symbol is used.
'''.format '''.format

33
kitty/backtrace.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2022 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#if __has_include(<execinfo.h>)
#include <execinfo.h>
static inline void
print_stack_trace(void) {
void *array[256];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 256);
// print out all the frames to stderr
backtrace_symbols_fd(array, size, STDERR_FILENO);
}
#else
static inline void
print_stack_trace(void) {
fprintf(stderr, "Stack trace functionality not available.\n");
}
#endif

View File

@@ -11,8 +11,8 @@ from functools import partial
from gettext import gettext as _ from gettext import gettext as _
from time import monotonic from time import monotonic
from typing import ( from typing import (
Any, Callable, Container, Dict, Iterable, Iterator, List, Optional, Any, Callable, Container, Dict, Iterable, Iterator, List, Optional, Set,
Sequence, Tuple, Union Tuple, Union
) )
from weakref import WeakValueDictionary from weakref import WeakValueDictionary
@@ -62,7 +62,7 @@ from .utils import (
platform_window_id, remove_socket_file, safe_print, set_primary_selection, platform_window_id, remove_socket_file, safe_print, set_primary_selection,
single_instance, startup_notification_handler, which single_instance, startup_notification_handler, which
) )
from .window import CommandOutput, CwdRequest, MatchPatternType, Window from .window import CommandOutput, CwdRequest, Window
class OSWindowDict(TypedDict): class OSWindowDict(TypedDict):
@@ -230,6 +230,7 @@ class Boss:
global_shortcuts: Dict[str, SingleKey] global_shortcuts: Dict[str, SingleKey]
): ):
set_layout_options(opts) set_layout_options(opts)
self.update_check_started = False
self.clipboard_buffers: Dict[str, str] = {} self.clipboard_buffers: Dict[str, str] = {}
self.update_check_process: Optional['PopenType[bytes]'] = None self.update_check_process: Optional['PopenType[bytes]'] = None
self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary() self.window_id_map: WeakValueDictionary[int, Window] = WeakValueDictionary()
@@ -273,7 +274,7 @@ class Boss:
for sc in self.global_shortcuts.values(): for sc in self.global_shortcuts.values():
self.keymap.pop(sc, None) self.keymap.pop(sc, None)
def startup_first_child(self, os_window_id: Optional[int], startup_sessions: Sequence[Optional[Session]] = ()) -> None: def startup_first_child(self, os_window_id: Optional[int], startup_sessions: Iterable[Session] = ()) -> None:
si = startup_sessions or create_sessions(get_options(), self.args, default_session=get_options().startup_session) si = startup_sessions or create_sessions(get_options(), self.args, default_session=get_options().startup_session)
for startup_session in si: for startup_session in si:
self.add_os_window(startup_session, os_window_id=os_window_id) self.add_os_window(startup_session, os_window_id=os_window_id)
@@ -340,42 +341,19 @@ class Boss:
yield from tab yield from tab
def match_windows(self, match: str) -> Iterator[Window]: def match_windows(self, match: str) -> Iterator[Window]:
try: if match == 'all':
field, exp = match.split(':', 1) yield from self.all_windows
except ValueError:
return return
if field == 'num': from .search_query_parser import search
tab = self.active_tab tab = self.active_tab
if tab is not None:
try: def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]:
w = tab.get_nth_window(int(exp)) return {wid for wid in candidates if self.window_id_map[wid].matches_query(location, query, tab)}
except Exception:
return for wid in search(match, (
if w is not None: 'id', 'title', 'pid', 'cwd', 'cmdline', 'num', 'env', 'recent', 'state'
yield w ), set(self.window_id_map), get_matches):
return yield self.window_id_map[wid]
if field == 'recent':
tab = self.active_tab
if tab is not None:
try:
num = int(exp)
except Exception:
return
w = self.window_id_map.get(tab.nth_active_window_id(num))
if w is not None:
yield w
return
if field != 'env':
pat: MatchPatternType = re.compile(exp)
else:
kp, vp = exp.partition('=')[::2]
if vp:
pat = re.compile(kp), re.compile(vp)
else:
pat = re.compile(kp), None
for window in self.all_windows:
if window.matches(field, pat):
yield window
def tab_for_window(self, window: Window) -> Optional[Tab]: def tab_for_window(self, window: Window) -> Optional[Tab]:
for tab in self.all_tabs: for tab in self.all_tabs:
@@ -385,55 +363,36 @@ class Boss:
return None return None
def match_tabs(self, match: str) -> Iterator[Tab]: def match_tabs(self, match: str) -> Iterator[Tab]:
try: if match == 'all':
field, exp = match.split(':', 1) return self.all_tabs
except ValueError: from .search_query_parser import search
return tm = self.active_tab_manager
pat = re.compile(exp) tim = {t.id: t for t in self.all_tabs}
def get_matches(location: str, query: str, candidates: Set[int]) -> Set[int]:
return {wid for wid in candidates if tim[wid].matches_query(location, query, tm)}
found = False found = False
if field in ('title', 'id'): for tid in search(match, (
for tab in self.all_tabs: 'id', 'index', 'title', 'window_id', 'window_title', 'pid', 'cwd', 'env', 'cmdline', 'recent', 'state'
if tab.matches(field, pat): ), set(tim), get_matches):
yield tab found = True
found = True yield tim[tid]
elif field in ('window_id', 'window_title'):
wf = field.split('_')[1]
tabs = {self.tab_for_window(w) for w in self.match_windows(f'{wf}:{exp}')}
for q in tabs:
if q:
found = True
yield q
elif field == 'index':
tm = self.active_tab_manager
if tm is not None and len(tm.tabs) > 0:
idx = (int(pat.pattern) + len(tm.tabs)) % len(tm.tabs)
found = True
yield tm.tabs[idx]
elif field == 'recent':
tm = self.active_tab_manager
if tm is not None and len(tm.tabs) > 0:
try:
num = int(exp)
except Exception:
return
q = tm.nth_active_tab(num)
if q is not None:
found = True
yield q
if not found: if not found:
tabs = {self.tab_for_window(w) for w in self.match_windows(match)} tabs = {self.tab_for_window(w) for w in self.match_windows(match)}
for q in tabs: for q in tabs:
if q: if q:
yield q yield q
def set_active_window(self, window: Window, switch_os_window_if_needed: bool = False) -> Optional[int]: def set_active_window(self, window: Window, switch_os_window_if_needed: bool = False, for_keep_focus: bool = False) -> Optional[int]:
for os_window_id, tm in self.os_window_map.items(): for os_window_id, tm in self.os_window_map.items():
for tab in tm: for tab in tm:
for w in tab: for w in tab:
if w.id == window.id: if w.id == window.id:
if tab is not self.active_tab: if tab is not self.active_tab:
tm.set_active_tab(tab) tm.set_active_tab(tab, for_keep_focus=window.tabref() if for_keep_focus else None)
tab.set_active_window(w) tab.set_active_window(w, for_keep_focus=window if for_keep_focus else None)
if switch_os_window_if_needed and current_os_window() != os_window_id: if switch_os_window_if_needed and current_os_window() != os_window_id:
focus_os_window(os_window_id, True) focus_os_window(os_window_id, True)
return os_window_id return os_window_id
@@ -769,20 +728,20 @@ class Boss:
def toggle_macos_secure_keyboard_entry(self) -> None: def toggle_macos_secure_keyboard_entry(self) -> None:
toggle_secure_input() toggle_secure_input()
def start(self, first_os_window_id: int) -> None: def start(self, first_os_window_id: int, startup_sessions: Iterable[Session]) -> None:
if not getattr(self, 'io_thread_started', False): if not getattr(self, 'io_thread_started', False):
self.child_monitor.start() self.child_monitor.start()
self.io_thread_started = True self.io_thread_started = True
urls: List[str] = getattr(sys, 'cmdline_args_for_open', []) urls: List[str] = getattr(sys, 'cmdline_args_for_open', [])
sess = create_sessions(get_options(), self.args, special_window=SpecialWindow([kitty_exe(), '+runpy', 'input()']))
if urls: if urls:
delattr(sys, 'cmdline_args_for_open') delattr(sys, 'cmdline_args_for_open')
sess = create_sessions(get_options(), self.args, special_window=SpecialWindow([kitty_exe(), '+runpy', 'input()']))
self.startup_first_child(first_os_window_id, startup_sessions=tuple(sess)) self.startup_first_child(first_os_window_id, startup_sessions=tuple(sess))
self.launch_urls(*urls) self.launch_urls(*urls)
else: else:
self.startup_first_child(first_os_window_id) self.startup_first_child(first_os_window_id, startup_sessions=startup_sessions)
if get_options().update_check_interval > 0 and not hasattr(self, 'update_check_started') and getattr(sys, 'frozen', False): if get_options().update_check_interval > 0 and not self.update_check_started and getattr(sys, 'frozen', False):
from .update_check import run_update_check from .update_check import run_update_check
run_update_check(get_options().update_check_interval * 60 * 60) run_update_check(get_options().update_check_interval * 60 * 60)
self.update_check_started = True self.update_check_started = True
@@ -1215,6 +1174,8 @@ class Boss:
if len(actions) > 1: if len(actions) > 1:
self.drain_actions(list(actions[1:]), window_for_dispatch, dispatch_type) self.drain_actions(list(actions[1:]), window_for_dispatch, dispatch_type)
except Exception as e: except Exception as e:
import traceback
traceback.print_exc()
self.show_error('Key action failed', f'{actions[0].pretty()}\n{e}') self.show_error('Key action failed', f'{actions[0].pretty()}\n{e}')
consumed = True consumed = True
return consumed return consumed
@@ -1377,7 +1338,7 @@ class Boss:
cmd = [kitty_exe(), '+runpy', 'import os, sys, time; time.sleep(0.05); os.execvp(sys.argv[1], sys.argv[1:])'] + get_editor(get_options()) + [confpath] cmd = [kitty_exe(), '+runpy', 'import os, sys, time; time.sleep(0.05); os.execvp(sys.argv[1], sys.argv[1:])'] + get_editor(get_options()) + [confpath]
self.new_os_window(*cmd) self.new_os_window(*cmd)
def _run_kitten( def run_kitten_with_metadata(
self, self,
kitten: str, kitten: str,
args: Iterable[str] = (), args: Iterable[str] = (),
@@ -1454,6 +1415,7 @@ class Boss:
action_on_removal(wid, self) action_on_removal(wid, self)
overlay_window.actions_on_removal.append(callback_wrapper) overlay_window.actions_on_removal.append(callback_wrapper)
return overlay_window return overlay_window
_run_kitten = run_kitten_with_metadata
@ac('misc', 'Run the specified kitten. See :doc:`/kittens/custom` for details') @ac('misc', 'Run the specified kitten. See :doc:`/kittens/custom` for details')
def kitten(self, kitten: str, *kargs: str) -> None: def kitten(self, kitten: str, *kargs: str) -> None:
@@ -1496,7 +1458,12 @@ class Boss:
break break
def show_error(self, title: str, msg: str) -> None: def show_error(self, title: str, msg: str) -> None:
self._run_kitten('show_error', args=['--title', title], input_data=msg) ec = sys.exc_info()
tb = ''
if ec != (None, None, None):
import traceback
tb = traceback.format_exc()
self._run_kitten('show_error', args=['--title', title], input_data=json.dumps({'msg': msg, 'tb': tb}))
@ac('mk', 'Create a new marker') @ac('mk', 'Create a new marker')
def create_marker(self) -> None: def create_marker(self) -> None:
@@ -1559,6 +1526,10 @@ class Boss:
if tab: if tab:
tab.set_active_window(window_id) tab.set_active_window(window_id)
def open_kitty_website(self) -> None:
self.open_url(website_url())
@ac('misc', 'Open the specified URL')
def open_url(self, url: str, program: Optional[Union[str, List[str]]] = None, cwd: Optional[str] = None) -> None: def open_url(self, url: str, program: Optional[Union[str, List[str]]] = None, cwd: Optional[str] = None) -> None:
if not url: if not url:
return return
@@ -1616,7 +1587,7 @@ class Boss:
def current_primary_selection_or_clipboard(self) -> str: def current_primary_selection_or_clipboard(self) -> str:
return get_primary_selection() if supports_primary_selection else get_clipboard_string() return get_primary_selection() if supports_primary_selection else get_clipboard_string()
@ac('cp', 'Paste from the clipboard to the active window') @ac('cp', 'Paste from the primary selection, if present, otherwise the clipboard to the active window')
def paste_from_selection(self) -> None: def paste_from_selection(self) -> None:
text = self.current_primary_selection_or_clipboard() text = self.current_primary_selection_or_clipboard()
self.paste_to_active_window(text) self.paste_to_active_window(text)
@@ -1994,8 +1965,10 @@ class Boss:
''') ''')
def load_config_file(self, *paths: str, apply_overrides: bool = True) -> None: def load_config_file(self, *paths: str, apply_overrides: bool = True) -> None:
from .config import load_config from .config import load_config
from .cli import default_config_paths
old_opts = get_options() old_opts = get_options()
paths = paths or old_opts.config_paths prev_paths = old_opts.config_paths or default_config_paths(self.args.config)
paths = paths or prev_paths
bad_lines: List[BadLine] = [] bad_lines: List[BadLine] = []
opts = load_config(*paths, overrides=old_opts.config_overrides if apply_overrides else None, accumulate_bad_lines=bad_lines) opts = load_config(*paths, overrides=old_opts.config_overrides if apply_overrides else None, accumulate_bad_lines=bad_lines)
if bad_lines: if bad_lines:
@@ -2276,7 +2249,11 @@ class Boss:
output = '\n'.join(f'{k}={v}' for k, v in os.environ.items()) output = '\n'.join(f'{k}={v}' for k, v in os.environ.items())
self.display_scrollback(w, output, title=_('Current kitty env vars'), report_cursor=False) self.display_scrollback(w, output, title=_('Current kitty env vars'), report_cursor=False)
@ac('debug', 'Close all shared SSH connections') @ac('debug', '''
Close all shared SSH connections
See :opt:`share_connections <kitten-ssh.share_connections>` for details.
''')
def close_shared_ssh_connections(self) -> None: def close_shared_ssh_connections(self) -> None:
cleanup_ssh_control_masters() cleanup_ssh_control_masters()

View File

@@ -1041,6 +1041,7 @@ process_cocoa_pending_actions(void) {
if (cocoa_pending_actions[RELOAD_CONFIG]) { call_boss(load_config_file, NULL); } if (cocoa_pending_actions[RELOAD_CONFIG]) { call_boss(load_config_file, NULL); }
if (cocoa_pending_actions[TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY]) { call_boss(toggle_macos_secure_keyboard_entry, NULL); } if (cocoa_pending_actions[TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY]) { call_boss(toggle_macos_secure_keyboard_entry, NULL); }
if (cocoa_pending_actions[TOGGLE_FULLSCREEN]) { call_boss(toggle_fullscreen, NULL); } if (cocoa_pending_actions[TOGGLE_FULLSCREEN]) { call_boss(toggle_fullscreen, NULL); }
if (cocoa_pending_actions[OPEN_KITTY_WEBSITE]) { call_boss(open_kitty_website, NULL); }
if (cocoa_pending_actions_data.wd) { if (cocoa_pending_actions_data.wd) {
if (cocoa_pending_actions[NEW_OS_WINDOW_WITH_WD]) { call_boss(new_os_window_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); } if (cocoa_pending_actions[NEW_OS_WINDOW_WITH_WD]) { call_boss(new_os_window_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); }
if (cocoa_pending_actions[NEW_TAB_WITH_WD]) { call_boss(new_tab_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); } if (cocoa_pending_actions[NEW_TAB_WITH_WD]) { call_boss(new_tab_with_wd, "sO", cocoa_pending_actions_data.wd, Py_True); }

View File

@@ -7,12 +7,15 @@ import sys
from collections import defaultdict from collections import defaultdict
from contextlib import contextmanager, suppress from contextlib import contextmanager, suppress
from typing import ( from typing import (
DefaultDict, Dict, Generator, List, Optional, Sequence, Tuple, TYPE_CHECKING TYPE_CHECKING, DefaultDict, Dict, Generator, List, Optional, Sequence,
Tuple
) )
import kitty.fast_data_types as fast_data_types import kitty.fast_data_types as fast_data_types
from .constants import is_macos, kitty_base_dir, shell_path, terminfo_dir from .constants import (
is_freebsd, is_macos, kitty_base_dir, shell_path, terminfo_dir
)
from .types import run_once from .types import run_once
from .utils import log_error, which from .utils import log_error, which
@@ -48,9 +51,18 @@ else:
with open(f'/proc/{pid}/cmdline', 'rb') as f: with open(f'/proc/{pid}/cmdline', 'rb') as f:
return list(filter(None, f.read().decode('utf-8').split('\0'))) return list(filter(None, f.read().decode('utf-8').split('\0')))
def cwd_of_process(pid: int) -> str: if is_freebsd:
ans = f'/proc/{pid}/cwd' def cwd_of_process(pid: int) -> str:
return os.path.realpath(ans) import subprocess
cp = subprocess.run(['pwdx', str(pid)], capture_output=True)
if cp.returncode != 0:
raise ValueError(f'Failed to find cwd of process with pid: {pid}')
ans = cp.stdout.decode('utf-8', 'replace').split()[1]
return os.path.realpath(ans)
else:
def cwd_of_process(pid: int) -> str:
ans = f'/proc/{pid}/cwd'
return os.path.realpath(ans)
def _environ_of_process(pid: int) -> str: def _environ_of_process(pid: int) -> str:
with open(f'/proc/{pid}/environ', 'rb') as f: with open(f'/proc/{pid}/environ', 'rb') as f:
@@ -195,9 +207,11 @@ class Child:
stdin: Optional[bytes] = None, stdin: Optional[bytes] = None,
env: Optional[Dict[str, str]] = None, env: Optional[Dict[str, str]] = None,
cwd_from: Optional['CwdRequest'] = None, cwd_from: Optional['CwdRequest'] = None,
allow_remote_control: bool = False allow_remote_control: bool = False,
is_clone_launch: str = '',
): ):
self.allow_remote_control = allow_remote_control self.allow_remote_control = allow_remote_control
self.is_clone_launch = is_clone_launch
self.argv = list(argv) self.argv = list(argv)
if cwd_from: if cwd_from:
try: try:
@@ -210,33 +224,36 @@ class Child:
self.stdin = stdin self.stdin = stdin
self.env = env or {} self.env = env or {}
@property
def final_env(self) -> Dict[str, str]: def final_env(self) -> Dict[str, str]:
from kitty.options.utils import DELETE_ENV_VAR from kitty.options.utils import DELETE_ENV_VAR
env: Optional[Dict[str, str]] = getattr(self, '_final_env', None) env = default_env().copy()
if env is None: if is_macos and env.get('LC_CTYPE') == 'UTF-8' and not sys._xoptions.get(
env = self._final_env = default_env().copy() 'lc_ctype_before_python') and not getattr(default_env, 'lc_ctype_set_by_user', False):
if is_macos and env.get('LC_CTYPE') == 'UTF-8' and not sys._xoptions.get( del env['LC_CTYPE']
'lc_ctype_before_python') and not getattr(default_env, 'lc_ctype_set_by_user', False): env.update(self.env)
del env['LC_CTYPE'] env['TERM'] = fast_data_types.get_options().term
env.update(self.env) env['COLORTERM'] = 'truecolor'
env['TERM'] = fast_data_types.get_options().term env['KITTY_PID'] = getpid()
env['COLORTERM'] = 'truecolor' if self.cwd:
env['KITTY_PID'] = getpid() # needed in case cwd is a symlink, in which case shells
if self.cwd: # can use it to display the current directory name rather
# needed in case cwd is a symlink, in which case shells # than the resolved path
# can use it to display the current directory name rather env['PWD'] = self.cwd
# than the resolved path tdir = checked_terminfo_dir()
env['PWD'] = self.cwd if tdir:
tdir = checked_terminfo_dir() env['TERMINFO'] = tdir
if tdir: env['KITTY_INSTALLATION_DIR'] = kitty_base_dir
env['TERMINFO'] = tdir opts = fast_data_types.get_options()
env['KITTY_INSTALLATION_DIR'] = kitty_base_dir self.unmodified_argv = list(self.argv)
opts = fast_data_types.get_options() if 'disabled' not in opts.shell_integration:
if 'disabled' not in opts.shell_integration: from .shell_integration import modify_shell_environ
from .shell_integration import modify_shell_environ modify_shell_environ(opts, env, self.argv)
modify_shell_environ(opts, env, self.argv) env = {k: v for k, v in env.items() if v is not DELETE_ENV_VAR}
env = {k: v for k, v in env.items() if v is not DELETE_ENV_VAR} if self.is_clone_launch:
env['KITTY_IS_CLONE_LAUNCH'] = self.is_clone_launch
self.is_clone_launch = '1' # free memory
else:
env.pop('KITTY_IS_CLONE_LAUNCH', None)
return env return env
def fork(self) -> Optional[int]: def fork(self) -> Optional[int]:
@@ -252,7 +269,7 @@ class Child:
remove_cloexec(stdin_read_fd) remove_cloexec(stdin_read_fd)
else: else:
stdin_read_fd = stdin_write_fd = -1 stdin_read_fd = stdin_write_fd = -1
env = tuple(f'{k}={v}' for k, v in self.final_env.items()) env = tuple(f'{k}={v}' for k, v in self.final_env().items())
argv = list(self.argv) argv = list(self.argv)
exe = argv[0] exe = argv[0]
if is_macos and exe == shell_path: if is_macos and exe == shell_path:
@@ -271,8 +288,9 @@ class Child:
# xterm, urxvt, konsole and gnome-terminal do not do it in my # xterm, urxvt, konsole and gnome-terminal do not do it in my
# testing. # testing.
argv[0] = (f'-{exe.split("/")[-1]}') argv[0] = (f'-{exe.split("/")[-1]}')
exe = which(exe) or exe self.final_exe = which(exe) or exe
pid = fast_data_types.spawn(exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd) self.final_argv0 = argv[0]
pid = fast_data_types.spawn(self.final_exe, self.cwd, tuple(argv), env, master, slave, stdin_read_fd, stdin_write_fd, ready_read_fd, ready_write_fd)
os.close(slave) os.close(slave)
self.pid = pid self.pid = pid
self.child_fd = master self.child_fd = master
@@ -340,8 +358,7 @@ class Child:
return cwd_of_process(self.pid) return cwd_of_process(self.pid)
return None return None
@property def get_pid_for_cwd(self, oldest: bool = False) -> Optional[int]:
def pid_for_cwd(self) -> Optional[int]:
with suppress(Exception): with suppress(Exception):
assert self.child_fd is not None assert self.child_fd is not None
pgrp = os.tcgetpgrp(self.child_fd) pgrp = os.tcgetpgrp(self.child_fd)
@@ -357,25 +374,32 @@ class Child:
# vim # vim
# With this script , the foreground process group will contain # With this script , the foreground process group will contain
# both the bash instance running the script and vim. # both the bash instance running the script and vim.
return max(foreground_processes) return min(foreground_processes) if oldest else max(foreground_processes)
return self.pid return self.pid
@property @property
def foreground_cwd(self) -> Optional[str]: def pid_for_cwd(self) -> Optional[int]:
return self.get_pid_for_cwd()
def get_foreground_cwd(self, oldest: bool = False) -> Optional[str]:
with suppress(Exception): with suppress(Exception):
assert self.pid_for_cwd is not None pid = self.get_pid_for_cwd(oldest)
return cwd_of_process(self.pid_for_cwd) or None if pid is not None:
return cwd_of_process(pid) or None
return None return None
@property
def foreground_cwd(self) -> Optional[str]:
return self.get_foreground_cwd()
@property @property
def foreground_environ(self) -> Dict[str, str]: def foreground_environ(self) -> Dict[str, str]:
try: pid = self.pid_for_cwd
assert self.pid_for_cwd is not None if pid is not None:
return environ_of_process(self.pid_for_cwd) with suppress(Exception):
except Exception: return environ_of_process(pid)
try: pid = self.pid
assert self.pid is not None if pid is not None:
return environ_of_process(self.pid) with suppress(Exception):
except Exception: return environ_of_process(pid)
pass
return {} return {}

View File

@@ -28,26 +28,27 @@ class OptionDict(TypedDict):
CONFIG_HELP = '''\ CONFIG_HELP = '''\
Specify a path to the configuration file(s) to use. All configuration files are Specify a path to the configuration file(s) to use. All configuration files are
merged onto the builtin {conf_name}.conf, overriding the builtin values. This option merged onto the builtin :file:`{conf_name}.conf`, overriding the builtin values.
can be specified multiple times to read multiple configuration files in This option can be specified multiple times to read multiple configuration files
sequence, which are merged. Use the special value NONE to not load a config in sequence, which are merged. Use the special value :code:`NONE` to not load
file. any config file.
If this option is not specified, config files are searched for in the order: If this option is not specified, config files are searched for in the order:
:file:`$XDG_CONFIG_HOME/{appname}/{conf_name}.conf`, :file:`~/.config/{appname}/{conf_name}.conf`, {macos_confpath} :file:`$XDG_CONFIG_HOME/{appname}/{conf_name}.conf`,
:file:`$XDG_CONFIG_DIRS/{appname}/{conf_name}.conf`. The first one that exists is used as the :file:`~/.config/{appname}/{conf_name}.conf`,{macos_confpath}
config file. :file:`$XDG_CONFIG_DIRS/{appname}/{conf_name}.conf`. The first one that exists
is used as the config file.
If the environment variable :envvar:`KITTY_CONFIG_DIRECTORY` is specified, that If the environment variable :envvar:`KITTY_CONFIG_DIRECTORY` is specified, that
directory is always used and the above searching does not happen. directory is always used and the above searching does not happen.
If :file:`/etc/xdg/{appname}/{conf_name}.conf` exists it is merged before (i.e. with lower If :file:`/etc/xdg/{appname}/{conf_name}.conf` exists, it is merged before (i.e.
priority) than any user config files. It can be used to specify system-wide with lower priority) than any user config files. It can be used to specify
defaults for all users. You can use either :code:`-` or :code:`/dev/stdin` to read the system-wide defaults for all users. You can use either :code:`-` or
config from STDIN. :file:`/dev/stdin` to read the config from STDIN.
'''.replace( '''.replace(
'{macos_confpath}', '{macos_confpath}',
(':file:`~/Library/Preferences/{appname}/{conf_name}.conf`,' if is_macos else ''), 1 (' :file:`~/Library/Preferences/{appname}/{conf_name}.conf`,' if is_macos else ''), 1
) )
@@ -149,6 +150,11 @@ def doc(x: str) -> str:
return website_url(x) return website_url(x)
@role
def ref(x: str) -> str:
return re.sub(r'\s*<\S+?>', '', x)
OptionSpecSeq = List[Union[str, OptionDict]] OptionSpecSeq = List[Union[str, OptionDict]]
@@ -289,9 +295,10 @@ def get_defaults_from_seq(seq: OptionSpecSeq) -> Dict[str, Any]:
default_msg = ('''\ default_msg = ('''\
Run the :italic:`{appname}` terminal emulator. You can also specify the :italic:`program` Run the :italic:`{appname}` terminal emulator. You can also specify the
to run inside :italic:`{appname}` as normal arguments following the :italic:`options`. :italic:`program` to run inside :italic:`{appname}` as normal arguments
For example: {appname} sh -c "echo hello, world. Press ENTER to quit; read" following the :italic:`options`.
For example: {appname} --hold sh -c "echo hello, world"
For comprehensive documentation for kitty, please see: {url}''').format( For comprehensive documentation for kitty, please see: {url}''').format(
appname=appname, url=website_url()) appname=appname, url=website_url())
@@ -578,17 +585,20 @@ def options_spec() -> str:
dest=cls dest=cls
default={appname} default={appname}
condition=not is_macos condition=not is_macos
Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it sets the app id. Set the class part of the :italic:`WM_CLASS` window property. On Wayland, it
sets the app id.
--name --name
condition=not is_macos condition=not is_macos
Set the name part of the :italic:`WM_CLASS` property (defaults to using the value from :option:`{appname} --class`) Set the name part of the :italic:`WM_CLASS` property. Defaults to using the
value from :option:`{appname} --class`.
--title -T --title -T
Set the OS window title. This will override any title set by the program running inside kitty, permanently Set the OS window title. This will override any title set by the program running
fixing the OS Window's title. So only use this if you are running a program that does not set titles. inside kitty, permanently fixing the OS window's title. So only use this if you
are running a program that does not set titles.
--config -c --config -c
@@ -599,68 +609,74 @@ type=list
--override -o --override -o
type=list type=list
Override individual configuration options, can be specified multiple times. Override individual configuration options, can be specified multiple times.
Syntax: :italic:`name=value`. For example: :option:`kitty -o` font_size=20 Syntax: :italic:`name=value`. For example: :option:`{appname} -o` font_size=20
--directory --working-directory -d --directory --working-directory -d
default=. default=.
Change to the specified directory when launching Change to the specified directory when launching.
--detach --detach
type=bool-set type=bool-set
condition=not is_macos condition=not is_macos
Detach from the controlling terminal, if any Detach from the controlling terminal, if any.
--session --session
Path to a file containing the startup :italic:`session` (tabs, windows, layout, programs). Path to a file containing the startup :italic:`session` (tabs, windows, layout,
Use - to read from STDIN. See the README file for details and an example. programs). Use - to read from STDIN. See the :file:`README` file for details and
an example.
--hold --hold
type=bool-set type=bool-set
Remain open after child process exits. Note that this only affects the first Remain open after child process exits. Note that this only affects the first
window. You can quit by either using the close window shortcut or pressing any key. window. You can quit by either using the close window shortcut or pressing any
key.
--single-instance -1 --single-instance -1
type=bool-set type=bool-set
If specified only a single instance of :italic:`{appname}` will run. New invocations will If specified only a single instance of :italic:`{appname}` will run. New
instead create a new top-level window in the existing :italic:`{appname}` instance. This invocations will instead create a new top-level window in the existing
allows :italic:`{appname}` to share a single sprite cache on the GPU and also reduces :italic:`{appname}` instance. This allows :italic:`{appname}` to share a single
startup time. You can also have separate groups of :italic:`{appname}` instances by using the sprite cache on the GPU and also reduces startup time. You can also have
:option:`kitty --instance-group` option separate groups of :italic:`{appname}` instances by using the :option:`{appname}
--instance-group` option.
--instance-group --instance-group
Used in combination with the :option:`kitty --single-instance` option. All :italic:`{appname}` invocations Used in combination with the :option:`{appname} --single-instance` option. All
with the same :option:`kitty --instance-group` will result in new windows being created :italic:`{appname}` invocations with the same :option:`{appname}
in the first :italic:`{appname}` instance within that group --instance-group` will result in new windows being created in the first
:italic:`{appname}` instance within that group.
--wait-for-single-instance-window-close --wait-for-single-instance-window-close
type=bool-set type=bool-set
Normally, when using :option:`--single-instance`, :italic:`{appname}` will open a new window in an existing Normally, when using :option:`{appname} --single-instance`, :italic:`{appname}`
instance and quit immediately. With this option, it will not quit till the newly opened will open a new window in an existing instance and quit immediately. With this
window is closed. Note that if no previous instance is found, then :italic:`{appname}` will wait anyway, option, it will not quit till the newly opened window is closed. Note that if no
previous instance is found, then :italic:`{appname}` will wait anyway,
regardless of this option. regardless of this option.
--listen-on --listen-on
Tell kitty to listen on the specified address for control Listen on the specified socket address for control messages. For example,
messages. For example, :option:`{appname} --listen-on`=unix:/tmp/mykitty or :option:`{appname} --listen-on`=unix:/tmp/mykitty or
:option:`{appname} --listen-on`=tcp:localhost:12345. On Linux systems, you can :option:`{appname} --listen-on`=tcp:localhost:12345. On Linux systems, you can
also use abstract UNIX sockets, not associated with a file, like this: also use abstract UNIX sockets, not associated with a file, like this:
:option:`{appname} --listen-on`=unix:@mykitty. Environment variables :option:`{appname} --listen-on`=unix:@mykitty. Environment variables are
in the setting are expanded and relative paths are resolved with expanded and relative paths are resolved with respect to the temporary
respect to the temporary directory. To control kitty, you can send directory. To control kitty, you can send commands to it with
it commands with :italic:`kitty @` using the :option:`kitty @ --to` option to :italic:`{appname} @` using the :option:`{appname} @ --to` option to specify
specify this address. This option will be ignored, unless you set this address. Unless you enabled :opt:`allow_remote_control` in
:opt:`allow_remote_control` to yes in :file:`kitty.conf`. Note that if you run :file:`{conf_name}.conf`, this option will be ignored. Note that if you run
:italic:`kitty @` within a kitty window, there is no need to specify the :option:`kitty @ --to` :italic:`{appname} @` within a kitty window, there is
option as it is read automatically from the environment. For UNIX sockets, this no need to specify the :option:`{appname} @ --to` option as it will
can also be specified in :file:`kitty.conf`. automatically read from the environment. For UNIX sockets, this can also be
specified in :file:`{conf_name}.conf`.
--start-as --start-as
@@ -674,45 +690,48 @@ Control how the initial kitty window is created.
--version -v --version -v
type=bool-set type=bool-set
The current {appname} version The current {appname} version.
--dump-commands --dump-commands
type=bool-set type=bool-set
Output commands received from child process to stdout Output commands received from child process to STDOUT.
--replay-commands --replay-commands
Replay previously dumped commands. Specify the path to a dump file previously created by :option:`kitty --dump-commands`. You Replay previously dumped commands. Specify the path to a dump file previously
created by :option:`{appname} --dump-commands`. You
can open a new kitty window to replay the commands with:: can open a new kitty window to replay the commands with::
kitty sh -c "kitty --replay-commands /path/to/dump/file; read" {appname} sh -c "{appname} --replay-commands /path/to/dump/file; read"
--dump-bytes --dump-bytes
Path to file in which to store the raw bytes received from the child process Path to file in which to store the raw bytes received from the child process.
--debug-rendering --debug-gl --debug-rendering --debug-gl
type=bool-set type=bool-set
Debug rendering commands. This will cause all OpenGL calls to check for errors Debug rendering commands. This will cause all OpenGL calls to check for errors
instead of ignoring them. Also prints out miscellaneous debug information. instead of ignoring them. Also prints out miscellaneous debug information.
Useful when debugging rendering problems Useful when debugging rendering problems.
--debug-input --debug-keyboard --debug-input --debug-keyboard
dest=debug_keyboard dest=debug_keyboard
type=bool-set type=bool-set
This option will cause kitty to print out key and mouse events as they are received Print out key and mouse events as they are received.
--debug-font-fallback --debug-font-fallback
type=bool-set type=bool-set
Print out information about the selection of fallback fonts for characters not present in the main font. Print out information about the selection of fallback fonts for characters not
present in the main font.
--watcher --watcher
This option is deprecated in favor of the :opt:`watcher` option in kitty.conf and should not be used. This option is deprecated in favor of the :opt:`watcher` option in
:file:`{conf_name}.conf` and should not be used.
--execute -e --execute -e
@@ -720,7 +739,8 @@ type=bool-set
! !
''' '''
setattr(options_spec, 'ans', OPTIONS.format( setattr(options_spec, 'ans', OPTIONS.format(
appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname), appname=appname, conf_name=appname,
config_help=CONFIG_HELP.format(appname=appname, conf_name=appname),
)) ))
ans: str = getattr(options_spec, 'ans') ans: str = getattr(options_spec, 'ans')
return ans return ans
@@ -764,12 +784,16 @@ def parse_args(
return ans, parse_cmdline(oc, disabled, ans, args=args) return ans, parse_cmdline(oc, disabled, ans, args=args)
SYSTEM_CONF = '/etc/xdg/kitty/kitty.conf' SYSTEM_CONF = f'/etc/xdg/{appname}/{appname}.conf'
def default_config_paths(conf_paths: Sequence[str]) -> Tuple[str, ...]:
return tuple(resolve_config(SYSTEM_CONF, defconf, conf_paths))
def create_opts(args: CLIOptions, accumulate_bad_lines: Optional[List[BadLineType]] = None) -> KittyOpts: def create_opts(args: CLIOptions, accumulate_bad_lines: Optional[List[BadLineType]] = None) -> KittyOpts:
from .config import load_config from .config import load_config
config = tuple(resolve_config(SYSTEM_CONF, defconf, args.config)) config = default_config_paths(args.config)
# Does not cover the case where `name =` when `=` is the value. # Does not cover the case where `name =` when `=` is the value.
pat = re.compile(r'^([a-zA-Z0-9_]+)[ \t]*=') pat = re.compile(r'^([a-zA-Z0-9_]+)[ \t]*=')
overrides = (pat.sub(r'\1 ', a.lstrip()) for a in args.override or ()) overrides = (pat.sub(r'\1 ', a.lstrip()) for a in args.override or ())
@@ -779,6 +803,6 @@ def create_opts(args: CLIOptions, accumulate_bad_lines: Optional[List[BadLineTyp
def create_default_opts() -> KittyOpts: def create_default_opts() -> KittyOpts:
from .config import load_config from .config import load_config
config = tuple(resolve_config(SYSTEM_CONF, defconf, ())) config = default_config_paths(())
opts = load_config(*config) opts = load_config(*config)
return opts return opts

View File

@@ -235,11 +235,7 @@ PENDING(clear_terminal_and_scrollback, CLEAR_TERMINAL_AND_SCROLLBACK)
PENDING(reload_config, RELOAD_CONFIG) PENDING(reload_config, RELOAD_CONFIG)
PENDING(toggle_macos_secure_keyboard_entry, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY) PENDING(toggle_macos_secure_keyboard_entry, TOGGLE_MACOS_SECURE_KEYBOARD_ENTRY)
PENDING(toggle_fullscreen, TOGGLE_FULLSCREEN) PENDING(toggle_fullscreen, TOGGLE_FULLSCREEN)
PENDING(open_kitty_website, OPEN_KITTY_WEBSITE)
- (void)open_kitty_website_url:(id)sender {
(void)sender;
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://sw.kovidgoyal.net/kitty/"]];
}
- (BOOL)validateMenuItem:(NSMenuItem *)item { - (BOOL)validateMenuItem:(NSMenuItem *)item {
if (item.action == @selector(toggle_macos_secure_keyboard_entry:)) { if (item.action == @selector(toggle_macos_secure_keyboard_entry:)) {
@@ -275,7 +271,7 @@ typedef struct {
typedef struct { typedef struct {
GlobalShortcut new_os_window, close_os_window, close_tab, edit_config_file, reload_config; GlobalShortcut new_os_window, close_os_window, close_tab, edit_config_file, reload_config;
GlobalShortcut previous_tab, next_tab, new_tab, new_window, close_window, reset_terminal, clear_terminal_and_scrollback; GlobalShortcut previous_tab, next_tab, new_tab, new_window, close_window, reset_terminal, clear_terminal_and_scrollback;
GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen; GlobalShortcut toggle_macos_secure_keyboard_entry, toggle_fullscreen, open_kitty_website;
} GlobalShortcuts; } GlobalShortcuts;
static GlobalShortcuts global_shortcuts; static GlobalShortcuts global_shortcuts;
@@ -290,7 +286,7 @@ cocoa_set_global_shortcut(PyObject *self UNUSED, PyObject *args) {
Q(new_os_window); else Q(close_os_window); else Q(close_tab); else Q(edit_config_file); Q(new_os_window); else Q(close_os_window); else Q(close_tab); else Q(edit_config_file);
else Q(new_tab); else Q(next_tab); else Q(previous_tab); else Q(new_tab); else Q(next_tab); else Q(previous_tab);
else Q(new_window); else Q(close_window); else Q(reset_terminal); else Q(clear_terminal_and_scrollback); else Q(reload_config); else Q(new_window); else Q(close_window); else Q(reset_terminal); else Q(clear_terminal_and_scrollback); else Q(reload_config);
else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); else Q(toggle_macos_secure_keyboard_entry); else Q(toggle_fullscreen); else Q(open_kitty_website);
#undef Q #undef Q
if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; } if (gs == NULL) { PyErr_SetString(PyExc_KeyError, "Unknown shortcut name"); return NULL; }
int cocoa_mods; int cocoa_mods;
@@ -652,10 +648,8 @@ cocoa_create_global_menu(void) {
keyEquivalent:@""]; keyEquivalent:@""];
NSMenu* helpMenu = [[NSMenu alloc] initWithTitle:@"Help"]; NSMenu* helpMenu = [[NSMenu alloc] initWithTitle:@"Help"];
[helpMenuItem setSubmenu:helpMenu]; [helpMenuItem setSubmenu:helpMenu];
[[helpMenu addItemWithTitle:[NSString stringWithFormat:@"Visit %@ Website", app_name]
action:@selector(open_kitty_website_url:) MENU_ITEM(helpMenu, @"Visit kitty Website", open_kitty_website);
keyEquivalent:@"?"]
setTarget:global_menu_target];
[NSApp setHelpMenu:helpMenu]; [NSApp setHelpMenu:helpMenu];
[helpMenu release]; [helpMenu release];

View File

@@ -125,7 +125,11 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
if func.__module__ != 'builtins': if func.__module__ != 'builtins':
tc_imports.add((func.__module__, func.__name__)) tc_imports.add((func.__module__, func.__name__))
defval = repr(func(option.defval_as_string)) defval_as_obj = func(option.defval_as_string)
if isinstance(defval_as_obj, frozenset):
defval = 'frozenset({' + ', '.join(repr(x) for x in sorted(defval_as_obj)) + '})'
else:
defval = repr(defval_as_obj)
if len(defval) > 100: if len(defval) > 100:
defval += ' # noqa' defval += ' # noqa'
if option.macos_defval is not unset: if option.macos_defval is not unset:

View File

@@ -55,6 +55,7 @@ def ref_map() -> Dict[str, str]:
'functional': f'{website_url("keyboard-protocol")}#functional-key-definitions', 'functional': f'{website_url("keyboard-protocol")}#functional-key-definitions',
'ssh_copy_command': f'{website_url("kittens/ssh")}#ssh-copy-command', 'ssh_copy_command': f'{website_url("kittens/ssh")}#ssh-copy-command',
'shell_integration': website_url("shell-integration"), 'shell_integration': website_url("shell-integration"),
'clone_shell': f'{website_url("shell-integration")}#clone-shell',
'github_discussions': 'https://github.com/kovidgoyal/kitty/discussions', 'github_discussions': 'https://github.com/kovidgoyal/kitty/discussions',
} }
for actions in get_all_actions().values(): for actions in get_all_actions().values():
@@ -65,23 +66,40 @@ def ref_map() -> Dict[str, str]:
def remove_markup(text: str) -> str: def remove_markup(text: str) -> str:
def extract(m: 'Match[str]') -> Tuple[str, str]:
parts = m.group(2).split('<')
t = parts[0].strip()
q = parts[-1].rstrip('>')
return t, q
def sub(m: 'Match[str]') -> str: def sub(m: 'Match[str]') -> str:
if m.group(1) == 'ref': if m.group(1) == 'ref':
q = m.group(2).split('<')[-1].rstrip('>') t, q = extract(m)
return ref_map()[q] return f'{t} <{ref_map()[q]}>'
if m.group(1) == 'doc':
t, q = extract(m)
return f'{t} <{website_url(q.lstrip("/"))}>'
if m.group(1) == 'ac': if m.group(1) == 'ac':
q = m.group(2).split('<')[-1].rstrip('>') q = m.group(2).split('<')[-1].rstrip('>')
return ref_map()[f'action-{q}'] return q
if m.group(1) == 'term':
t, _ = extract(m)
return t
if m.group(1) == 'option':
t, _ = extract(m)
return t
if m.group(1) == 'disc': if m.group(1) == 'disc':
parts = m.group(2).split('<') t, q = extract(m)
t = parts[0].strip()
q = parts[-1].rstrip('>')
return f'{t} {ref_map()["github_discussions"]}/{q}' return f'{t} {ref_map()["github_discussions"]}/{q}'
return str(m.group(2)) return str(m.group(2))
return re.sub(r':([a-zA-Z0-9]+):`(.+?)`', sub, text, flags=re.DOTALL) return re.sub(r':([a-zA-Z0-9]+):`(.+?)`', sub, text, flags=re.DOTALL)
def strip_inline_literal(text: str) -> str:
return re.sub(r'``([^`]+)``', r'`\1`', text, flags=re.DOTALL)
def iter_blocks(lines: Iterable[str]) -> Iterator[Tuple[List[str], int]]: def iter_blocks(lines: Iterable[str]) -> Iterator[Tuple[List[str], int]]:
current_block: List[str] = [] current_block: List[str] = []
prev_indent = 0 prev_indent = 0
@@ -123,6 +141,7 @@ def wrapped_block(lines: Iterable[str], comment_symbol: str = '#: ') -> Iterator
def render_block(text: str, comment_symbol: str = '#: ') -> str: def render_block(text: str, comment_symbol: str = '#: ') -> str:
text = remove_markup(text) text = remove_markup(text)
text = strip_inline_literal(text)
lines = text.splitlines() lines = text.splitlines()
return '\n'.join(wrapped_block(lines, comment_symbol)) return '\n'.join(wrapped_block(lines, comment_symbol))
@@ -270,7 +289,11 @@ class MultiOption:
for k in self.items: for k in self.items:
if k.documented: if k.documented:
documented = True documented = True
a(f'{self.name} {k.defval_as_str if k.add_to_default else ""}'.rstrip()) if k.add_to_default:
a(f'{self.name} {k.defval_as_str}'.rstrip())
else:
# Comment out multi-options that have no default values
a(f'# {self.name}'.rstrip())
if not k.add_to_default and k.defval_as_str: if not k.add_to_default and k.defval_as_str:
a('') a('')
a(f'#: E.g. {self.name} {k.defval_as_str}'.rstrip()) a(f'#: E.g. {self.name} {k.defval_as_str}'.rstrip())
@@ -546,6 +569,9 @@ class Group:
if commented: if commented:
ans = [x if x.startswith('#') or not x.strip() else (f'# {x}') for x in ans] ans = [x if x.startswith('#') or not x.strip() else (f'# {x}') for x in ans]
else:
# Comment out any invalid options that have no value
ans = [f'# {x}' if not x.startswith('#') and len(x.strip().split()) == 1 else x for x in ans]
return ans return ans

View File

@@ -22,10 +22,11 @@ class Version(NamedTuple):
appname: str = 'kitty' appname: str = 'kitty'
kitty_face = '🐱' kitty_face = '🐱'
version: Version = Version(0, 25, 0) version: Version = Version(0, 25, 1)
str_version: str = '.'.join(map(str, version)) str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower() _plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat is_macos: bool = 'darwin' in _plat
is_freebsd: bool = 'freebsd' in _plat
is_running_from_develop: bool = False is_running_from_develop: bool = False
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
extensions_dir: str = getattr(sys, 'kitty_extensions_dir') extensions_dir: str = getattr(sys, 'kitty_extensions_dir')

View File

@@ -9,6 +9,7 @@
#define PY_SSIZE_T_CLEAN #define PY_SSIZE_T_CLEAN
#include <Python.h> #include <Python.h>
#include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <poll.h> #include <poll.h>
@@ -163,12 +164,14 @@ typedef struct {
sprite_index sprite_x, sprite_y, sprite_z; sprite_index sprite_x, sprite_y, sprite_z;
CellAttrs attrs; CellAttrs attrs;
} GPUCell; } GPUCell;
static_assert(sizeof(GPUCell) == 20, "Fix the ordering of GPUCell");
typedef struct { typedef struct {
char_type ch; char_type ch;
combining_type cc_idx[2];
hyperlink_id_type hyperlink_id; hyperlink_id_type hyperlink_id;
combining_type cc_idx[3];
} CPUCell; } CPUCell;
static_assert(sizeof(CPUCell) == 12, "Fix the ordering of CPUCell");
typedef enum { UNKNOWN_PROMPT_KIND = 0, PROMPT_START = 1, SECONDARY_PROMPT = 2, OUTPUT_START = 3 } PromptKind; typedef enum { UNKNOWN_PROMPT_KIND = 0, PROMPT_START = 1, SECONDARY_PROMPT = 2, OUTPUT_START = 3 } PromptKind;
typedef union LineAttrs { typedef union LineAttrs {

View File

@@ -976,7 +976,7 @@ class FileTransmission:
finally: finally:
self.drop_receive(ar.id) self.drop_receive(ar.id)
else: else:
log_error('Transmission receive command with unknown action: {cmd.action}, ignoring') log_error(f'Transmission receive command with unknown action: {cmd.action}, ignoring')
def transmit_rsync_signature( def transmit_rsync_signature(
self, fs: Iterator[memoryview], self, fs: Iterator[memoryview],

View File

@@ -10,6 +10,7 @@
#include "lineops.h" #include "lineops.h"
#include "fonts.h" #include "fonts.h"
#include <fontconfig/fontconfig.h> #include <fontconfig/fontconfig.h>
#include <dlfcn.h>
#include "emoji.h" #include "emoji.h"
#include "freetype_render_ui_text.h" #include "freetype_render_ui_text.h"
#ifndef FC_COLOR #ifndef FC_COLOR
@@ -18,10 +19,111 @@
static bool initialized = false; static bool initialized = false;
static void* libfontconfig_handle = NULL;
#define FcInit dynamically_loaded_fc_symbol.Init
#define FcFini dynamically_loaded_fc_symbol.Fini
#define FcCharSetAddChar dynamically_loaded_fc_symbol.CharSetAddChar
#define FcPatternDestroy dynamically_loaded_fc_symbol.PatternDestroy
#define FcObjectSetDestroy dynamically_loaded_fc_symbol.ObjectSetDestroy
#define FcPatternAddDouble dynamically_loaded_fc_symbol.PatternAddDouble
#define FcPatternAddString dynamically_loaded_fc_symbol.PatternAddString
#define FcFontMatch dynamically_loaded_fc_symbol.FontMatch
#define FcCharSetCreate dynamically_loaded_fc_symbol.CharSetCreate
#define FcPatternGetString dynamically_loaded_fc_symbol.PatternGetString
#define FcFontSetDestroy dynamically_loaded_fc_symbol.FontSetDestroy
#define FcPatternGetInteger dynamically_loaded_fc_symbol.PatternGetInteger
#define FcPatternAddBool dynamically_loaded_fc_symbol.PatternAddBool
#define FcFontList dynamically_loaded_fc_symbol.FontList
#define FcObjectSetBuild dynamically_loaded_fc_symbol.ObjectSetBuild
#define FcCharSetDestroy dynamically_loaded_fc_symbol.CharSetDestroy
#define FcConfigSubstitute dynamically_loaded_fc_symbol.ConfigSubstitute
#define FcDefaultSubstitute dynamically_loaded_fc_symbol.DefaultSubstitute
#define FcPatternAddInteger dynamically_loaded_fc_symbol.PatternAddInteger
#define FcPatternCreate dynamically_loaded_fc_symbol.PatternCreate
#define FcPatternGetBool dynamically_loaded_fc_symbol.PatternGetBool
#define FcPatternAddCharSet dynamically_loaded_fc_symbol.PatternAddCharSet
static struct {
FcBool(*Init)(void);
void(*Fini)(void);
FcBool (*CharSetAddChar) (FcCharSet *fcs, FcChar32 ucs4);
void (*PatternDestroy) (FcPattern *p);
void (*ObjectSetDestroy) (FcObjectSet *os);
FcBool (*PatternAddDouble) (FcPattern *p, const char *object, double d);
FcBool (*PatternAddString) (FcPattern *p, const char *object, const FcChar8 *s);
FcPattern * (*FontMatch) (FcConfig *config, FcPattern *p, FcResult *result);
FcCharSet* (*CharSetCreate) (void);
FcResult (*PatternGetString) (const FcPattern *p, const char *object, int n, FcChar8 ** s);
void (*FontSetDestroy) (FcFontSet *s);
FcResult (*PatternGetInteger) (const FcPattern *p, const char *object, int n, int *i);
FcBool (*PatternAddBool) (FcPattern *p, const char *object, FcBool b);
FcFontSet * (*FontList) (FcConfig *config, FcPattern *p, FcObjectSet *os);
FcObjectSet * (*ObjectSetBuild) (const char *first, ...);
void (*CharSetDestroy) (FcCharSet *fcs);
FcBool (*ConfigSubstitute) (FcConfig *config, FcPattern *p, FcMatchKind kind);
void (*DefaultSubstitute) (FcPattern *pattern);
FcBool (*PatternAddInteger) (FcPattern *p, const char *object, int i);
FcPattern * (*PatternCreate) (void);
FcResult (*PatternGetBool) (const FcPattern *p, const char *object, int n, FcBool *b);
FcBool (*PatternAddCharSet) (FcPattern *p, const char *object, const FcCharSet *c);
} dynamically_loaded_fc_symbol = {0};
#define LOAD_FUNC(name) {\
*(void **) (&dynamically_loaded_fc_symbol.name) = dlsym(libfontconfig_handle, "Fc" #name); \
if (!dynamically_loaded_fc_symbol.name) { \
const char* error = dlerror(); \
fatal("Failed to load the function Fc" #name " with error: %s", error ? error : ""); \
} \
}
static void
load_fontconfig_lib(void) {
const char* libnames[] = {
#if defined(_KITTY_FONTCONFIG_LIBRARY)
_KITTY_FONTCONFIG_LIBRARY,
#else
"libfontconfig.so",
// some installs are missing the .so symlink, so try the full name
"libfontconfig.so.1",
#endif
NULL
};
for (int i = 0; libnames[i]; i++) {
libfontconfig_handle = dlopen(libnames[i], RTLD_LAZY);
if (libfontconfig_handle) break;
}
if (libfontconfig_handle == NULL) { fatal("Failed to find and load fontconfig"); }
dlerror(); /* Clear any existing error */
LOAD_FUNC(Init);
LOAD_FUNC(Fini);
LOAD_FUNC(CharSetAddChar);
LOAD_FUNC(PatternDestroy);
LOAD_FUNC(ObjectSetDestroy);
LOAD_FUNC(PatternAddDouble);
LOAD_FUNC(PatternAddString);
LOAD_FUNC(FontMatch);
LOAD_FUNC(CharSetCreate);
LOAD_FUNC(PatternGetString);
LOAD_FUNC(FontSetDestroy);
LOAD_FUNC(PatternGetInteger);
LOAD_FUNC(PatternAddBool);
LOAD_FUNC(FontList);
LOAD_FUNC(ObjectSetBuild);
LOAD_FUNC(CharSetDestroy);
LOAD_FUNC(ConfigSubstitute);
LOAD_FUNC(DefaultSubstitute);
LOAD_FUNC(PatternAddInteger);
LOAD_FUNC(PatternCreate);
LOAD_FUNC(PatternGetBool);
LOAD_FUNC(PatternAddCharSet);
}
#undef LOAD_FUNC
static void static void
ensure_initialized(void) { ensure_initialized(void) {
if (!initialized) { if (!initialized) {
load_fontconfig_lib();
if (!FcInit()) fatal("Failed to initialize fontconfig library"); if (!FcInit()) fatal("Failed to initialize fontconfig library");
initialized = true; initialized = true;
} }
@@ -31,6 +133,8 @@ static void
finalize(void) { finalize(void) {
if (initialized) { if (initialized) {
FcFini(); FcFini();
dlclose(libfontconfig_handle);
libfontconfig_handle = NULL;
initialized = false; initialized = false;
} }
} }

View File

@@ -422,7 +422,7 @@ load_fallback_font(FontGroup *fg, CPUCell *cell, bool bold, bool italic, bool em
if (fg->fallback_fonts_count > 100) { log_error("Too many fallback fonts"); return MISSING_FONT; } if (fg->fallback_fonts_count > 100) { log_error("Too many fallback fonts"); return MISSING_FONT; }
ssize_t f; ssize_t f;
if (bold) f = fg->italic_font_idx > 0 ? fg->bi_font_idx : fg->bold_font_idx; if (bold) f = italic ? fg->bi_font_idx : fg->bold_font_idx;
else f = italic ? fg->italic_font_idx : fg->medium_font_idx; else f = italic ? fg->italic_font_idx : fg->medium_font_idx;
if (f < 0) f = fg->medium_font_idx; if (f < 0) f = fg->medium_font_idx;

13
kitty/glfw-wrapper.h generated
View File

@@ -762,6 +762,16 @@ typedef enum GLFWMouseButton {
* [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint).
*/ */
#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003
/*! @brief macOS specific
* [window hint](@ref GLFW_COCOA_COLOR_SPACE_hint).
*/
#define GLFW_COCOA_COLOR_SPACE 0x00023004
typedef enum {
DEFAULT_COLORSPACE = 0,
SRGB_COLORSPACE = 1,
DISPLAY_P3_COLORSPACE = 2,
} GlfwCocoaColorSpaces;
/*! @brief X11 specific /*! @brief X11 specific
* [window hint](@ref GLFW_X11_CLASS_NAME_hint). * [window hint](@ref GLFW_X11_CLASS_NAME_hint).
*/ */
@@ -944,7 +954,8 @@ typedef enum {
typedef enum { typedef enum {
GLFW_IME_NONE, GLFW_IME_NONE,
GLFW_IME_PREEDIT_CHANGED, GLFW_IME_PREEDIT_CHANGED,
GLFW_IME_COMMIT_TEXT GLFW_IME_COMMIT_TEXT,
GLFW_IME_WAYLAND_DONE_EVENT,
} GLFWIMEState; } GLFWIMEState;
typedef enum { typedef enum {

View File

@@ -775,6 +775,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
glfwWindowHintString(GLFW_X11_INSTANCE_NAME, wm_class_name); glfwWindowHintString(GLFW_X11_INSTANCE_NAME, wm_class_name);
glfwWindowHintString(GLFW_X11_CLASS_NAME, wm_class_class); glfwWindowHintString(GLFW_X11_CLASS_NAME, wm_class_class);
glfwWindowHintString(GLFW_WAYLAND_APP_ID, wm_class_class); glfwWindowHintString(GLFW_WAYLAND_APP_ID, wm_class_class);
glfwWindowHint(GLFW_COCOA_COLOR_SPACE, OPT(macos_colorspace));
#endif #endif
if (global_state.num_os_windows >= MAX_CHILDREN) { if (global_state.num_os_windows >= MAX_CHILDREN) {

View File

@@ -1505,7 +1505,7 @@ x_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixe
static bool static bool
y_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) { y_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) {
const GraphicsCommand *g = data; const GraphicsCommand *g = data;
return ref->start_row <= (int32_t)g->y_offset - 1 && ((int32_t)(g->y_offset - 1 < ref->start_row + ref->effective_num_rows)); return ref->start_row <= (int32_t)g->y_offset - 1 && ((int32_t)g->y_offset - 1) < ((int32_t)(ref->start_row + ref->effective_num_rows));
} }
static bool static bool

View File

@@ -136,6 +136,12 @@ on_key_input(GLFWkeyevent *ev) {
id_type active_window_id = w->id; id_type active_window_id = w->id;
switch(ev->ime_state) { switch(ev->ime_state) {
case GLFW_IME_WAYLAND_DONE_EVENT:
// If we update IME position here it sends GNOME's text input system into
// an infinite loop. See https://github.com/kovidgoyal/kitty/issues/5105
screen_draw_overlay_text(screen, NULL);
debug("handled wayland IME done event\n");
return;
case GLFW_IME_PREEDIT_CHANGED: case GLFW_IME_PREEDIT_CHANGED:
update_ime_position(w, screen); update_ime_position(w, screen);
screen_draw_overlay_text(screen, text); screen_draw_overlay_text(screen, text);

View File

@@ -2,6 +2,7 @@
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
import os
from typing import Any, Dict, Iterable, List, NamedTuple, Optional, Sequence from typing import Any, Dict, Iterable, List, NamedTuple, Optional, Sequence
from .boss import Boss from .boss import Boss
@@ -10,7 +11,8 @@ from .cli import parse_args
from .cli_stub import LaunchCLIOptions from .cli_stub import LaunchCLIOptions
from .constants import kitty_exe, shell_path from .constants import kitty_exe, shell_path
from .fast_data_types import ( from .fast_data_types import (
get_os_window_title, patch_color_profiles, set_clipboard_string get_boss, get_options, get_os_window_title, patch_color_profiles,
set_clipboard_string
) )
from .options.utils import env as parse_env from .options.utils import env as parse_env
from .tabs import Tab, TabManager from .tabs import Tab, TabManager
@@ -34,48 +36,51 @@ def options_spec() -> str:
return ''' return '''
--window-title --title --window-title --title
The title to set for the new window. By default, title is controlled by the The title to set for the new window. By default, title is controlled by the
child process. The special value :code:`current` will copy the title from the currently child process. The special value :code:`current` will copy the title from the
active window. currently active window.
--tab-title --tab-title
The title for the new tab if launching in a new tab. By default, the title The title for the new tab if launching in a new tab. By default, the title
of the active window in the tab is used as the tab title. The special value of the active window in the tab is used as the tab title. The special value
:code:`current` will copy the title form the title of the currently active tab. :code:`current` will copy the title from the title of the currently active tab.
--type --type
type=choices type=choices
default=window default=window
choices=window,tab,os-window,overlay,background,clipboard,primary choices=window,tab,os-window,overlay,background,clipboard,primary
Where to launch the child process, in a new kitty window in the current tab, Where to launch the child process, in a new kitty :code:`window` in the current
a new tab, or a new OS window or an overlay over the current window. tab, a new :code:`tab`, or a new :code:`os-window` or an :code:`overlay` over
Note that if the current window already has an overlay, then it will the current window. Note that if the current window already has an overlay, then
open a new window. The value of background means the process will be it will open a new window. The value of :code:`background` means the process
run in the background. The values clipboard and primary are meant will be run in the background. The values :code:`clipboard` and :code:`primary`
to work with :option:`launch --stdin-source` to copy data to the system are meant to work with :option:`--stdin-source <launch --stdin-source>` to copy
clipboard or primary selection. data to the system clipboard or primary selection.
--keep-focus --dont-take-focus --keep-focus --dont-take-focus
type=bool-set type=bool-set
Keep the focus on the currently active window instead of switching Keep the focus on the currently active window instead of switching to the newly
to the newly opened window. opened window.
--cwd --cwd
The working directory for the newly launched child. Use the special value The working directory for the newly launched child. Use the special value
:code:`current` to use the working directory of the currently active window. :code:`current` to use the working directory of the currently active window.
The special value :code:`last_reported` uses the last working directory The special value :code:`last_reported` uses the last working directory reported
reported by the shell (needs :ref:`shell_integration` to work). by the shell (needs :ref:`shell_integration` to work). The special value
:code:`oldest` works like :code:`current` but uses the working directory of the
oldest foreground process associated with the currently active window rather
than the newest foreground process.
--env --env
type=list type=list
Environment variables to set in the child process. Can be specified multiple Environment variables to set in the child process. Can be specified multiple
times to set different environment variables. Syntax: :code:`name=value`. times to set different environment variables. Syntax: :code:`name=value`. Using
Using :code:`name=` will set to empty string and just :code:`name` will :code:`name=` will set to empty string and just :code:`name` will remove the
remove the environment variable. environment variable.
--hold --hold
@@ -97,121 +102,129 @@ currently active window.
--copy-env --copy-env
type=bool-set type=bool-set
Copy the environment variables from the currently active window into the Copy the environment variables from the currently active window into the newly
newly launched child process. Note that most shells only set environment launched child process. Note that most shells only set environment variables
variables for child processes, so this will only copy the environment for child processes, so this will only copy the environment variables that the
variables that the shell process itself has not the environment variables shell process itself has, not the environment variables child processes inside
child processes inside the shell see. To copy that enviroment, use the the shell see. To copy that enviroment, use either the :ref:`clone-in-kitty
kitty remote control feature with :code:`kitty @launch --copy-env`. <clone_shell>` feature or the kitty remote control feature with :option:`kitty
@ launch --copy-env`.
--location --location
type=choices type=choices
default=default default=default
choices=first,after,before,neighbor,last,vsplit,hsplit,split,default choices=first,after,before,neighbor,last,vsplit,hsplit,split,default
Where to place the newly created window when it is added to a tab which Where to place the newly created window when it is added to a tab which already
already has existing windows in it. :code:`after` and :code:`before` place the new has existing windows in it. :code:`after` and :code:`before` place the new
window before or after the active window. :code:`neighbor` is a synonym for :code:`after`. window before or after the active window. :code:`neighbor` is a synonym for
Also applies to creating a new tab, where the value of :code:`after` :code:`after`. Also applies to creating a new tab, where the value of
will cause the new tab to be placed next to the current tab instead of at the end. :code:`after` will cause the new tab to be placed next to the current tab
The values of :code:`vsplit`, :code:`hsplit` and :code:`split` are only used by the instead of at the end. The values of :code:`vsplit`, :code:`hsplit` and
:code:`splits` layout and control if the new window is placed in a vertical, :code:`split` are only used by the :code:`splits` layout and control if the new
horizontal or automatic split with the currently active window. The default is window is placed in a vertical, horizontal or automatic split with the currently
to place the window in a layout dependent manner, typically, after the active window. The default is to place the window in a layout dependent manner,
currently active window. typically, after the currently active window.
--allow-remote-control --allow-remote-control
type=bool-set type=bool-set
Programs running in this window can control kitty (if remote control is Programs running in this window can control kitty (even if remote control is not
enabled). Note that any program with the right level of permissions can still enabled in :file:`kitty.conf`). Note that any program with the right level of
write to the pipes of any other program on the same computer and therefore can permissions can still write to the pipes of any other program on the same
control kitty. It can, however, be useful to block programs running on other computer and therefore can control kitty. It can, however, be useful to block
computers (for example, over ssh) or as other users. programs running on other computers (for example, over SSH) or as other users.
--stdin-source --stdin-source
type=choices type=choices
default=none default=none
choices=none,@selection,@screen,@screen_scrollback,@alternate,@alternate_scrollback,@first_cmd_output_on_screen,@last_cmd_output,@last_visited_cmd_output choices=none,@selection,@screen,@screen_scrollback,@alternate,@alternate_scrollback,@first_cmd_output_on_screen,@last_cmd_output,@last_visited_cmd_output
Pass the screen contents as :code:`STDIN` to the child process. :code:`@selection` is Pass the screen contents as :file:`STDIN` to the child process.
the currently selected text. :code:`@screen` is the contents of the currently active :code:`@selection` is the currently selected text. :code:`@screen` is the
window. :code:`@screen_scrollback` is the same as :code:`@screen`, but includes the contents of the currently active window. :code:`@screen_scrollback` is the same
scrollback buffer as well. :code:`@alternate` is the secondary screen of the current as :code:`@screen`, but includes the scrollback buffer as well.
active window. For example if you run a full screen terminal application, the :code:`@alternate` is the secondary screen of the current active window. For
secondary screen will be the screen you return to when quitting the application. example if you run a full screen terminal application, the secondary screen will
:code:`@first_cmd_output_on_screen` is the output from the first command run in the shell on screen, be the screen you return to when quitting the application.
:code:`@last_cmd_output` is the output from the last command run in the shell, :code:`@first_cmd_output_on_screen` is the output from the first command run in
:code:`@last_visited_cmd_output` is the first output below the last scrolled position via the shell on screen, :code:`@last_cmd_output` is the output from the last
scroll_to_prompt, this three needs :ref:`shell_integration` to work. command run in the shell, :code:`@last_visited_cmd_output` is the first output
below the last scrolled position via :ac:`scroll_to_prompt`, this three needs
:ref:`shell integration <shell_integration>` to work.
--stdin-add-formatting --stdin-add-formatting
type=bool-set type=bool-set
When using :option:`launch --stdin-source` add formatting escape codes, without this When using :option:`--stdin-source <launch --stdin-source>` add formatting
only plain text will be sent. escape codes, without this only plain text will be sent.
--stdin-add-line-wrap-markers --stdin-add-line-wrap-markers
type=bool-set type=bool-set
When using :option:`launch --stdin-source` add a carriage return at every line wrap When using :option:`--stdin-source <launch --stdin-source>` add a carriage
location (where long lines are wrapped at screen edges). This is useful if you return at every line wrap location (where long lines are wrapped at screen
want to pipe to program that wants to duplicate the screen layout of the edges). This is useful if you want to pipe to program that wants to duplicate
screen. the screen layout of the screen.
--marker --marker
Create a marker that highlights text in the newly created window. The syntax is Create a marker that highlights text in the newly created window. The syntax is
the same as for the :code:`toggle_marker` map action (see :doc:`/marks`). the same as for the :ac:`toggle_marker` action (see :doc:`/marks`).
--os-window-class --os-window-class
Set the WM_CLASS property on X11 and the application id property on Wayland for Set the *WM_CLASS* property on X11 and the application id property on Wayland
the newly created OS Window when using :option:`launch --type`=os-window. for the newly created OS window when using :option:`--type=os-window
Defaults to whatever is used by the parent kitty process, which in turn <launch --type>`. Defaults to whatever is used by the parent kitty process,
defaults to :code:`kitty`. which in turn defaults to :code:`kitty`.
--os-window-name --os-window-name
Set the WM_NAME property on X11 for the newly created OS Window when using Set the *WM_NAME* property on X11 for the newly created OS Window when using
:option:`launch --type`=os-window. Defaults to :option:`launch --os-window-class`. :option:`--type=os-window <launch --type>`. Defaults to
:option:`--os-window-class <launch --os-window-class>`.
--os-window-title --os-window-title
Set the title for the newly created OS window. This title will override any Set the title for the newly created OS window. This title will override any
titles set by programs running in kitty. The special value :code:`current` titles set by programs running in kitty. The special value :code:`current` will
will use the title of the current OS Window, if any. use the title of the current OS window, if any.
--logo --logo
Path to a PNG image to use as the logo for the newly created window. See :opt:`window_logo_path`. Path to a PNG image to use as the logo for the newly created window. See
:opt:`window_logo_path`.
--logo-position --logo-position
The position for the window logo. Only takes effect if :option:`--logo` is specified. See :opt:`window_logo_position`. The position for the window logo. Only takes effect if :option:`--logo` is
specified. See :opt:`window_logo_position`.
--logo-alpha --logo-alpha
type=float type=float
default=-1 default=-1
The amount the window logo should be faded into the background. The amount the window logo should be faded into the background. Only takes
Only takes effect if :option:`--logo` is specified. See :opt:`window_logo_position`. effect if :option:`--logo` is specified. See :opt:`window_logo_position`.
--color --color
type=list type=list
Change colors in the newly launched window. You can either specify a path to a .conf Change colors in the newly launched window. You can either specify a path to a
file with the same syntax as kitty.conf to read the colors from, or specify them :file:`.conf` file with the same syntax as :file:`kitty.conf` to read the colors
individually, for example: ``--color background=white`` ``--color foreground=red`` from, or specify them individually, for example: ``--color background=white``
``--color foreground=red``
--watcher -w --watcher -w
type=list type=list
Path to a python file. Appropriately named functions in this file will be called Path to a Python file. Appropriately named functions in this file will be called
for various events, such as when the window is resized, focused or closed. See the section for various events, such as when the window is resized, focused or closed. See
on watchers in the launch command documentation: :ref:`watchers`. Relative paths are the section on watchers in the launch command documentation: :ref:`watchers`.
resolved relative to the kitty config directory. Global watchers for all windows can be Relative paths are resolved relative to the :ref:`kitty config directory
specified with :opt:`watcher`. <confloc>`. Global watchers for all windows can be specified with
:opt:`watcher` in :file:`kitty.conf`.
''' '''
@@ -224,7 +237,7 @@ def parse_launch_args(args: Optional[Sequence[str]] = None) -> LaunchSpec:
return LaunchSpec(opts, args) return LaunchSpec(opts, args)
def get_env(opts: LaunchCLIOptions, active_child: Optional[Child]) -> Dict[str, str]: def get_env(opts: LaunchCLIOptions, active_child: Optional[Child] = None) -> Dict[str, str]:
env: Dict[str, str] = {} env: Dict[str, str] = {}
if opts.copy_env and active_child: if opts.copy_env and active_child:
env.update(active_child.foreground_environ) env.update(active_child.foreground_environ)
@@ -335,6 +348,7 @@ class ForceWindowLaunch:
force_window_launch = ForceWindowLaunch() force_window_launch = ForceWindowLaunch()
non_window_launch_types = 'background', 'clipboard', 'primary'
def launch( def launch(
@@ -342,9 +356,11 @@ def launch(
opts: LaunchCLIOptions, opts: LaunchCLIOptions,
args: List[str], args: List[str],
target_tab: Optional[Tab] = None, target_tab: Optional[Tab] = None,
force_target_tab: bool = False force_target_tab: bool = False,
active: Optional[Window] = None,
is_clone_launch: str = '',
) -> Optional[Window]: ) -> Optional[Window]:
active = boss.active_window_for_cwd active = active or boss.active_window_for_cwd
if active: if active:
active_child = active.child active_child = active.child
else: else:
@@ -353,7 +369,7 @@ def launch(
opts.window_title = active.title if active else None opts.window_title = active.title if active else None
if opts.tab_title == 'current': if opts.tab_title == 'current':
atab = boss.active_tab atab = boss.active_tab
opts.tab_title = atab.title if atab else None opts.tab_title = atab.effective_title if atab else None
if opts.os_window_title == 'current': if opts.os_window_title == 'current':
tm = boss.active_tab_manager tm = boss.active_tab_manager
opts.os_window_title = get_os_window_title(tm.os_window_id) if tm else None opts.os_window_title = get_os_window_title(tm.os_window_id) if tm else None
@@ -377,6 +393,9 @@ def launch(
elif opts.cwd == 'last_reported': elif opts.cwd == 'last_reported':
if active: if active:
kw['cwd_from'] = CwdRequest(active, CwdRequestType.last_reported) kw['cwd_from'] = CwdRequest(active, CwdRequestType.last_reported)
elif opts.cwd == 'oldest':
if active:
kw['cwd_from'] = CwdRequest(active, CwdRequestType.oldest)
else: else:
kw['cwd'] = opts.cwd kw['cwd'] = opts.cwd
if opts.location != 'default': if opts.location != 'default':
@@ -435,7 +454,7 @@ def launch(
if exe: if exe:
final_cmd[0] = exe final_cmd[0] = exe
kw['cmd'] = final_cmd kw['cmd'] = final_cmd
if force_window_launch and opts.type not in ('background', 'clipboard', 'primary'): if force_window_launch and opts.type not in non_window_launch_types:
opts.type = 'window' opts.type = 'window'
if opts.type == 'overlay' and active: if opts.type == 'overlay' and active:
kw['overlay_for'] = active.id kw['overlay_for'] = active.id
@@ -461,12 +480,164 @@ def launch(
tab = tab_for_window(boss, opts, target_tab) tab = tab_for_window(boss, opts, target_tab)
if tab is not None: if tab is not None:
watchers = load_watch_modules(opts.watcher) watchers = load_watch_modules(opts.watcher)
new_window: Window = tab.new_window(env=env or None, watchers=watchers or None, **kw) new_window: Window = tab.new_window(env=env or None, watchers=watchers or None, is_clone_launch=is_clone_launch, **kw)
if opts.color: if opts.color:
apply_colors(new_window, opts.color) apply_colors(new_window, opts.color)
if opts.keep_focus and active: if opts.keep_focus and active:
boss.set_active_window(active, switch_os_window_if_needed=True) boss.set_active_window(active, switch_os_window_if_needed=True, for_keep_focus=True)
if opts.logo: if opts.logo:
new_window.set_logo(opts.logo, opts.logo_position or '', opts.logo_alpha) new_window.set_logo(opts.logo, opts.logo_position or '', opts.logo_alpha)
return new_window return new_window
return None return None
def parse_opts_for_clone(args: List[str]) -> LaunchCLIOptions:
unsafe, unsafe_args = parse_launch_args(args)
default_opts, default_args = parse_launch_args()
# only copy safe options, those that dont lead to local code exec
for x in (
'window_title', 'tab_title', 'type', 'keep_focus', 'cwd', 'env', 'hold',
'location', 'os_window_class', 'os_window_name', 'os_window_title',
'logo', 'logo_position', 'logo_alpha', 'color'
):
setattr(default_opts, x, getattr(unsafe, x))
return default_opts
def parse_bash_env(text: str) -> Dict[str, str]:
# See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
ans = {}
pos = 0
escapes = r'"\$`'
while pos < len(text):
idx = text.find('="', pos)
if idx < 0:
break
i = text.rfind(' ', 0, idx)
if i < 0:
break
key = text[i+1:idx]
pos = idx + 2
buf: List[str] = []
a = buf.append
while pos < len(text):
ch = text[pos]
pos += 1
if ch == '\\':
if text[pos] in escapes:
a(text[pos])
pos += 1
continue
a(ch)
elif ch == '"':
break
else:
a(ch)
ans[key] = ''.join(buf)
return ans
def parse_null_env(text: str) -> Dict[str, str]:
ans = {}
for line in text.split('\0'):
if line:
try:
k, v = line.split('=', 1)
except ValueError:
continue
ans[k] = v
return ans
class CloneCmd:
def __init__(self, msg: str) -> None:
self.args: List[str] = []
self.env: Optional[Dict[str, str]] = None
self.cwd = ''
self.shell = ''
self.envfmt = 'default'
self.pid = -1
self.history = ''
self.parse_message(msg)
self.opts = parse_opts_for_clone(self.args)
def parse_message(self, msg: str) -> None:
import base64
simple = 'pid', 'envfmt', 'shell'
for x in msg.split(','):
k, v = x.split('=', 1)
if k in simple:
setattr(self, k, int(v) if k == 'pid' else v)
continue
v = base64.standard_b64decode(v).decode('utf-8', 'replace')
if k == 'a':
self.args.append(v)
elif k == 'env':
env = parse_bash_env(v) if self.envfmt == 'bash' else parse_null_env(v)
self.env = {k: v for k, v in env.items() if k not in {
'HOME', 'LOGNAME', 'USER', 'PWD',
# some people export these. We want the shell rc files to recreate them
'PS0', 'PS1', 'PS2', 'PS3', 'PS4', 'RPS1', 'PROMPT_COMMAND', 'SHLVL',
# conda state env vars
'CONDA_SHLVL', 'CONDA_PREFIX', 'CONDA_PROMPT_MODIFIER', 'CONDA_EXE', 'CONDA_PYTHON_EXE', '_CE_CONDA', '_CE_M',
# skip SSH environment variables
'SSH_CLIENT', 'SSH_CONNECTION', 'SSH_ORIGINAL_COMMAND', 'SSH_TTY', 'SSH2_TTY',
'SSH_TUNNEL', 'SSH_USER_AUTH', 'SSH_AUTH_SOCK',
} and not k.startswith((
# conda state env vars for multi-level virtual environments
'CONDA_PREFIX_',
))}
elif k == 'cwd':
self.cwd = v
elif k == 'history':
self.history = v
def clone_and_launch(msg: str, window: Window) -> None:
from .child import cmdline_of_process
from .shell_integration import serialize_env
c = CloneCmd(msg)
if c.cwd and not c.opts.cwd:
c.opts.cwd = c.cwd
c.opts.copy_colors = True
c.opts.copy_env = False
if c.opts.type in non_window_launch_types:
c.opts.type = 'window'
env_to_serialize = c.env or {}
if env_to_serialize.get('PATH') and env_to_serialize.get('VIRTUAL_ENV'):
# only pass VIRTUAL_ENV if it is currently active
if f"{env_to_serialize['VIRTUAL_ENV']}/bin" not in env_to_serialize['PATH'].split(os.pathsep):
del env_to_serialize['VIRTUAL_ENV']
env_to_serialize['KITTY_CLONE_SOURCE_STRATEGIES'] = ',' + ','.join(get_options().clone_source_strategies) + ','
is_clone_launch = serialize_env(c.shell, env_to_serialize)
ssh_kitten_cmdline = window.ssh_kitten_cmdline()
if ssh_kitten_cmdline:
from kittens.ssh.utils import (
patch_cmdline, set_cwd_in_cmdline, set_env_in_cmdline
)
cmdline = ssh_kitten_cmdline
if c.opts.cwd:
set_cwd_in_cmdline(c.opts.cwd, cmdline)
c.opts.cwd = None
if c.env:
set_env_in_cmdline({
'KITTY_IS_CLONE_LAUNCH': is_clone_launch,
}, cmdline)
c.env = None
if c.opts.env:
for entry in reversed(c.opts.env):
patch_cmdline('env', entry, cmdline)
c.opts.env = []
else:
try:
cmdline = cmdline_of_process(c.pid)
except Exception:
cmdline = []
if not cmdline:
cmdline = list(window.child.argv)
if cmdline and cmdline[0] == window.child.final_argv0:
cmdline[0] = window.child.final_exe
if cmdline and cmdline == [window.child.final_exe] + window.child.argv[1:]:
cmdline = window.child.unmodified_argv
launch(get_boss(), c.opts, cmdline, active=window, is_clone_launch=is_clone_launch)

View File

@@ -17,7 +17,7 @@ from .conf.utils import BadLine
from .config import cached_values_for from .config import cached_values_for
from .constants import ( from .constants import (
appname, beam_cursor_data_file, config_dir, glfw_path, is_macos, appname, beam_cursor_data_file, config_dir, glfw_path, is_macos,
is_wayland, kitty_exe, logo_png_file, running_in_kitty is_wayland, kitty_exe, logo_png_file, running_in_kitty, website_url
) )
from .fast_data_types import ( from .fast_data_types import (
GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window, GLFW_IBEAM_CURSOR, GLFW_MOD_ALT, GLFW_MOD_SHIFT, create_os_window,
@@ -29,7 +29,7 @@ from .fonts.render import set_font_family
from .options.types import Options from .options.types import Options
from .options.utils import DELETE_ENV_VAR from .options.utils import DELETE_ENV_VAR
from .os_window_size import initial_window_size_func from .os_window_size import initial_window_size_func
from .session import get_os_window_sizing_data from .session import create_sessions, get_os_window_sizing_data
from .types import SingleKey from .types import SingleKey
from .utils import ( from .utils import (
cleanup_ssh_control_masters, detach, expandvars, log_error, cleanup_ssh_control_masters, detach, expandvars, log_error,
@@ -163,19 +163,24 @@ def _run_app(opts: Options, args: CLIOptions, bad_lines: Sequence[BadLine] = ())
val = get_macos_shortcut_for(func_map, 'load_config_file', lookup_name='reload_config') val = get_macos_shortcut_for(func_map, 'load_config_file', lookup_name='reload_config')
if val is not None: if val is not None:
global_shortcuts['reload_config'] = val global_shortcuts['reload_config'] = val
val = get_macos_shortcut_for(func_map, f'open_url {website_url()}', lookup_name='open_kitty_website')
if val is not None:
global_shortcuts['open_kitty_website'] = val
if is_macos and opts.macos_custom_beam_cursor: if is_macos and opts.macos_custom_beam_cursor:
set_custom_ibeam_cursor() set_custom_ibeam_cursor()
if not is_wayland() and not is_macos: # no window icons on wayland if not is_wayland() and not is_macos: # no window icons on wayland
set_x11_window_icon() set_x11_window_icon()
with cached_values_for(run_app.cached_values_name) as cached_values: with cached_values_for(run_app.cached_values_name) as cached_values:
startup_sessions = tuple(create_sessions(opts, args, default_session=opts.startup_session))
wincls = (startup_sessions[0].os_window_class if startup_sessions else '') or args.cls or appname
with startup_notification_handler(extra_callback=run_app.first_window_callback) as pre_show_callback: with startup_notification_handler(extra_callback=run_app.first_window_callback) as pre_show_callback:
window_id = create_os_window( window_id = create_os_window(
run_app.initial_window_size_func(get_os_window_sizing_data(opts), cached_values), run_app.initial_window_size_func(get_os_window_sizing_data(opts, startup_sessions[0] if startup_sessions else None), cached_values),
pre_show_callback, pre_show_callback,
args.title or appname, args.name or args.cls or appname, args.title or appname, args.name or args.cls or appname,
args.cls or appname, load_all_shaders, disallow_override_title=bool(args.title)) wincls, load_all_shaders, disallow_override_title=bool(args.title))
boss = Boss(opts, args, cached_values, global_shortcuts) boss = Boss(opts, args, cached_values, global_shortcuts)
boss.start(window_id) boss.start(window_id, startup_sessions)
if bad_lines: if bad_lines:
boss.show_bad_config_lines(bad_lines) boss.show_bad_config_lines(bad_lines)
try: try:

View File

@@ -58,7 +58,7 @@
// National Replacement Character Set Mode // National Replacement Character Set Mode
#define DECNRCM (42 << 5) #define DECNRCM (42 << 5)
// Xterm mouse protocol // xterm mouse protocol
#define MOUSE_BUTTON_TRACKING (1000 << 5) #define MOUSE_BUTTON_TRACKING (1000 << 5)
#define MOUSE_MOTION_TRACKING (1002 << 5) #define MOUSE_MOTION_TRACKING (1002 << 5)
#define MOUSE_MOVE_TRACKING (1003 << 5) #define MOUSE_MOVE_TRACKING (1003 << 5)

View File

@@ -120,9 +120,13 @@ encode_mouse_button(Window *w, int button, MouseAction action, int mods) {
if (button == GLFW_MOUSE_BUTTON_LEFT) { if (button == GLFW_MOUSE_BUTTON_LEFT) {
switch(action) { switch(action) {
case PRESS: case PRESS:
global_state.tracked_drag_in_window = w->id; break; global_state.tracked_drag_in_window = w->id;
global_state.tracked_drag_button = button;
break;
case RELEASE: case RELEASE:
global_state.tracked_drag_in_window = 0; break; global_state.tracked_drag_in_window = 0;
global_state.tracked_drag_button = -1;
break;
default: default:
break; break;
} }
@@ -360,7 +364,7 @@ HANDLER(handle_move_event) {
handle_mouse_movement_in_kitty(w, button, mouse_cell_changed | cell_half_changed); handle_mouse_movement_in_kitty(w, button, mouse_cell_changed | cell_half_changed);
} else { } else {
if (!mouse_cell_changed && screen->modes.mouse_tracking_protocol != SGR_PIXEL_PROTOCOL) return; if (!mouse_cell_changed && screen->modes.mouse_tracking_protocol != SGR_PIXEL_PROTOCOL) return;
int sz = encode_mouse_button(w, MAX(0, button), button >=0 ? DRAG : MOVE, modifiers); int sz = encode_mouse_button(w, button, button >=0 ? DRAG : MOVE, modifiers);
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); } if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
} }
} }
@@ -769,7 +773,7 @@ mouse_event(const int button, int modifiers, int action) {
clamp_to_window = true; clamp_to_window = true;
Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab; Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab;
for (window_idx = 0; window_idx < t->num_windows && t->windows[window_idx].id != w->id; window_idx++); for (window_idx = 0; window_idx < t->num_windows && t->windows[window_idx].id != w->id; window_idx++);
handle_move_event(w, button, modifiers, window_idx); handle_move_event(w, global_state.tracked_drag_button, modifiers, window_idx);
clamp_to_window = false; clamp_to_window = false;
debug("sent to child as drag move\n"); debug("sent to child as drag move\n");
return; return;

File diff suppressed because it is too large Load Diff

41
kitty/options/parse.py generated
View File

@@ -8,15 +8,16 @@ from kitty.conf.utils import (
from kitty.options.utils import ( from kitty.options.utils import (
action_alias, active_tab_title_template, adjust_baseline, adjust_line_height, allow_hyperlinks, action_alias, active_tab_title_template, adjust_baseline, adjust_line_height, allow_hyperlinks,
allow_remote_control, bell_on_tab, box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts, allow_remote_control, bell_on_tab, box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts,
clipboard_control, config_or_absolute_path, copy_on_select, cursor_text_color, clipboard_control, clone_source_strategies, config_or_absolute_path, copy_on_select,
deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias, cursor_text_color, deprecated_hide_window_decorations_aliases,
deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations, deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures,
macos_option_as_alt, macos_titlebar_color, narrow_symbols, optional_edge_width, parse_map, edge_width, env, font_features, hide_window_decorations, macos_option_as_alt, macos_titlebar_color,
parse_mouse_map, paste_actions, resize_draw_strategy, scrollback_lines, narrow_symbols, optional_edge_width, parse_map, parse_mouse_map, paste_actions,
scrollback_pager_history_size, shell_integration, store_multiple, symbol_map, tab_activity_symbol, resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, shell_integration,
tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height,
tab_title_template, titlebar_color, to_cursor_shape, to_font_size, to_layout_names, to_modifiers, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, titlebar_color,
url_prefixes, url_style, visual_window_select_characters, window_border_width, window_size to_cursor_shape, to_font_size, to_layout_names, to_modifiers, url_prefixes, url_style,
visual_window_select_characters, window_border_width, window_size
) )
@@ -50,6 +51,14 @@ class Parser:
def adjust_line_height(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def adjust_line_height(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['adjust_line_height'] = adjust_line_height(val) ans['adjust_line_height'] = adjust_line_height(val)
def allow_cloning(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_allow_cloning:
raise ValueError(f"The value {val} is not a valid choice for allow_cloning")
ans["allow_cloning"] = val
choices_for_allow_cloning = frozenset(('yes', 'y', 'true', 'no', 'n', 'false', 'ask'))
def allow_hyperlinks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def allow_hyperlinks(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['allow_hyperlinks'] = allow_hyperlinks(val) ans['allow_hyperlinks'] = allow_hyperlinks(val)
@@ -112,6 +121,9 @@ class Parser:
def clipboard_max_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def clipboard_max_size(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['clipboard_max_size'] = positive_float(val) ans['clipboard_max_size'] = positive_float(val)
def clone_source_strategies(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['clone_source_strategies'] = clone_source_strategies(val)
def close_on_child_death(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def close_on_child_death(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['close_on_child_death'] = to_bool(val) ans['close_on_child_death'] = to_bool(val)
@@ -1023,6 +1035,14 @@ class Parser:
def listen_on(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def listen_on(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['listen_on'] = str(val) ans['listen_on'] = str(val)
def macos_colorspace(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
val = val.lower()
if val not in self.choices_for_macos_colorspace:
raise ValueError(f"The value {val} is not a valid choice for macos_colorspace")
ans["macos_colorspace"] = val
choices_for_macos_colorspace = frozenset(('srgb', 'default', 'displayp3'))
def macos_custom_beam_cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def macos_custom_beam_cursor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['macos_custom_beam_cursor'] = to_bool(val) ans['macos_custom_beam_cursor'] = to_bool(val)
@@ -1143,6 +1163,9 @@ class Parser:
def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['select_by_word_characters'] = str(val) ans['select_by_word_characters'] = str(val)
def select_by_word_characters_forward(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['select_by_word_characters_forward'] = str(val)
def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['selection_background'] = to_color_or_none(val) ans['selection_background'] = to_color_or_none(val)

View File

@@ -304,6 +304,19 @@ convert_from_opts_select_by_word_characters(PyObject *py_opts, Options *opts) {
Py_DECREF(ret); Py_DECREF(ret);
} }
static void
convert_from_python_select_by_word_characters_forward(PyObject *val, Options *opts) {
select_by_word_characters_forward(val, opts);
}
static void
convert_from_opts_select_by_word_characters_forward(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "select_by_word_characters_forward");
if (ret == NULL) return;
convert_from_python_select_by_word_characters_forward(ret, opts);
Py_DECREF(ret);
}
static void static void
convert_from_python_click_interval(PyObject *val, Options *opts) { convert_from_python_click_interval(PyObject *val, Options *opts) {
opts->click_interval = parse_s_double_to_monotonic_t(val); opts->click_interval = parse_s_double_to_monotonic_t(val);
@@ -1006,6 +1019,19 @@ convert_from_opts_macos_menubar_title_max_length(PyObject *py_opts, Options *opt
Py_DECREF(ret); Py_DECREF(ret);
} }
static void
convert_from_python_macos_colorspace(PyObject *val, Options *opts) {
opts->macos_colorspace = macos_colorspace(val);
}
static void
convert_from_opts_macos_colorspace(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "macos_colorspace");
if (ret == NULL) return;
convert_from_python_macos_colorspace(ret, opts);
Py_DECREF(ret);
}
static bool static bool
convert_opts_from_python_opts(PyObject *py_opts, Options *opts) { convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
convert_from_opts_font_size(py_opts, opts); convert_from_opts_font_size(py_opts, opts);
@@ -1054,6 +1080,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_select_by_word_characters(py_opts, opts); convert_from_opts_select_by_word_characters(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_select_by_word_characters_forward(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_click_interval(py_opts, opts); convert_from_opts_click_interval(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_focus_follows_mouse(py_opts, opts); convert_from_opts_focus_follows_mouse(py_opts, opts);
@@ -1162,5 +1190,7 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_macos_menubar_title_max_length(py_opts, opts); convert_from_opts_macos_menubar_title_max_length(py_opts, opts);
if (PyErr_Occurred()) return false; if (PyErr_Occurred()) return false;
convert_from_opts_macos_colorspace(py_opts, opts);
if (PyErr_Occurred()) return false;
return true; return true;
} }

View File

@@ -127,6 +127,13 @@ pointer_shape(PyObject *shape_name) {
return BEAM; return BEAM;
} }
static int
macos_colorspace(PyObject *csname) {
if (PyUnicode_CompareWithASCIIString(csname, "srgb")) return 1;
if (PyUnicode_CompareWithASCIIString(csname, "displayp3")) return 2;
return 0;
}
static inline void static inline void
free_url_prefixes(void) { free_url_prefixes(void) {
OPT(url_prefixes).num = 0; OPT(url_prefixes).num = 0;
@@ -180,6 +187,12 @@ select_by_word_characters(PyObject *chars, Options *opts) {
opts->select_by_word_characters = list_of_chars(chars); opts->select_by_word_characters = list_of_chars(chars);
} }
static void
select_by_word_characters_forward(PyObject *chars, Options *opts) {
free(opts->select_by_word_characters_forward);
opts->select_by_word_characters_forward = list_of_chars(chars);
}
static void static void
tab_bar_style(PyObject *val, Options *opts) { tab_bar_style(PyObject *val, Options *opts) {
opts->tab_bar_hidden = PyUnicode_CompareWithASCIIString(val, "hidden") == 0 ? true: false; opts->tab_bar_hidden = PyUnicode_CompareWithASCIIString(val, "hidden") == 0 ? true: false;

13
kitty/options/types.py generated
View File

@@ -13,9 +13,11 @@ from kitty.types import FloatEdges, SingleKey
import kitty.types import kitty.types
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
choices_for_allow_cloning = typing.Literal['yes', 'y', 'true', 'no', 'n', 'false', 'ask']
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped'] choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped']
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand'] choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand']
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
choices_for_macos_colorspace = typing.Literal['srgb', 'default', 'displayp3']
choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window']
choices_for_placement_strategy = typing.Literal['center', 'top-left'] choices_for_placement_strategy = typing.Literal['center', 'top-left']
choices_for_pointer_shape_when_dragging = typing.Literal['arrow', 'beam', 'hand'] choices_for_pointer_shape_when_dragging = typing.Literal['arrow', 'beam', 'hand']
@@ -27,9 +29,11 @@ if typing.TYPE_CHECKING:
choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right'] choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right']
choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
else: else:
choices_for_allow_cloning = str
choices_for_background_image_layout = str choices_for_background_image_layout = str
choices_for_default_pointer_shape = str choices_for_default_pointer_shape = str
choices_for_linux_display_server = str choices_for_linux_display_server = str
choices_for_macos_colorspace = str
choices_for_macos_show_window_title_in = str choices_for_macos_show_window_title_in = str
choices_for_placement_strategy = str choices_for_placement_strategy = str
choices_for_pointer_shape_when_dragging = str choices_for_pointer_shape_when_dragging = str
@@ -51,6 +55,7 @@ option_names = ( # {{{
'adjust_baseline', 'adjust_baseline',
'adjust_column_width', 'adjust_column_width',
'adjust_line_height', 'adjust_line_height',
'allow_cloning',
'allow_hyperlinks', 'allow_hyperlinks',
'allow_remote_control', 'allow_remote_control',
'background', 'background',
@@ -70,6 +75,7 @@ option_names = ( # {{{
'click_interval', 'click_interval',
'clipboard_control', 'clipboard_control',
'clipboard_max_size', 'clipboard_max_size',
'clone_source_strategies',
'close_on_child_death', 'close_on_child_death',
'color0', 'color0',
'color1', 'color1',
@@ -369,6 +375,7 @@ option_names = ( # {{{
'kitty_mod', 'kitty_mod',
'linux_display_server', 'linux_display_server',
'listen_on', 'listen_on',
'macos_colorspace',
'macos_custom_beam_cursor', 'macos_custom_beam_cursor',
'macos_hide_from_tasks', 'macos_hide_from_tasks',
'macos_menubar_title_max_length', 'macos_menubar_title_max_length',
@@ -404,6 +411,7 @@ option_names = ( # {{{
'scrollback_pager', 'scrollback_pager',
'scrollback_pager_history_size', 'scrollback_pager_history_size',
'select_by_word_characters', 'select_by_word_characters',
'select_by_word_characters_forward',
'selection_background', 'selection_background',
'selection_foreground', 'selection_foreground',
'shell', 'shell',
@@ -461,6 +469,7 @@ class Options:
adjust_baseline: typing.Union[int, float] = 0 adjust_baseline: typing.Union[int, float] = 0
adjust_column_width: typing.Union[int, float] = 0 adjust_column_width: typing.Union[int, float] = 0
adjust_line_height: typing.Union[int, float] = 0 adjust_line_height: typing.Union[int, float] = 0
allow_cloning: choices_for_allow_cloning = 'ask'
allow_hyperlinks: int = 1 allow_hyperlinks: int = 1
allow_remote_control: str = 'n' allow_remote_control: str = 'n'
background: Color = Color(0, 0, 0) background: Color = Color(0, 0, 0)
@@ -480,6 +489,7 @@ class Options:
click_interval: float = -1.0 click_interval: float = -1.0
clipboard_control: typing.Tuple[str, ...] = ('write-clipboard', 'write-primary', 'read-clipboard-ask', 'read-primary-ask') clipboard_control: typing.Tuple[str, ...] = ('write-clipboard', 'write-primary', 'read-clipboard-ask', 'read-primary-ask')
clipboard_max_size: float = 64.0 clipboard_max_size: float = 64.0
clone_source_strategies: typing.FrozenSet[str] = frozenset({'conda', 'env_var', 'path', 'venv'})
close_on_child_death: bool = False close_on_child_death: bool = False
command_on_bell: typing.List[str] = ['none'] command_on_bell: typing.List[str] = ['none']
confirm_os_window_close: int = -1 confirm_os_window_close: int = -1
@@ -519,6 +529,7 @@ class Options:
kitty_mod: int = 5 kitty_mod: int = 5
linux_display_server: choices_for_linux_display_server = 'auto' linux_display_server: choices_for_linux_display_server = 'auto'
listen_on: str = 'none' listen_on: str = 'none'
macos_colorspace: choices_for_macos_colorspace = 'srgb'
macos_custom_beam_cursor: bool = False macos_custom_beam_cursor: bool = False
macos_hide_from_tasks: bool = False macos_hide_from_tasks: bool = False
macos_menubar_title_max_length: int = 0 macos_menubar_title_max_length: int = 0
@@ -551,6 +562,7 @@ class Options:
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER'] scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
scrollback_pager_history_size: int = 0 scrollback_pager_history_size: int = 0
select_by_word_characters: str = '@-./_~?&=%+#' select_by_word_characters: str = '@-./_~?&=%+#'
select_by_word_characters_forward: str = ''
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205) selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
selection_foreground: typing.Optional[kitty.fast_data_types.Color] = Color(0, 0, 0) selection_foreground: typing.Optional[kitty.fast_data_types.Color] = Color(0, 0, 0)
shell: str = '.' shell: str = '.'
@@ -916,6 +928,7 @@ if is_macos:
defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=107), definition='clear_terminal to_cursor active')) # noqa defaults.map.append(KeyDefinition(trigger=SingleKey(mods=8, key=107), definition='clear_terminal to_cursor active')) # noqa
defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=44), definition='load_config_file')) # noqa defaults.map.append(KeyDefinition(trigger=SingleKey(mods=12, key=44), definition='load_config_file')) # noqa
defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=44), definition='debug_config')) # noqa defaults.map.append(KeyDefinition(trigger=SingleKey(mods=10, key=44), definition='debug_config')) # noqa
defaults.map.append(KeyDefinition(trigger=SingleKey(mods=9, key=47), definition='open_url https://sw.kovidgoyal.net/kitty/')) # noqa
defaults.mouse_map = [ defaults.mouse_map = [
# click_url_or_select # click_url_or_select
MouseMapping(repeat_count=-2, definition='mouse_handle_click selection link prompt'), # noqa MouseMapping(repeat_count=-2, definition='mouse_handle_click selection link prompt'), # noqa

View File

@@ -91,6 +91,20 @@ def kitten_parse(func: str, rest: str) -> FuncArgsType:
return func, [args[0]] + (to_cmdline(args[1]) if len(args) > 1 else []) return func, [args[0]] + (to_cmdline(args[1]) if len(args) > 1 else [])
@func_with_args('open_url')
def open_url_parse(func: str, rest: str) -> FuncArgsType:
from urllib.parse import urlparse
url = ''
try:
url = python_string(rest)
tokens = urlparse(url)
if not all((tokens.scheme, tokens.netloc,)):
raise ValueError('Invalid URL')
except Exception:
log_error('Ignoring invalid URL string: ' + rest)
return func, (url,)
@func_with_args('goto_tab') @func_with_args('goto_tab')
def goto_tab_parse(func: str, rest: str) -> FuncArgsType: def goto_tab_parse(func: str, rest: str) -> FuncArgsType:
args = (max(0, int(rest)), ) args = (max(0, int(rest)), )
@@ -746,6 +760,10 @@ def tab_bar_margin_height(x: str) -> TabBarMarginHeight:
return TabBarMarginHeight(next(ans), next(ans)) return TabBarMarginHeight(next(ans), next(ans))
def clone_source_strategies(x: str) -> FrozenSet[str]:
return frozenset({'venv', 'conda', 'path', 'env_var'} & set(x.lower().split(',')))
def clear_all_mouse_actions(val: str, dict_with_parse_results: Optional[Dict[str, Any]] = None) -> bool: def clear_all_mouse_actions(val: str, dict_with_parse_results: Optional[Dict[str, Any]] = None) -> bool:
ans = to_bool(val) ans = to_bool(val)
if ans and dict_with_parse_results is not None: if ans and dict_with_parse_results is not None:

View File

@@ -1001,7 +1001,7 @@ dispatch_csi(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
case 'm': case 'm':
if (start_modifier == '>' && !end_modifier) { if (start_modifier == '>' && !end_modifier) {
REPORT_ERROR( REPORT_ERROR(
"The application is trying to use XTerm's modifyOtherKeys." "The application is trying to use xterm's modifyOtherKeys."
" This is superseded by the kitty keyboard protocol: https://sw.kovidgoyal.net/kitty/keyboard-protocol/" " This is superseded by the kitty keyboard protocol: https://sw.kovidgoyal.net/kitty/keyboard-protocol/"
" the application should be updated to use that" " the application should be updated to use that"
); );
@@ -1086,6 +1086,7 @@ dispatch_dcs(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
} else IF_SIMPLE_PREFIX("echo|", handle_remote_echo) } else IF_SIMPLE_PREFIX("echo|", handle_remote_echo)
} else IF_SIMPLE_PREFIX("ssh|", handle_remote_ssh) } else IF_SIMPLE_PREFIX("ssh|", handle_remote_ssh)
} else IF_SIMPLE_PREFIX("ask|", handle_remote_askpass) } else IF_SIMPLE_PREFIX("ask|", handle_remote_askpass)
} else IF_SIMPLE_PREFIX("clone|", handle_remote_clone)
#undef IF_SIMPLE_PREFIX #undef IF_SIMPLE_PREFIX
} else { } else {
REPORT_ERROR("Unrecognized DCS @ code: 0x%x", screen->parser_buf[1]); REPORT_ERROR("Unrecognized DCS @ code: 0x%x", screen->parser_buf[1]);

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