Compare commits

..

48 Commits

Author SHA1 Message Date
Kovid Goyal
ad328bfeaa version 0.35.2 2024-06-22 09:04:46 +05:30
Kovid Goyal
df229dafa0 Clarify docs that remote_control_script is a convenience wrapper for launch 2024-06-21 06:17:32 +05:30
Kovid Goyal
1a38b60463 URL detection: Fix IPv6 hostnames breaking URL detection
Fixes #7565
2024-06-21 05:53:21 +05:30
Kovid Goyal
b63e523098 ... 2024-06-20 15:50:57 +05:30
Kovid Goyal
2bcb32d611 Fix scrollback_indicator_opacity not actually controlling the opacity
Fixes #7557
2024-06-19 06:03:30 +05:30
Kovid Goyal
fbdc2b44e0 Merge branch 'fn' of https://github.com/pcc/kitty 2024-06-18 14:06:24 +05:30
Peter Collingbourne
be1000669f Prevent Fn key from scrolling to the bottom
When the Fn key is pressed it should not cause us to scroll to the bottom
of the scrollback. This is because Fn may be used to access movement keys
(e.g. on a MacBook keyboard, Fn+Up = Page Up).

Most keyboards do not expose Fn to the operating system as a separate key
event, but there are two known exceptions: Macs running Linux (generates
XF86Fn) and some ThinkPads (generates XF86WakeUp). Ignore both key
events when deciding whether to scroll to the bottom. For consistency,
do the same when deciding whether key events should hide the mouse.
2024-06-17 23:18:57 -07:00
Kovid Goyal
48f053b8cc Fix #7555 2024-06-18 05:59:12 +05:30
Kovid Goyal
4a48e96e81 Merge branch 'fix-gnome44-transparent-title-bar' of https://github.com/adamschmalhofer/kitty 2024-06-17 20:32:35 +05:30
Adam Schmalhofer
8fabc47776 Fix Gnome 44 invisible title bar on Wayland
a.k.a. title bar is completely missing

Fixes: https://github.com/kovidgoyal/kitty/issues/7425
2024-06-17 13:18:48 +02:00
Kovid Goyal
7b477ccca8 clarify some docs further 2024-06-17 09:27:40 +05:30
Kovid Goyal
9be6b9c374 When using --single-instance allow creating sessions with only background processes 2024-06-17 08:01:43 +05:30
Kovid Goyal
499eb3c3c2 ... 2024-06-17 07:39:04 +05:30
Kovid Goyal
2a6870b21f Wayland labwc: Fix kitty timing out waiting for compositor to quit fucking around with scales on labwc
labwc is unique among Wayland compositors in implementing fractional
scale but not preferred integer buffer scale events. We didn't cater to
this particular combination of before. And to top it off it appears to
have no way for the user to set/control the scale so I cant even test
what it will do with fractional scales other than 1. Sigh. As with all
things Wayland, you need to be a masochist to subject yourself to them.

Fixes #7540
2024-06-16 15:01:46 +05:30
Kovid Goyal
57aa591a90 ... 2024-06-16 06:13:54 +05:30
Kovid Goyal
e0998fcbb1 Update changelog 2024-06-16 06:09:01 +05:30
Kovid Goyal
608a497421 forgot to port test to use new API 2024-06-15 16:41:11 +05:30
Kovid Goyal
f4bec5f4ab Remote control: Fix empty password not working
Fixes #7538
2024-06-15 11:15:19 +05:30
Kovid Goyal
68649d78df Cleanup previous PR 2024-06-15 06:12:31 +05:30
Kovid Goyal
5babab18a0 Merge branch 'unfocused_cursor_shape' of https://github.com/n0pl4c3/kitty 2024-06-15 05:59:45 +05:30
Kovid Goyal
6c4cb4c1d6 Fix #7545 2024-06-15 05:40:10 +05:30
n0pl4c3
1968d0b8e0 Implemented option to change cursor shape in unfocused window 2024-06-14 23:02:34 +02:00
Kovid Goyal
6f0366d42f Update changelog and cleanup docs of the window_logo_scale option 2024-06-14 13:49:58 +05:30
Kovid Goyal
192bd8a211 Merge branch 'window-logo-scaling' of https://github.com/amuDev/kitty 2024-06-14 13:44:53 +05:30
Kovid Goyal
946342c4fb Merge branch 'master' of https://github.com/SpoonOil/kitty 2024-06-14 11:43:00 +05:30
SpoonOil
185645f84b Merge pull request #1 from SpoonOil/SpoonOil-patch-1
Fix typo in definition.py
2024-06-13 22:17:58 -04:00
SpoonOil
af01cf92cc Fix typo in definition.py
It's is incorrect here, which can clearly be seen by expanding the contraction to "It is". Its is correct for possessive.
2024-06-13 22:16:38 -04:00
aki
4d8b34cab8 change window_logo_scale to float, add granular xy scaling options to window_logo_scale 2024-06-13 23:33:28 +09:00
Kovid Goyal
ecc44dffeb Fix #7535
I think
2024-06-13 12:26:54 +05:30
aki
a8b28ca32b remove test block 2024-06-12 22:13:00 +09:00
aki
56fc4eddbd add option to scale window_logo via window_logo_scale 2024-06-12 21:29:04 +09:00
Kovid Goyal
e3239fdcdf ... 2024-06-10 09:25:14 +05:30
Kovid Goyal
dea7752df1 Note that textual now supports the kitty keyboard protocol 2024-06-10 09:24:31 +05:30
Kovid Goyal
0e1737b0e6 Merge branch 'dependabot/go_modules/all-go-deps-c92472c2bb' of https://github.com/kovidgoyal/kitty 2024-06-10 08:51:35 +05:30
dependabot[bot]
3dd09236aa Bump the all-go-deps group with 2 updates
Bumps the all-go-deps group with 2 updates: [golang.org/x/image](https://github.com/golang/image) and [golang.org/x/sys](https://github.com/golang/sys).


Updates `golang.org/x/image` from 0.16.0 to 0.17.0
- [Commits](https://github.com/golang/image/compare/v0.16.0...v0.17.0)

Updates `golang.org/x/sys` from 0.20.0 to 0.21.0
- [Commits](https://github.com/golang/sys/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/image
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-go-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 03:19:16 +00:00
Kovid Goyal
d5fe1333e2 Bump version of wayland client library bundled with the pre-built binaries
Some change in mesa 24.1.1 causes glfw EGL context creation to fail on
Wayland when using anything less than the newest Wayland client library.
This prevents kitty from starting with the error:
[glfw error 65542]: EGL: Failed to get EGL display: Success

Sigh, Wayland. Probably the newest client library will break on older
systems. Even basic things like window creation cant be relied upon to
be stable in this joke of a graphics stack.

See #7517
2024-06-07 16:27:33 +05:30
Kovid Goyal
f155d23a1e Merge branch 'ubuntu-shortcuts' of https://github.com/metaflow/kitty 2024-06-07 15:08:38 +05:30
Mikhail Goncharov
c153ea8acc use readlink -f ~ to get user home
/home/$USER works most of the time but might be wrong
2024-06-07 11:03:37 +02:00
Kovid Goyal
a6c7744119 ssh kitten: Passthrough when -V is specified
Fixes #7515
2024-06-06 19:52:35 +05:30
Kovid Goyal
50d5deb9fe Debug output: Use proper output for titlebar colors 2024-06-05 06:04:25 +05:30
Kovid Goyal
6c3c36c5b0 Merge branch 'pr-2e007452' of https://github.com/sxyazi/kitty 2024-06-04 11:52:47 +05:30
sxyazi
14c16fa943 Add Yazi terminal file manager to the list of software implementing kitty's graphics protocol 2024-06-04 14:06:14 +08:00
Kovid Goyal
f17a5934e2 Fix #7504 2024-06-04 11:02:47 +05:30
Kovid Goyal
6bd8c71e30 Merge branch 'dependabot/go_modules/all-go-deps-21d6f4b677' of https://github.com/kovidgoyal/kitty 2024-06-03 22:27:15 +05:30
dependabot[bot]
521d3a86f0 Bump github.com/shirou/gopsutil/v3 in the all-go-deps group
Bumps the all-go-deps group with 1 update: [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil).


Updates `github.com/shirou/gopsutil/v3` from 3.24.4 to 3.24.5
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/compare/v3.24.4...v3.24.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-03 03:21:51 +00:00
Kovid Goyal
88aa4d1de3 Revert 72272ab4fe
Apparently NVIDIA drivers dont handle this well. Sigh.

Go back to calling wl_egl_window_resize() before resizing the
framebuffer instead of before swapping in the resized framebuffer.
Logically, these should be equivalent, but...

Wayland is such an ongoing disaster.

Fixes #7493 (I hope).
2024-06-02 19:24:00 +05:30
Kovid Goyal
06a45dcf36 Merge branch 'master' of https://github.com/sweetbbak/kitty 2024-05-31 22:48:23 +05:30
Meili C
63de42aaef add simde dependency to stdenv.linux in shell.nix 2024-05-31 08:49:09 -08:00
37 changed files with 372 additions and 120 deletions

View File

@@ -282,9 +282,9 @@
"name": "wayland",
"os": "linux",
"unix": {
"filename": "wayland-1.22.0.tar.xz",
"hash": "sha256:1540af1ea698a471c2d8e9d288332c7e0fd360c8f1d12936ebb7e7cbc2425842",
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.22.0/downloads/{filename}"]
"filename": "wayland-1.23.0.tar.xz",
"hash": "sha256:05b3e1574d3e67626b5974f862f36b5b427c7ceeb965cb36a4e6c2d342e45ab2",
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.23.0/downloads/{filename}"]
}
},

View File

@@ -55,8 +55,8 @@ particular desktop, but it should work for most major desktop environments.
# If you want to open text files and images in kitty via your file manager also add the kitty-open.desktop file
cp ~/.local/kitty.app/share/applications/kitty-open.desktop ~/.local/share/applications/
# Update the paths to the kitty and its icon in the kitty desktop file(s)
sed -i "s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|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
sed -i "s|Icon=kitty|Icon=$(readlink -f ~)/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g" ~/.local/share/applications/kitty*.desktop
sed -i "s|Exec=kitty|Exec=$(readlink -f ~)/.local/kitty.app/bin/kitty|g" ~/.local/share/applications/kitty*.desktop
# Make xdg-terminal-exec (and hence desktop environments that support it use kitty)
echo 'kitty.desktop' > ~/.config/xdg-terminals.list

View File

@@ -50,6 +50,23 @@ consumption to do the same tasks.
Detailed list of changes
-------------------------------------
0.35.2 [2024-06-22]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- A new option, :opt:`window_logo_scale` to specify how window logos are scaled with respect to the size of the window containing the logo (:pull:`7534`)
- A new option, :opt:`cursor_shape_unfocused` to specify the shape of the text cursor in unfocused OS windows (:pull:`7544`)
- Remote control: Fix empty password not working (:iss:`7538`)
- Wayland: Fix regression in 0.34.0 causing flickering on window resize on NVIDIA drivers (:iss:`7493`)
- Wayland labwc: Fix kitty timing out waiting for compositor to quit fucking around with scales on labwc (:iss:`7540`)
- Fix :opt:`scrollback_indicator_opacity` not actually controlling the opacity (:iss:`7557`)
- URL detection: Fix IPv6 hostnames breaking URL detection (:iss:`7565`)
0.35.1 [2024-05-31]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -29,6 +29,7 @@ Some programs and libraries that use the kitty graphics protocol:
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with image previews
* `Yazi <https://github.com/sxyazi/yazi>`_ - Blazing fast terminal file manager written in Rust, based on async I/O
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
* `tpix <https://github.com/jesvedberg/tpix>`_ - a statically compiled binary that can be used to display images and easily installed on remote servers without root access
* `mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_ - A video player that can play videos in the terminal

View File

@@ -46,6 +46,13 @@ graphics protocol.
Another terminal file manager, with previews of file contents powered by kitty's
graphics protocol.
.. _tool_yazi:
`Yazi <https://github.com/sxyazi/yazi>`_
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Blazing fast terminal file manager, with built-in kitty graphics protocol support
(implemented both Classic protocol and Unicode placeholders).
.. _tool_hunter:
`hunter <https://github.com/rabite0/hunter>`_

View File

@@ -42,6 +42,7 @@ In addition to kitty, this protocol is also implemented in:
<https://github.com/dankamongmen/notcurses/issues/2131>`__
* The `crossterm library
<https://github.com/crossterm-rs/crossterm/pull/688>`__
* The `textual library <https://github.com/Textualize/textual/pull/4631>`__
* The `Vim text editor <https://github.com/vim/vim/commit/63a2e360cca2c70ab0a85d14771d3259d4b3aafa>`__
* The `Emacs text editor via the kkp package <https://github.com/benjaminor/kkp>`__
* The `Neovim text editor <https://github.com/neovim/neovim/pull/18181>`__
@@ -49,7 +50,7 @@ In addition to kitty, this protocol is also implemented in:
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
* The `Helix text editor <https://github.com/helix-editor/helix/pull/4939>`__
* The `far2l file manager <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__
* The `yazi file manager <https://github.com/sxyazi/yazi>`__
* The `Yazi file manager <https://github.com/sxyazi/yazi>`__
* The `awrit web browser <https://github.com/chase/awrit>`__
* The `nushell shell <https://github.com/nushell/nushell/pull/10540>`__
* The `fish shell <https://github.com/fish-shell/fish-shell/commit/8bf8b10f685d964101f491b9cc3da04117a308b4>`__

View File

@@ -287,10 +287,11 @@ If you wish to run a more complex script, you can use::
In this script you can use ``kitten @`` to run as many remote
control commands as you like and process their output.
:ac:`remote_control_script` is really just an alias for the
:ac:`remote_control_script` is similar to the
:ac:`launch` command with ``--type=background --allow-remote-control``.
For more advanced usage, including fine grained permissions, setting
env vars, etc. see the docs for the :doc:`launch <launch>` command.
env vars, command line interpolation, passing data to STDIN, etc.
the :doc:`launch <launch>` command should be used.
.. note:: You do not need :opt:`allow_remote_control` to use these mappings,
as they are not actual remote programs, but are simply a way to reuse the

3
glfw/context.c vendored
View File

@@ -476,9 +476,6 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* handle)
return;
}
#ifdef _GLFW_WAYLAND
_glfwWaylandBeforeBufferSwap(window);
#endif
window->context.swapBuffers(window);
#ifdef _GLFW_WAYLAND
_glfwWaylandAfterBufferSwap(window);

3
glfw/wl_platform.h vendored
View File

@@ -185,9 +185,6 @@ typedef struct _GLFWwindowWayland
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
} layer_shell;
struct {
int width, height, dirty;
} framebuffer_size_at_last_resize;
/* information about axis events on current frame */
struct
{

27
glfw/wl_window.c vendored
View File

@@ -370,27 +370,21 @@ wait_for_swap_to_commit(_GLFWwindow *window) {
static void
resizeFramebuffer(_GLFWwindow* window) {
GLFWwindow *ctx = glfwGetCurrentContext();
const bool ctx_changed = ctx != (GLFWwindow*)window;
if (ctx_changed) glfwMakeContextCurrent((GLFWwindow*)window);
double scale = _glfwWaylandWindowScale(window);
int scaled_width = (int)round(window->wl.width * scale);
int scaled_height = (int)round(window->wl.height * scale);
debug("Resizing framebuffer of window: %llu to: %dx%d window size: %dx%d at scale: %.3f\n",
window->id, scaled_width, scaled_height, window->wl.width, window->wl.height, scale);
wl_egl_window_resize(window->wl.native, scaled_width, scaled_height, 0, 0);
update_regions(window);
wait_for_swap_to_commit(window);
window->wl.framebuffer_size_at_last_resize.width = scaled_width;
window->wl.framebuffer_size_at_last_resize.height = scaled_height;
window->wl.framebuffer_size_at_last_resize.dirty = true;
if (ctx_changed) glfwMakeContextCurrent(ctx);
_glfwInputFramebufferSize(window, scaled_width, scaled_height);
}
void
_glfwWaylandBeforeBufferSwap(_GLFWwindow* window) {
if (window->wl.framebuffer_size_at_last_resize.dirty) {
wl_egl_window_resize(window->wl.native, window->wl.framebuffer_size_at_last_resize.width, window->wl.framebuffer_size_at_last_resize.height, 0, 0);
window->wl.framebuffer_size_at_last_resize.dirty = false;
}
}
void
_glfwWaylandAfterBufferSwap(_GLFWwindow* window) {
if (window->wl.temp_buffer_used_during_window_creation) {
@@ -555,7 +549,10 @@ fractional_scale_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_f
debug("Fractional scale requested: %u/120 = %.2f for window %llu\n", scale, scale / 120., window->id);
window->wl.fractional_scale = scale;
// Hyprland sends a fraction scale = 1 event before configuring the xdg surface and then another after with the correct scale
window->wl.window_fully_created = window->wl.once.surface_configured || scale != 120;
// labwc doesnt support preferred buffer scale, so we assume it's done fucking around with scales even if the scale is 120
// As far as I can tell from googling labwc has no way to specify scales other
// than 1 anyway, so no way to test what it will do in such cases. Sigh, more half baked Wayland shit.
window->wl.window_fully_created = window->wl.once.surface_configured || scale != 120 || !_glfw.wl.has_preferred_buffer_scale;
apply_scale_changes(window, true, true);
}
@@ -1108,8 +1105,10 @@ create_window_desktop_surface(_GLFWwindow* window)
}
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
if (_glfw.wl.xdg_wm_base_version < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
memset(&window->wl.wm_capabilities, 0xff, sizeof(window->wl.wm_capabilities));
if (_glfw.wl.xdg_wm_base_version < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) {
window->wl.wm_capabilities.maximize = true; window->wl.wm_capabilities.minimize = true; window->wl.wm_capabilities.fullscreen = true;
window->wl.wm_capabilities.window_menu = true;
}
#endif
xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window);
if (_glfw.wl.decorationManager) {

6
go.mod
View File

@@ -12,11 +12,11 @@ require (
github.com/google/uuid v1.6.0
github.com/kovidgoyal/imaging v1.6.3
github.com/seancfoley/ipaddress-go v1.6.0
github.com/shirou/gopsutil/v3 v3.24.4
github.com/shirou/gopsutil/v3 v3.24.5
github.com/zeebo/xxh3 v1.0.2
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b
golang.org/x/image v0.16.0
golang.org/x/sys v0.20.0
golang.org/x/image v0.17.0
golang.org/x/sys v0.21.0
howett.net/plist v1.0.1
)

26
go.sum
View File

@@ -8,7 +8,6 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
@@ -19,7 +18,6 @@ github.com/edwvee/exiffix v0.0.0-20240229113213-0dbb146775be h1:FNPYI8/ifKGW7kdB
github.com/edwvee/exiffix v0.0.0-20240229113213-0dbb146775be/go.mod h1:G3dK5MziX9e4jUa8PWjowCOPCcyQwxsZ5a0oYA73280=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -32,12 +30,10 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kovidgoyal/imaging v1.6.3 h1:iNPpv7ygiaB/NOztc6APMT7yr9UwBS+rOZwIbAdtyY8=
github.com/kovidgoyal/imaging v1.6.3/go.mod h1:sHvcLOOVhJuto2IoNdPLEqnAUoL5ZfHEF0PpNH+882g=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
@@ -46,19 +42,12 @@ github.com/seancfoley/bintree v1.3.1 h1:cqmmQK7Jm4aw8gna0bP+huu5leVOgHGSJBEpUx3E
github.com/seancfoley/bintree v1.3.1/go.mod h1:hIUabL8OFYyFVTQ6azeajbopogQc2l5C/hiXMcemWNU=
github.com/seancfoley/ipaddress-go v1.6.0 h1:9z7yGmOnV4P2ML/dlR/kCJiv5tp8iHOOetJvxJh/R5w=
github.com/seancfoley/ipaddress-go v1.6.0/go.mod h1:TQRZgv+9jdvzHmKoPGBMxyiaVmoI0rYpfEk8Q/sL/Iw=
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
@@ -74,21 +63,18 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI=
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
golang.org/x/image v0.17.0 h1:nTRVVdajgB8zCMZVsViyzhnMKPwYeroEERRC64JuLco=
golang.org/x/image v0.17.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=

View File

@@ -188,7 +188,7 @@ func run_set_loop(opts *Options, args []string) (err error) {
to_process := make([]*Input, len(args))
defer func() {
for _, i := range inputs {
if i.src != nil {
if i != nil && i.src != nil {
rc, ok := i.src.(io.Closer)
if ok {
rc.Close()

View File

@@ -119,7 +119,7 @@ func (self *ErrInvalidSSHArgs) Error() string {
}
func PassthroughArgs() map[string]bool {
return map[string]bool{"-N": true, "-n": true, "-f": true, "-G": true, "-T": true}
return map[string]bool{"-N": true, "-n": true, "-f": true, "-G": true, "-T": true, "-V": true}
}
func ParseSSHArgs(args []string, extra_args ...string) (ssh_args []string, server_args []string, passthrough bool, found_extra_args []string, err error) {

View File

@@ -33,7 +33,7 @@ from typing import (
from weakref import WeakValueDictionary
from .child import cached_process_data, default_env, set_default_env
from .cli import create_opts, parse_args
from .cli import create_opts, green, parse_args
from .cli_stub import CLIOptions
from .clipboard import (
Clipboard,
@@ -733,7 +733,7 @@ class Boss:
For example::
map f1 remote_control_script arg1 arg2 ...
map f1 remote_control_script /path/to/script arg1 arg2 ...
See :ref:`rc_mapping` for details.
''')
@@ -822,6 +822,15 @@ class Boss:
args.directory = os.path.join(data['cwd'], args.directory)
focused_os_window = os_window_id = 0
for session in create_sessions(opts, args, respect_cwd=True):
if not session.has_non_background_processes:
# background only do not create and OS Window
from .launch import LaunchSpec, launch
for tab in session.tabs:
for window in tab.windows:
if window.is_background_process:
assert isinstance(window.launch_spec, LaunchSpec)
launch(get_boss(), window.launch_spec.opts, window.launch_spec.args)
continue
os_window_id = self.add_os_window(
session, wclass=args.cls, wname=args.name, opts_for_size=opts, startup_id=startup_id,
override_title=args.title or None)
@@ -1110,7 +1119,7 @@ class Boss:
'Are you sure you want to close this tab? It is running the {} program and {} other programs.', num)
else:
msg = _('Are you sure you want to close this tab? It is running the {} program')
msg = msg.format(active_program or program or 'shell', num)
msg = msg.format(green(active_program or program or 'shell'), num)
w = self.confirm(msg, self.handle_close_tab_confirmation, tab.id, window=tab.active_window, title=_('Close tab?'))
tab.confirm_close_window_id = w.id
@@ -1752,7 +1761,7 @@ class Boss:
'Are you sure you want to close this OS window? It is running the {} program and {} other programs.', num)
else:
msg = _('Are you sure you want to close this OS window? It is running the {} program')
msg = msg.format(active_program or program or 'shell', num)
msg = msg.format(green(active_program or program or 'shell'), num)
w = self.confirm(msg, self.handle_close_os_window_confirmation, os_window_id, window=tm.active_window, title=_('Close OS window'))
tm.confirm_close_window_id = w.id
@@ -1819,7 +1828,7 @@ class Boss:
'Are you sure you want to quit kitty? It is running the {} program and {} other programs.', num)
else:
msg = _('Are you sure you want to quit kitty? It is running the {} program')
msg = msg.format(active_program or program or 'shell', num)
msg = msg.format(green(active_program or program or 'shell'), num)
w = self.confirm(msg, self.handle_quit_confirmation, window=tm.active_window, title=_('Quit kitty?'))
self.quit_confirmation_window_id = w.id
set_application_quit_request(CLOSE_BEING_CONFIRMED)

View File

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

View File

@@ -21,7 +21,7 @@ from .fast_data_types import Color, SingleKey, num_users, opengl_version_string,
from .options.types import Options as KittyOpts
from .options.types import defaults
from .options.utils import KeyboardMode, KeyDefinition
from .rgb import color_as_sharp
from .rgb import color_as_sharp, color_from_int
from .types import MouseEvent, Shortcut, mod_to_names
AnyEvent = TypeVar('AnyEvent', MouseEvent, Shortcut)
@@ -101,6 +101,15 @@ def compare_opts(opts: KittyOpts, print: Print) -> None:
else:
if f == 'kitty_mod':
print(fmt.format(f), '+'.join(mod_to_names(getattr(opts, f))))
elif f in ('wayland_titlebar_color', 'macos_titlebar_color'):
if val == 0:
cval = 'system'
elif val == 1:
cval = 'background'
else:
col = color_from_int(val >> 8)
cval = color_as_sharp(col) + ' ' + styled(' ', bg=col)
colors.append(fmt.format(f) + ' ' + cval)
else:
print(fmt.format(f), str(getattr(opts, f)))

View File

@@ -11,6 +11,10 @@
#include "glfw-wrapper.h"
#include <structmember.h>
#ifndef __APPLE__
#include <xkbcommon/xkbcommon.h>
#endif
// python KeyEvent object {{{
typedef struct {
PyObject_HEAD
@@ -44,6 +48,19 @@ is_modifier_key(const uint32_t key) {
END_ALLOW_CASE_RANGE
}
static bool
is_no_action_key(const uint32_t key, const uint32_t native_key) {
switch (native_key) {
#ifndef __APPLE__
case XKB_KEY_XF86Fn:
case XKB_KEY_XF86WakeUp:
return true;
#endif
default:
return is_modifier_key(key);
}
}
static void
dealloc(PyKeyEvent* self) {
Py_CLEAR(self->key); Py_CLEAR(self->shifted_key); Py_CLEAR(self->alternate_key);
@@ -163,7 +180,7 @@ on_key_input(GLFWkeyevent *ev) {
}
}
if (!w) { debug("no active window, ignoring\n"); return; }
if (OPT(mouse_hide_wait) < 0 && !is_modifier_key(key)) hide_mouse(global_state.callback_os_window);
if (OPT(mouse_hide_wait) < 0 && !is_no_action_key(key, native_key)) hide_mouse(global_state.callback_os_window);
Screen *screen = w->render_data.screen;
id_type active_window_id = w->id;
@@ -227,7 +244,7 @@ on_key_input(GLFWkeyevent *ev) {
debug("discarding repeat key event as DECARM is off\n");
return;
}
if (screen->scrolled_by && action == GLFW_PRESS && !is_modifier_key(key)) {
if (screen->scrolled_by && action == GLFW_PRESS && !is_no_action_key(key, native_key)) {
screen_history_scroll(screen, SCROLL_FULL, false); // scroll back to bottom
}
char encoded_key[KEY_BUFFER_SIZE] = {0};

View File

@@ -50,6 +50,11 @@ cell_text(CPUCell *cell) {
// URL detection {{{
static bool
is_hostname_char(char_type ch) {
return ch == '[' || ch == ']' || is_url_char(ch);
}
static index_type
find_colon_slash(Line *self, index_type x, index_type limit) {
// Find :// at or before x
@@ -60,7 +65,7 @@ find_colon_slash(Line *self, index_type x, index_type limit) {
if (pos < limit) return 0;
do {
char_type ch = self->cpu_cells[pos].ch;
if (!is_url_char(ch)) return false;
if (!is_hostname_char(ch)) return false;
if (pos == x) {
if (ch == ':') {
if (pos + 2 < self->xnum && self->cpu_cells[pos+1].ch == '/' && self->cpu_cells[pos + 2].ch == '/') state = SECOND_SLASH;
@@ -108,9 +113,15 @@ has_url_prefix_at(Line *self, index_type at, index_type min_prefix_len, index_ty
#define MIN_URL_LEN 5
static bool
has_url_beyond(Line *self, index_type x) {
has_url_beyond_colon_slash(Line *self, index_type x) {
unsigned num_of_slashes = 0;
for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) {
if (!is_url_char(self->cpu_cells[i].ch)) return false;
const char_type ch = self->cpu_cells[i].ch;
if (num_of_slashes < 3) {
if (!is_hostname_char(ch)) return false;
if (ch == '/') num_of_slashes++;
}
else { if (!is_url_char(ch)) return false; }
}
return true;
}
@@ -123,30 +134,40 @@ line_url_start_at(Line *self, index_type x) {
index_type ds_pos = 0, t;
// First look for :// ahead of x
ds_pos = find_colon_slash(self, x + OPT(url_prefixes).max_prefix_len + 3, x < 2 ? 0 : x - 2);
if (ds_pos != 0 && has_url_beyond(self, ds_pos)) {
if (ds_pos != 0 && has_url_beyond_colon_slash(self, ds_pos)) {
if (has_url_prefix_at(self, ds_pos, ds_pos > x ? ds_pos - x: 0, &t)) return t;
}
ds_pos = find_colon_slash(self, x, 0);
if (ds_pos == 0 || self->xnum < ds_pos + MIN_URL_LEN + 3 || !has_url_beyond(self, ds_pos)) return self->xnum;
if (ds_pos == 0 || self->xnum < ds_pos + MIN_URL_LEN + 3 || !has_url_beyond_colon_slash(self, ds_pos)) return self->xnum;
if (has_url_prefix_at(self, ds_pos, 0, &t)) return t;
return self->xnum;
}
static bool
is_pos_ok_for_url(Line *self, index_type x, bool in_hostname, index_type last_hostname_char_pos) {
if (x >= self->xnum) return false;
if (in_hostname && x <= last_hostname_char_pos) return is_hostname_char(self->cpu_cells[x].ch);
return is_url_char(self->cpu_cells[x].ch);
}
index_type
line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel, bool next_line_starts_with_url_chars) {
line_url_end_at(Line *self, index_type x, bool check_short, char_type sentinel, bool next_line_starts_with_url_chars, bool in_hostname, index_type last_hostname_char_pos) {
index_type ans = x;
if (x >= self->xnum || (check_short && self->xnum <= MIN_URL_LEN + 3)) return 0;
if (sentinel) { while (ans < self->xnum && self->cpu_cells[ans].ch != sentinel && is_url_char(self->cpu_cells[ans].ch)) ans++; }
else { while (ans < self->xnum && is_url_char(self->cpu_cells[ans].ch)) ans++; }
#define pos_ok(x) is_pos_ok_for_url(self, x, in_hostname, last_hostname_char_pos)
if (sentinel) { while (ans < self->xnum && self->cpu_cells[ans].ch != sentinel && pos_ok(ans)) ans++; }
else { while (ans < self->xnum && pos_ok(ans)) ans++; }
if (ans) ans--;
if (ans < self->xnum - 1 || !next_line_starts_with_url_chars) {
while (ans > x && can_strip_from_end_of_url(self->cpu_cells[ans].ch)) ans--;
}
#undef pos_ok
return ans;
}
bool
line_startswith_url_chars(Line *self) {
line_startswith_url_chars(Line *self, bool in_hostname) {
if (in_hostname) return is_hostname_char(self->cpu_cells[0].ch);
return is_url_char(self->cpu_cells[0].ch);
}
@@ -163,7 +184,7 @@ url_end_at(Line *self, PyObject *args) {
unsigned int x, sentinel = 0;
int next_line_starts_with_url_chars = 0;
if (!PyArg_ParseTuple(args, "I|Ip", &x, &sentinel, &next_line_starts_with_url_chars)) return NULL;
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, x, true, sentinel, next_line_starts_with_url_chars));
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, x, true, sentinel, next_line_starts_with_url_chars, false, self->xnum));
}
// }}}

View File

@@ -89,8 +89,8 @@ void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, hy
void line_right_shift(Line *, unsigned int , unsigned int );
void line_add_combining_char(CPUCell *, GPUCell *, uint32_t , unsigned int );
index_type line_url_start_at(Line *self, index_type x);
index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool);
bool line_startswith_url_chars(Line*);
index_type line_url_end_at(Line *self, index_type x, bool, char_type, bool, bool, index_type);
bool line_startswith_url_chars(Line*, bool);
bool line_as_ansi(Line *self, ANSIBuf *output, const GPUCell**, index_type start_at, index_type stop_before, char_type prefix_char) __attribute__((nonnull));
unsigned int line_length(Line *self);
size_t cell_as_unicode(CPUCell *cell, bool include_cc, Py_UCS4 *buf, char_type);

View File

@@ -296,7 +296,7 @@ opt('cursor', '#cccccc',
option_type='to_color_or_none',
long_text='''
Default cursor color. If set to the special value :code:`none` the cursor will
be rendered with a "reverse video" effect. It's color will be the color of the
be rendered with a "reverse video" effect. Its color will be the color of the
text in the cell it is over and the text will be rendered with the background
color of the cell. Note that if the program running in the terminal sets a
cursor color, this takes precedence. Also, the cursor colors are modified if
@@ -330,6 +330,12 @@ cursor shape to :code:`beam` at shell prompts. You can avoid this by setting
'''
)
opt('cursor_shape_unfocused', 'hollow', option_type='to_cursor_unfocused_shape', ctype='int', long_text='''
Defines the text cursor shape when the OS window is not focused. The unfocused
cursor shape can be one of :code:`block`, :code:`beam`, :code:`underline`,
:code:`hollow`.
''')
opt('cursor_beam_thickness', '1.5',
option_type='positive_float', ctype='float',
long_text='The thickness of the beam cursor (in pts).'
@@ -356,6 +362,7 @@ Stop blinking cursor after the specified number of seconds of keyboard
inactivity. Set to zero to never stop blinking.
'''
)
egr() # }}}
@@ -1160,6 +1167,17 @@ faded and one being fully opaque.
'''
)
opt('window_logo_scale', '0', option_type='window_logo_scale', ctype='!window_logo_scale', long_text='''
The percentage (0-100] of the window size to which the logo should scale. Using a single
number means the logo is scaled to that percentage of the shortest window dimension, while preseving
aspect ratio of the logo image.
Using two numbers means the width and height of the logo are scaled to the respective
percentage of the window's width and height.
Using zero as the percentage disables scaling in that dimension. A single zero (the default)
disables all scaling of the window logo.
''')
opt('resize_debounce_time', '0.1 0.5',
option_type='resize_debounce_time', ctype='!resize_debounce_time',
@@ -2902,9 +2920,9 @@ doesn't work, kitty will cycle through various known editors (:program:`vim`,
opt('close_on_child_death', 'no',
option_type='to_bool', ctype='bool',
long_text='''
Close the window when the child process (shell) exits. With the default value
Close the window when the child process (usually the shell) exits. With the default value
:code:`no`, the terminal will remain open when the child exits as long as there
are still processes outputting to the terminal (for example disowned or
are still other processes outputting to the terminal (for example disowned or
backgrounded processes). When enabled with :code:`yes`, the window will close as
soon as the child process exits. Note that setting it to :code:`yes` means that
any background processes still using the terminal can fail silently because

13
kitty/options/parse.py generated
View File

@@ -17,8 +17,9 @@ from kitty.options.utils import (
remote_control_password, resize_debounce_time, scrollback_lines, scrollback_pager_history_size,
shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge,
tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator,
tab_title_template, titlebar_color, to_cursor_shape, to_font_size, to_layout_names, to_modifiers,
url_prefixes, url_style, visual_window_select_characters, window_border_width, window_size
tab_title_template, titlebar_color, to_cursor_shape, to_cursor_unfocused_shape, to_font_size,
to_layout_names, to_modifiers, url_prefixes, url_style, visual_window_select_characters,
window_border_width, window_logo_scale, window_size
)
@@ -919,6 +920,9 @@ class Parser:
def cursor_shape(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['cursor_shape'] = to_cursor_shape(val)
def cursor_shape_unfocused(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['cursor_shape_unfocused'] = to_cursor_unfocused_shape(val)
def cursor_stop_blinking_after(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['cursor_stop_blinking_after'] = positive_float(val)
@@ -1388,7 +1392,10 @@ class Parser:
raise ValueError(f"The value {val} is not a valid choice for window_logo_position")
ans["window_logo_position"] = val
choices_for_window_logo_position = frozenset(('top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'))
choices_for_window_logo_position = choices_for_placement_strategy
def window_logo_scale(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['window_logo_scale'] = window_logo_scale(val)
def window_margin_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['window_margin_width'] = edge_width(val)

View File

@@ -83,6 +83,19 @@ convert_from_opts_cursor_shape(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_cursor_shape_unfocused(PyObject *val, Options *opts) {
opts->cursor_shape_unfocused = PyLong_AsLong(val);
}
static void
convert_from_opts_cursor_shape_unfocused(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "cursor_shape_unfocused");
if (ret == NULL) return;
convert_from_python_cursor_shape_unfocused(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_cursor_beam_thickness(PyObject *val, Options *opts) {
opts->cursor_beam_thickness = PyFloat_AsFloat(val);
@@ -616,6 +629,19 @@ convert_from_opts_window_logo_alpha(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_window_logo_scale(PyObject *val, Options *opts) {
window_logo_scale(val, opts);
}
static void
convert_from_opts_window_logo_scale(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "window_logo_scale");
if (ret == NULL) return;
convert_from_python_window_logo_scale(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_resize_debounce_time(PyObject *val, Options *opts) {
resize_debounce_time(val, opts);
@@ -1150,6 +1176,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_shape(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_shape_unfocused(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_beam_thickness(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_underline_thickness(py_opts, opts);
@@ -1232,6 +1260,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_window_logo_alpha(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_window_logo_scale(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_resize_debounce_time(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_resize_in_steps(py_opts, opts);

View File

@@ -338,6 +338,12 @@ tab_bar_margin_height(PyObject *val, Options *opts) {
opts->tab_bar_margin_height.inner = PyFloat_AsDouble(PyTuple_GET_ITEM(val, 1));
}
static void
window_logo_scale(PyObject *src, Options *opts) {
opts->window_logo_scale.width = PyFloat_AsFloat(PyTuple_GET_ITEM(src, 0));
opts->window_logo_scale.height = PyFloat_AsFloat(PyTuple_GET_ITEM(src, 1));
}
static void
resize_debounce_time(PyObject *src, Options *opts) {
opts->resize_debounce_time.on_end = s_double_to_monotonic_t(PyFloat_AsDouble(PyTuple_GET_ITEM(src, 0)));

View File

@@ -34,7 +34,7 @@ choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'ri
choices_for_terminfo_type = typing.Literal['path', 'direct', 'none']
choices_for_undercurl_style = typing.Literal['thin-sparse', 'thin-dense', 'thick-sparse', 'thick-dense']
choices_for_underline_hyperlinks = typing.Literal['hover', 'always', 'never']
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 = choices_for_placement_strategy
option_names = ( # {{{
'action_alias',
@@ -330,6 +330,7 @@ option_names = ( # {{{
'cursor_beam_thickness',
'cursor_blink_interval',
'cursor_shape',
'cursor_shape_unfocused',
'cursor_stop_blinking_after',
'cursor_text_color',
'cursor_underline_thickness',
@@ -459,6 +460,7 @@ option_names = ( # {{{
'window_logo_alpha',
'window_logo_path',
'window_logo_position',
'window_logo_scale',
'window_margin_width',
'window_padding_width',
'window_resize_step_cells',
@@ -502,6 +504,7 @@ class Options:
cursor_beam_thickness: float = 1.5
cursor_blink_interval: float = -1.0
cursor_shape: int = 1
cursor_shape_unfocused: int = 0
cursor_stop_blinking_after: float = 15.0
cursor_text_color: typing.Optional[kitty.fast_data_types.Color] = Color(17, 17, 17)
cursor_underline_thickness: float = 2.0
@@ -619,6 +622,7 @@ class Options:
window_logo_alpha: float = 0.5
window_logo_path: typing.Optional[str] = None
window_logo_position: choices_for_window_logo_position = 'bottom-right'
window_logo_scale: typing.Tuple[float, float] = (0, -1.0)
window_margin_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0)
window_padding_width: FloatEdges = FloatEdges(left=0, top=0, right=0, bottom=0)
window_resize_step_cells: int = 2

View File

@@ -44,7 +44,7 @@ from kitty.conf.utils import (
unit_float,
)
from kitty.constants import is_macos
from kitty.fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, Color, Shlex, SingleKey
from kitty.fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE, NO_CURSOR_SHAPE, Color, Shlex, SingleKey
from kitty.fonts import FontFeature, FontModification, ModificationType, ModificationUnit, ModificationValue
from kitty.key_names import character_key_name_aliases, functional_key_name_aliases, get_key_name_lookup
from kitty.rgb import color_as_int
@@ -524,6 +524,12 @@ cshapes = {
'beam': CURSOR_BEAM,
'underline': CURSOR_UNDERLINE
}
cshapes_unfocused = {
'block': CURSOR_BLOCK,
'beam': CURSOR_BEAM,
'underline': CURSOR_UNDERLINE,
'hollow': NO_CURSOR_SHAPE
}
def to_cursor_shape(x: str) -> int:
@@ -537,6 +543,17 @@ def to_cursor_shape(x: str) -> int:
)
def to_cursor_unfocused_shape(x: str) -> int:
try:
return cshapes_unfocused[x.lower()]
except KeyError:
raise ValueError(
'Invalid unfocused cursor shape: {} allowed values are {}'.format(
x, ', '.join(cshapes_unfocused)
)
)
def scrollback_lines(x: str) -> int:
ans = int(x)
if ans < 0:
@@ -646,6 +663,13 @@ def resize_draw_strategy(x: str) -> int:
return cmap.get(x.lower(), 0)
def window_logo_scale(x: str) -> Tuple[float, float]:
parts = x.split(maxsplit=1)
if len(parts) == 1:
return positive_float(parts[0]), -1.0
return positive_float(parts[0]), positive_float(parts[1])
def resize_debounce_time(x: str) -> Tuple[float, float]:
parts = x.split(maxsplit=1)
if len(parts) == 1:
@@ -770,7 +794,7 @@ def remote_control_password(val: str, current_val: Dict[str, str]) -> Iterable[T
# line of remote_control_password
raise ValueError('Passwords are not allowed to start with hyphens, ignoring this password')
if len(parts) == 1:
yield parts[0], tuple()
yield "", (parts[0],)
else:
yield parts[0], tuple(parts[1:])

View File

@@ -276,7 +276,8 @@ they will only work if this process is run within a kitty window.
--password
A password to use when contacting kitty. This will cause kitty to ask the user
for permission to perform the specified action, unless the password has been
accepted before or is pre-configured in :file:`kitty.conf`.
accepted before or is pre-configured in :file:`kitty.conf`. To use a blank password
specify :option:`kitten @ --use-password` as :code:`always`.
--password-file
@@ -300,7 +301,7 @@ default=if-available
choices=if-available,never,always
If no password is available, kitty will usually just send the remote control command
without a password. This option can be used to force it to :code:`always` or :code:`never` use
the supplied password.
the supplied password. If set to always and no password is provided, the blank password is used.
'''.format, appname=appname)

View File

@@ -3189,25 +3189,35 @@ screen_open_url(Screen *self) {
// URLs {{{
static void
extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type sentinel, bool newlines_allowed) {
extend_url(Screen *screen, Line *line, index_type *x, index_type *y, char_type sentinel, bool newlines_allowed, index_type last_hostname_char_pos) {
unsigned int count = 0;
bool has_newline = false;
index_type orig_y = *y;
while(count++ < 10) {
bool in_hostname = last_hostname_char_pos >= line->xnum;
has_newline = !line->gpu_cells[line->xnum-1].attrs.next_char_was_wrapped;
if (*x != line->xnum - 1 || (!newlines_allowed && has_newline)) break;
bool next_line_starts_with_url_chars = false;
line = screen_visual_line(screen, *y + 2);
if (line) {
next_line_starts_with_url_chars = line_startswith_url_chars(line);
next_line_starts_with_url_chars = line_startswith_url_chars(line, in_hostname);
has_newline = !line->attrs.is_continued;
if (next_line_starts_with_url_chars && has_newline && !newlines_allowed) next_line_starts_with_url_chars = false;
if (sentinel && next_line_starts_with_url_chars && line->cpu_cells[0].ch == sentinel) next_line_starts_with_url_chars = false;
}
line = screen_visual_line(screen, *y + 1);
if (!line) break;
index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars);
if (!new_x && !line_startswith_url_chars(line)) break;
if (in_hostname) {
for (last_hostname_char_pos = 0; last_hostname_char_pos < line->xnum; last_hostname_char_pos++) {
if (line->cpu_cells[last_hostname_char_pos].ch == '/') {
if (last_hostname_char_pos > 0) last_hostname_char_pos--;
else { in_hostname = false; last_hostname_char_pos = line->xnum; }
break;
}
}
}
index_type new_x = line_url_end_at(line, 0, false, sentinel, next_line_starts_with_url_chars, in_hostname, last_hostname_char_pos);
if (!new_x && !line_startswith_url_chars(line, in_hostname)) break;
*y += 1; *x = new_x;
}
if (sentinel && *x == 0 && *y > orig_y) {
@@ -3254,24 +3264,30 @@ screen_detect_url(Screen *screen, unsigned int x, unsigned int y) {
}
char_type sentinel = 0;
bool newlines_allowed = !is_excluded_from_url('\n');
index_type last_hostname_char_pos = screen->columns;
if (line) {
url_start = line_url_start_at(line, x);
if (url_start < line->xnum) {
bool next_line_starts_with_url_chars = false;
if (y < screen->lines - 1) {
line = screen_visual_line(screen, y+1);
next_line_starts_with_url_chars = line_startswith_url_chars(line);
next_line_starts_with_url_chars = line_startswith_url_chars(line, last_hostname_char_pos >= line->xnum);
if (next_line_starts_with_url_chars && !newlines_allowed && !line->attrs.is_continued) next_line_starts_with_url_chars = false;
line = screen_visual_line(screen, y);
}
sentinel = get_url_sentinel(line, url_start);
url_end = line_url_end_at(line, x, true, sentinel, next_line_starts_with_url_chars);
index_type slash_count = 0;
for (index_type i = url_start; i < line->xnum; i++) {
const char_type ch = line->cpu_cells[i].ch;
if (ch == '/' && ++slash_count > 2) { last_hostname_char_pos = i - 1; break; }
}
url_end = line_url_end_at(line, x, true, sentinel, next_line_starts_with_url_chars, x <= last_hostname_char_pos, last_hostname_char_pos);
}
has_url = url_end > url_start;
}
if (has_url) {
index_type y_extended = y;
extend_url(screen, line, &url_end, &y_extended, sentinel, newlines_allowed);
extend_url(screen, line, &url_end, &y_extended, sentinel, newlines_allowed, last_hostname_char_pos);
screen_mark_url(screen, url_start, y, url_end, y_extended);
} else {
screen_mark_url(screen, 0, 0, 0, 0);

View File

@@ -39,6 +39,11 @@ class WindowSpec:
def __init__(self, launch_spec: Union['LaunchSpec', 'SpecialWindowInstance']):
self.launch_spec = launch_spec
self.resize_spec: Optional[ResizeSpec] = None
self.is_background_process = False
if hasattr(launch_spec, 'opts'): # LaunchSpec
from .launch import LaunchSpec
assert isinstance(launch_spec, LaunchSpec)
self.is_background_process = launch_spec.opts.type == 'background'
class Tab:
@@ -53,6 +58,13 @@ class Tab:
self.cwd: Optional[str] = None
self.next_title: Optional[str] = None
@property
def has_non_background_processes(self) -> bool:
for w in self.windows:
if not w.is_background_process:
return True
return False
class Session:
@@ -65,6 +77,13 @@ class Session:
self.os_window_state: Optional[str] = None
self.focus_os_window: bool = False
@property
def has_non_background_processes(self) -> bool:
for t in self.tabs:
if t.has_non_background_processes:
return True
return False
def add_tab(self, opts: Options, name: str = '') -> None:
if self.tabs and not self.tabs[-1].windows:
del self.tabs[-1]

View File

@@ -333,7 +333,18 @@ cell_update_uniform_block(ssize_t vao_idx, Screen *screen, int uniform_buffer, c
case CURSOR_UNDERLINE:
rd->cursor_fg_sprite_idx = UNDERLINE_IDX; break;
}
} else rd->cursor_fg_sprite_idx = UNFOCUSED_IDX;
} else {
switch(OPT(cursor_shape_unfocused)) {
default:
rd->cursor_fg_sprite_idx = UNFOCUSED_IDX; break;
case CURSOR_BEAM:
rd->cursor_fg_sprite_idx = BEAM_IDX; break;
case CURSOR_UNDERLINE:
rd->cursor_fg_sprite_idx = UNDERLINE_IDX; break;
case CURSOR_BLOCK:
rd->cursor_fg_sprite_idx = BLOCK_IDX; break;
}
}
color_type cell_fg = rd->default_fg, cell_bg = rd->default_bg;
index_type cell_color_x = cursor->x;
bool reversed = false;
@@ -601,7 +612,7 @@ draw_scroll_indicator(bool premult, Screen *screen, const CellRenderData *crd) {
if (premult) { BLEND_PREMULT } else { BLEND_ONTO_OPAQUE }
bind_program(TINT_PROGRAM);
const color_type bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
GLfloat alpha = 0.8f;
GLfloat alpha = OPT(scrollback_indicator_opacity);
float frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
const GLfloat bar_height = crd->gl.dy;
GLfloat bottom = (crd->gl.ystart - crd->gl.height);
@@ -732,6 +743,41 @@ draw_window_logo(ssize_t vao_idx, OSWindow *os_window, const WindowLogoRenderDat
BLEND_PREMULT;
GLfloat logo_width_gl = gl_size(wl->instance->width, os_window->viewport_width);
GLfloat logo_height_gl = gl_size(wl->instance->height, os_window->viewport_height);
if (OPT(window_logo_scale.width) > 0 || OPT(window_logo_scale.height) > 0) {
unsigned int scaled_wl_width = os_window->viewport_width;
unsigned int scaled_wl_height = os_window->viewport_height;
// [sx] Scales logo to sx % of the viewports shortest dimension, preserving aspect ratio
if (OPT(window_logo_scale.height) < 0) {
if (os_window->viewport_height < os_window->viewport_width) {
scaled_wl_height = (int)(os_window->viewport_height * OPT(window_logo_scale.width) / 100);
scaled_wl_width = wl->instance->width * scaled_wl_height / wl->instance->height;
} else {
scaled_wl_width = (int)(os_window->viewport_width * OPT(window_logo_scale.width) / 100);
scaled_wl_height = wl->instance->height * scaled_wl_width / wl->instance->width;
}
}
// [0 sy] Scales logo's y dimension to sy % of viewporty keeping original x dimension
else if (OPT(window_logo_scale.width) == 0.0) {
scaled_wl_height = (int)(scaled_wl_height * OPT(window_logo_scale.height) / 100);
scaled_wl_width = wl->instance->width;
}
// [sx 0] Scales logo's x dimension to sx % of viewportx keeping original y dimension
else if (OPT(window_logo_scale.height) == 0.0) {
scaled_wl_width = (int)(scaled_wl_width * OPT(window_logo_scale.width) / 100);
scaled_wl_height = wl->instance->height;
}
// [sx sy] Scales logo's x and y dimension to sx and sy % of viewportx and viewporty respectively
else {
scaled_wl_height = (int)(scaled_wl_height * OPT(window_logo_scale.height) / 100);
scaled_wl_width = (int)(scaled_wl_width * OPT(window_logo_scale.width) / 100);
}
logo_height_gl = gl_size(scaled_wl_height, os_window->viewport_height);
logo_width_gl = gl_size(scaled_wl_width, os_window->viewport_width);
}
GLfloat logo_left_gl = clamp_position_to_nearest_pixel(
crd->gl.xstart + crd->gl.width * wl->position.canvas_x - logo_width_gl * wl->position.image_x, os_window->viewport_width);
GLfloat logo_top_gl = clamp_position_to_nearest_pixel(

View File

@@ -38,7 +38,7 @@ typedef struct {
double wheel_scroll_multiplier, touch_scroll_multiplier;
int wheel_scroll_min_lines;
bool enable_audio_bell;
CursorShape cursor_shape;
CursorShape cursor_shape, cursor_shape_unfocused;
float cursor_beam_thickness;
float cursor_underline_thickness;
unsigned int url_style;
@@ -65,6 +65,7 @@ typedef struct {
ImageAnchorPosition window_logo_position;
bool background_image_linear;
float background_tint, background_tint_gaps, window_logo_alpha;
struct { float width, height; } window_logo_scale;
bool dynamic_background_opacity;
float inactive_text_alpha;

View File

@@ -221,7 +221,8 @@ class Tab: # {{{
if window.resize_spec is not None:
self.resize_window(*window.resize_spec)
self.windows.set_active_window_group_for(self.windows.all_windows[session_tab.active_window_idx])
with suppress(IndexError):
self.windows.set_active_window_group_for(self.windows.all_windows[session_tab.active_window_idx])
def serialize_state(self) -> Dict[str, Any]:
return {

View File

@@ -1028,12 +1028,12 @@ class TestScreen(BaseTest):
url = ''.join(s.text_for_marked_url())
self.assertEqual(expected, url)
def t(url, x=0, y=0, before='', after=''):
def t(url, x=0, y=0, before='', after='', expected=''):
s.reset()
s.cursor.x = x
s.cursor.y = y
s.draw(before + url + after)
ae(url, x=x + 1 + len(before), y=y)
ae(expected or url, x=x + 1 + len(before), y=y)
t('http://moo.com')
@@ -1043,10 +1043,15 @@ class TestScreen(BaseTest):
t('http://moo.com', before=st, after=e)
for trailer in ')-=':
t('http://moo.com' + trailer)
for trailer in '{([]}<>':
for trailer in '{}([<>':
t('http://moo.com', after=trailer)
t('http://moo.com', x=s.columns - 9)
t('https://wraps-by-one-char.com', before='[', after=']')
t('http://[::1]:8080')
t('https://wr[aps-by-one-ch]ar.com')
t('http://[::1]:8080/x', after='[')
t('http://[::1]:8080/x]y34', expected='http://[::1]:8080/x')
t('https://wraps-by-one-char.com[]/x', after='[')
def test_prompt_marking(self):
s = self.create_screen()

View File

@@ -211,7 +211,10 @@ def get_data():
sys.stdout.write('\r\033[K')
data = base64.standard_b64decode(data)
with temporary_directory(dir=HOME, prefix='.kitty-ssh-kitten-untar-') as tdir, tarfile.open(fileobj=io.BytesIO(data)) as tf:
tf.extractall(tdir)
try:
tf.extractall(tdir, filter='data')
except TypeError:
tf.extractall(tdir)
with open(tdir + '/data.sh') as f:
env_vars = f.read()
apply_env_vars(env_vars)

View File

@@ -45,6 +45,7 @@ in
openssl
xxHash
dbus
simde
]
++ checkInputs;

View File

@@ -32,10 +32,16 @@ const lowerhex = "0123456789abcdef"
var ProtocolVersion [3]int = [3]int{0, 26, 0}
type password struct {
val string
is_set bool
}
type GlobalOptions struct {
to_network, to_address, password string
to_address_is_from_env_var bool
already_setup bool
to_network, to_address string
password password
to_address_is_from_env_var bool
already_setup bool
}
var global_options GlobalOptions
@@ -135,15 +141,15 @@ func simple_serializer(rc *utils.RemoteControlCmd) (ans []byte, err error) {
type serializer_func func(rc *utils.RemoteControlCmd) ([]byte, error)
func create_serializer(password string, encoded_pubkey string, io_data *rc_io_data) (err error) {
func create_serializer(password password, encoded_pubkey string, io_data *rc_io_data) (err error) {
io_data.serializer = simple_serializer
if password != "" {
if password.is_set {
encryption_version, pubkey, err := get_pubkey(encoded_pubkey)
if err != nil {
return err
}
io_data.serializer = func(rc *utils.RemoteControlCmd) (ans []byte, err error) {
ec, err := crypto.Encrypt_cmd(rc, global_options.password, pubkey, encryption_version)
ec, err := crypto.Encrypt_cmd(rc, global_options.password.val, pubkey, encryption_version)
if err != nil {
return
}
@@ -293,25 +299,26 @@ func send_rc_command(io_data *rc_io_data) (err error) {
return
}
func get_password(password string, password_file string, password_env string, use_password string) (ans string, err error) {
func get_password(password string, password_file string, password_env string, use_password string) (ans password, err error) {
if use_password == "never" {
return
}
if password != "" {
ans = password
ans.is_set, ans.val = true, password
}
if ans == "" && password_file != "" {
if !ans.is_set && password_file != "" {
if password_file == "-" {
if tty.IsTerminal(os.Stdin.Fd()) {
ans, err = tui.ReadPassword("Password: ", true)
p, err := tui.ReadPassword("Password: ", true)
if err != nil {
return
return ans, err
}
ans.is_set, ans.val = true, p
} else {
var q []byte
q, err = io.ReadAll(os.Stdin)
if err == nil {
ans = strings.TrimRight(string(q), " \n\t")
ans.is_set, ans.val = true, strings.TrimRight(string(q), " \n\t")
}
ttyf, err := os.Open(tty.Ctermid())
if err == nil {
@@ -323,7 +330,7 @@ func get_password(password string, password_file string, password_env string, us
var q []byte
q, err = os.ReadFile(password_file)
if err == nil {
ans = strings.TrimRight(string(q), " \n\t")
ans.is_set, ans.val = true, strings.TrimRight(string(q), " \n\t")
} else {
if errors.Is(err, os.ErrNotExist) {
err = nil
@@ -334,13 +341,14 @@ func get_password(password string, password_file string, password_env string, us
return
}
}
if ans == "" && password_env != "" {
ans = os.Getenv(password_env)
if !ans.is_set && password_env != "" {
ans.val, ans.is_set = os.LookupEnv(password_env)
}
if ans == "" && use_password == "always" {
return ans, fmt.Errorf("No password was found")
if !ans.is_set && use_password == "always" {
ans.is_set = true
return ans, nil
}
if len(ans) > 1024 {
if len(ans.val) > 1024 {
return ans, fmt.Errorf("Specified password is too long")
}
return ans, nil

View File

@@ -58,7 +58,7 @@ func TestCommandToJSON(t *testing.T) {
func TestRCSerialization(t *testing.T) {
io_data := rc_io_data{}
err := create_serializer("", "", &io_data)
err := create_serializer(password{"", false}, "", &io_data)
if err != nil {
t.Fatal(err)
}
@@ -85,7 +85,7 @@ func TestRCSerialization(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = create_serializer("tpw", pubkey, &io_data)
err = create_serializer(password{"tpw", true}, pubkey, &io_data)
if err != nil {
t.Fatal(err)
}