Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d32202b3a | ||
|
|
4f4d562670 | ||
|
|
28fc9c69da | ||
|
|
6edf00e699 | ||
|
|
a0d6445dda | ||
|
|
e74797037c | ||
|
|
3fb125dba7 | ||
|
|
3c8640f9ad | ||
|
|
2e63a4c83f | ||
|
|
9da5bee178 | ||
|
|
2fc6f3b542 | ||
|
|
4754f42e51 | ||
|
|
941fe918fb | ||
|
|
f4e82e972e | ||
|
|
f66dbf111d | ||
|
|
1a2da5c49d | ||
|
|
8327dabb29 | ||
|
|
195ea6c140 | ||
|
|
fcc0707174 | ||
|
|
aa9c3cd634 | ||
|
|
b541341681 | ||
|
|
e5d50aca6d | ||
|
|
b738f4d4ff | ||
|
|
5c38aabf0e | ||
|
|
03e9ed6947 | ||
|
|
63493fad22 | ||
|
|
696b857f91 | ||
|
|
53ae2bbe0d | ||
|
|
01069e919d | ||
|
|
fc0095f505 | ||
|
|
421528e130 | ||
|
|
7b70356515 | ||
|
|
e803505aad | ||
|
|
ad1ff455a0 | ||
|
|
7692cb5c3d | ||
|
|
a94e208db3 | ||
|
|
ba9d5cf3ff | ||
|
|
0dff0d03f9 | ||
|
|
c92aca5d19 | ||
|
|
5762baeed7 | ||
|
|
601cf01222 | ||
|
|
0eef48b516 | ||
|
|
3c1954f329 | ||
|
|
cc29640604 | ||
|
|
d0329460b8 | ||
|
|
717c0c96de | ||
|
|
b3f161efce | ||
|
|
0286940163 | ||
|
|
d4a4ee386f | ||
|
|
33498f9133 | ||
|
|
da3d4d1bef | ||
|
|
c69b8870d2 | ||
|
|
85b55b31b6 | ||
|
|
948919e42b | ||
|
|
85c40090ed | ||
|
|
98b50ec145 | ||
|
|
1ab4f7d2d0 | ||
|
|
98801b6fa6 | ||
|
|
bdd68284b5 | ||
|
|
a61d70ea9a | ||
|
|
e271719dd2 | ||
|
|
a08efa1fc5 | ||
|
|
ffac3600e0 | ||
|
|
6499f8ac24 | ||
|
|
63307cb1d8 | ||
|
|
0a6fb362f6 | ||
|
|
457fcbfb90 | ||
|
|
3b6277b9e2 | ||
|
|
e6e61028b1 | ||
|
|
e9be66126b | ||
|
|
681fe7f2f2 | ||
|
|
0196920533 | ||
|
|
5f5bb3ace0 | ||
|
|
3c970e0122 | ||
|
|
43af6e3b8a | ||
|
|
ac8cfc12fb | ||
|
|
b19472e0f5 | ||
|
|
b4d08044a0 | ||
|
|
b2fe02e63f | ||
|
|
d1a5d30233 | ||
|
|
bba30138e1 | ||
|
|
082546a1e7 | ||
|
|
41ffd58e26 | ||
|
|
b4f24e4e1e | ||
|
|
75c8ffd715 | ||
|
|
688606ff7c | ||
|
|
2e3f9dffa7 | ||
|
|
859033415b | ||
|
|
1f1b52b580 | ||
|
|
4e7bf80447 | ||
|
|
e39df50884 | ||
|
|
8d6a9d45c2 | ||
|
|
0862e85577 | ||
|
|
0b9a37139e | ||
|
|
6357f7b811 | ||
|
|
24197dc422 | ||
|
|
9bc2ab3245 | ||
|
|
bf4e8c490c | ||
|
|
590a4d70ee | ||
|
|
40341d2ddd | ||
|
|
0cd2c41ee3 | ||
|
|
5d65cdb6a8 | ||
|
|
759a15ccbb | ||
|
|
5aead5eebe | ||
|
|
a325a5fdee | ||
|
|
931e91f1a7 | ||
|
|
6e13509720 | ||
|
|
5b4844e71e | ||
|
|
66cbbea9bb |
@@ -4,6 +4,88 @@ Changelog
|
|||||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||||
|
|
||||||
|
|
||||||
|
0.17.4 [2020-05-09]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Allow showing the name of the current layout and the number of windows
|
||||||
|
in tab titles (:iss:`2634`)
|
||||||
|
|
||||||
|
- macOS: Fix a regression in the previous release that caused ligatures to be
|
||||||
|
not be centered horizontally (:iss:`2591`)
|
||||||
|
|
||||||
|
- By default, double clicking no longer considers the : as part of words, see
|
||||||
|
:opt:`select_by_word_characters` (:iss:`2602`)
|
||||||
|
|
||||||
|
- Fix a regression that caused clicking in the padding/margins of windows in
|
||||||
|
the stack layout to switch the window to the first window (:iss:`2604`)
|
||||||
|
|
||||||
|
- macOS: Fix a regression that broke drag and drop (:iss:`2605`)
|
||||||
|
|
||||||
|
- Report modifier key state when sending wheel events to the terminal program
|
||||||
|
|
||||||
|
- Fix kitty @ send-text not working with text larger than 1024 bytes when using
|
||||||
|
:option:`kitty --listen-on` (:iss:`2607`)
|
||||||
|
|
||||||
|
- Wayland: Fix OS window title not updating for hidden windows (:iss:`2629`)
|
||||||
|
|
||||||
|
- Fix :opt:`background_tint` making the window semi-transparent (:iss:`2618`)
|
||||||
|
|
||||||
|
|
||||||
|
0.17.3 [2020-04-23]
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
- Allow individually setting margins and padding for each edge (left, right,
|
||||||
|
top, bottom). Margins can also be controlled per window via remote control
|
||||||
|
(:iss:`2546`)
|
||||||
|
|
||||||
|
- Fix reverse video not being rendered correctly when using transparency or a
|
||||||
|
background image (:iss:`2419`)
|
||||||
|
|
||||||
|
- Allow mapping arbitrary remote control commands to key presses in
|
||||||
|
:file:`kitty.conf`
|
||||||
|
|
||||||
|
- X11: Fix crash when doing drag and drop from some applications (:iss:`2505`)
|
||||||
|
|
||||||
|
- Fix :option:`launch --stdin-add-formatting` not working (:iss:`2512`)
|
||||||
|
|
||||||
|
- Update to Unicode 13.0 (:iss:`2513`)
|
||||||
|
|
||||||
|
- Render country flags designated by a pair of unicode codepoints
|
||||||
|
in two cells instead of four.
|
||||||
|
|
||||||
|
- diff kitten: New option to control the background color for filler lines in
|
||||||
|
the margin (:iss:`2518`)
|
||||||
|
|
||||||
|
- Fix specifying options for layouts in the startup session file not working
|
||||||
|
(:iss:`2520`)
|
||||||
|
|
||||||
|
- macOS: Fix incorrect horizontal positioning of some full-width East Asian characters
|
||||||
|
(:iss:`1457`)
|
||||||
|
|
||||||
|
- macOS: Render multi-cell PUA characters centered, matching behavior on other
|
||||||
|
platforms
|
||||||
|
|
||||||
|
- Linux: Ignore keys if they are designated as layout/group/mode switch keys
|
||||||
|
(:iss:`2519`)
|
||||||
|
|
||||||
|
- Marks: Fix marks not handling wide characters and tab characters correctly
|
||||||
|
(:iss:`2534`)
|
||||||
|
|
||||||
|
- Add a new :opt:`listen_on` option in kitty.conf to set :option:`kitty --listen-on`
|
||||||
|
globally. Also allow using environment variables in this option (:iss:`2569`).
|
||||||
|
|
||||||
|
- Allow sending mouse events in kittens (:pull:`2538`)
|
||||||
|
|
||||||
|
- icat kitten: Fix display of 16-bit depth images (:iss:`2542`)
|
||||||
|
|
||||||
|
- Add ncurses specific terminfo definitions for strikethrough (:pull:`2567`)
|
||||||
|
|
||||||
|
- Fix a regression in 0.17 that broke displaying graphics over SSH
|
||||||
|
(:iss:`2568`)
|
||||||
|
|
||||||
|
- Fix :option:`--title` not being applied at window creation time (:iss:`2570`)
|
||||||
|
|
||||||
0.17.2 [2020-03-29]
|
0.17.2 [2020-03-29]
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ following :file:`~/.config/fontconfig/fonts.conf`::
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||||
<fontconfig>
|
<fontconfig>
|
||||||
<match target="scan">
|
<match target="font">
|
||||||
<test name="family">
|
<test name="family">
|
||||||
<string>Your Font Family Name</string>
|
<string>Your Font Family Name</string>
|
||||||
</test>
|
</test>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ You can also use your favorite package manager to install the |kitty| package.
|
|||||||
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
`openSUSE <https://build.opensuse.org/package/show/X11:terminals/kitty>`_,
|
||||||
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
`Arch Linux <https://www.archlinux.org/packages/community/x86_64/kitty/>`_,
|
||||||
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
`Gentoo <https://packages.gentoo.org/packages/x11-terms/kitty>`_,
|
||||||
`Fedora <https://copr.fedorainfracloud.org/coprs/gagbo/kitty-latest/>`_,
|
`Fedora <https://src.fedoraproject.org/rpms/kitty>`_,
|
||||||
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
`Void Linux <https://github.com/void-linux/void-packages/blob/master/srcpkgs/kitty/template>`_,
|
||||||
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
and `Solus <https://dev.getsol.us/source/kitty/>`_.
|
||||||
|
|
||||||
|
|||||||
@@ -20,24 +20,24 @@ your machine).
|
|||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
def main(args: List[str]) -> str:
|
def main(args: List[str]) -> str:
|
||||||
# this is the main entry point of the kitten, it will be executed in
|
# this is the main entry point of the kitten, it will be executed in
|
||||||
# the overlay window when the kitten is launched
|
# the overlay window when the kitten is launched
|
||||||
answer = input('Enter some text: ')
|
answer = input('Enter some text: ')
|
||||||
# whatever this function returns will be available in the
|
# whatever this function returns will be available in the
|
||||||
# handle_result() function
|
# handle_result() function
|
||||||
return answer
|
return answer
|
||||||
|
|
||||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
|
def handle_result(args: List[str], answer: str, target_window_id: int, boss: kitty.boss.Boss) -> None:
|
||||||
# get the kitty window into which to paste answer
|
# get the kitty window into which to paste answer
|
||||||
w = boss.window_id_map.get(target_window_id)
|
w = boss.window_id_map.get(target_window_id)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
w.paste(answer)
|
w.paste(answer)
|
||||||
|
|
||||||
|
|
||||||
Now in :file:`kitty.conf` add the lines::
|
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.
|
||||||
@@ -53,7 +53,7 @@ Passing arguments to kittens
|
|||||||
You can pass arguments to kittens by defining them in the map directive in
|
You can pass arguments to kittens by defining them in the map directive in
|
||||||
:file:`kitty.conf`. For example::
|
:file:`kitty.conf`. For example::
|
||||||
|
|
||||||
map ctrl+k kitten mykitten.py arg1 arg2
|
map ctrl+k kitten mykitten.py arg1 arg2
|
||||||
|
|
||||||
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
|
||||||
@@ -70,17 +70,17 @@ function, telling kitty what kind of input your kitten would like. For example:
|
|||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
# 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):
|
||||||
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, stdin_data, target_window_id, boss):
|
||||||
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
|
||||||
@@ -104,23 +104,23 @@ Create a file in the kitty config folder, :file:`~/.config/kitty/zoom_toggle.py`
|
|||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
def main(args):
|
def main(args):
|
||||||
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, answer, target_window_id, boss):
|
||||||
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':
|
||||||
tab.last_used_layout()
|
tab.last_used_layout()
|
||||||
else:
|
else:
|
||||||
tab.goto_layout('stack')
|
tab.goto_layout('stack')
|
||||||
|
|
||||||
|
|
||||||
Now in kitty.conf add::
|
Now in kitty.conf add::
|
||||||
|
|
||||||
map f11 kitten zoom_toggle.py
|
map f11 kitten zoom_toggle.py
|
||||||
|
|
||||||
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
|
Pressing :kbd:`F11` will now act as a zoom toggle function. You can get even
|
||||||
more fancy, switching the kitty OS window to fullscreen as well as changing the
|
more fancy, switching the kitty OS window to fullscreen as well as changing the
|
||||||
@@ -132,6 +132,32 @@ layout, by simply adding the line::
|
|||||||
To the ``handle_result()`` function, above.
|
To the ``handle_result()`` function, above.
|
||||||
|
|
||||||
|
|
||||||
|
Sending mouse events
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
If the program running in a window is receiving mouse events you can simulate
|
||||||
|
those using::
|
||||||
|
|
||||||
|
from kitty.fast_data_types import send_mouse_event
|
||||||
|
send_mouse_event(screen, x, y, button, action, mods)
|
||||||
|
|
||||||
|
``screen`` is the ``screen`` attribute of the window you want to send the event
|
||||||
|
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is
|
||||||
|
``GLFW_MOUSE_BUTTON_{button}`` where ``{button}`` is one of ``LEFT``,
|
||||||
|
``RIGHT``, ``MIDDLE`` or a digit from ``1`` to ``8``. ``action`` is one of
|
||||||
|
``PRESS``, ``RELEASE``, ``DRAG`` or ``MOVE``. ``mods`` is a bitmask of
|
||||||
|
``GLFW_MOD_{mod}`` where ``{mod}`` is one of ``SHIFT``, ``CONTROL`` or ``ALT``.
|
||||||
|
All the mentioned constants are imported from ``kitty.fast_data_types``.
|
||||||
|
|
||||||
|
For example, to send a left click at position x: 2, y: 3 to the active window::
|
||||||
|
|
||||||
|
from kitty.fast_data_types import send_mouse_event, GLFW_MOUSE_BUTTON_LEFT, PRESS
|
||||||
|
send_mouse_event(boss.active_window.screen, 2, 3, GLFW_MOUSE_BUTTON_LEFT, PRESS, 0)
|
||||||
|
|
||||||
|
The function will only send the event if the program is receiving events of
|
||||||
|
that type, and will return ``True`` if it sent the event, and ``False`` if not.
|
||||||
|
|
||||||
|
|
||||||
Debugging kittens
|
Debugging kittens
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
@@ -157,11 +183,11 @@ 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
|
||||||
|
|
||||||
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
|
`insert password <https://github.com/kovidgoyal/kitty/issues/1222>`_
|
||||||
Insert a password from a CLI password manager, taking care to only do it at
|
Insert a password from a CLI password manager, taking care to only do it at
|
||||||
a password prompt.
|
a password prompt.
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ Then you can simply use ``icat image.png`` to view images.
|
|||||||
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
|
`ImageMagick <https://www.imagemagick.org>`_ must be installed for ``icat`` to
|
||||||
work.
|
work.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
kitty's image display protocol may not work when used within a terminal
|
||||||
|
multiplexer such as ``screen`` or ``tmux``, depending on whether the
|
||||||
|
multiplexer has added support for it or not.
|
||||||
|
|
||||||
|
|
||||||
.. program:: kitty +kitten icat
|
.. program:: kitty +kitten icat
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ In order for control to work, :opt:`allow_remote_control` must be enabled in
|
|||||||
|
|
||||||
Now, in the new |kitty| window, enter the command::
|
Now, in the new |kitty| window, enter the command::
|
||||||
|
|
||||||
kitty @ new-window --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 ``cat`` program that will appear next
|
||||||
to the current window.
|
to the current window.
|
||||||
@@ -54,7 +54,7 @@ window. Type ``Ctrl+D`` when you are ready to stop.
|
|||||||
|
|
||||||
Now, let's open a new tab::
|
Now, let's open a new tab::
|
||||||
|
|
||||||
kitty @ new-window --new-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 with::
|
||||||
@@ -134,6 +134,19 @@ still write to the pipes of any other program on the same computer and
|
|||||||
therefore can control |kitty|. It can, however, be useful to block programs
|
therefore can control |kitty|. It can, however, be useful to block programs
|
||||||
running on other computers (for example, over ssh) or as other users.
|
running on other computers (for example, over ssh) or as other users.
|
||||||
|
|
||||||
|
Mapping key presses to remote control commands
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
If you wish to trigger a remote control command easily with just a keypress,
|
||||||
|
you can map it in :file:`kitty.conf`. For example::
|
||||||
|
|
||||||
|
map F1 remote_control set-spacing margin=30
|
||||||
|
|
||||||
|
Then pressing the :kbd:`F1` key will set the active window margins to 30.
|
||||||
|
The syntax for what follows :code:`remote_control` is exactly the same
|
||||||
|
as the syntax for what follows :code:`kitty @` above.
|
||||||
|
|
||||||
|
|
||||||
Documentation for the remote control protocol
|
Documentation for the remote control protocol
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ static inline void
|
|||||||
{parr}
|
{parr}
|
||||||
{keys_enum}
|
{keys_enum}
|
||||||
enum KEYS key = '{initial_key}';
|
enum KEYS key = '{initial_key}';
|
||||||
|
if (screen->parser_buf[pos] == ';') state = AFTER_VALUE;
|
||||||
|
|
||||||
while (pos < screen->parser_buf_pos) {{
|
while (pos < screen->parser_buf_pos) {{
|
||||||
switch(state) {{
|
switch(state) {{
|
||||||
|
|||||||
105
gen-wcwidth.py
105
gen-wcwidth.py
@@ -51,7 +51,8 @@ all_symbols: Set[int] = set()
|
|||||||
name_map: Dict[int, str] = {}
|
name_map: Dict[int, str] = {}
|
||||||
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set)
|
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set)
|
||||||
zwj = 0x200d
|
zwj = 0x200d
|
||||||
marks = set(emoji_skin_tone_modifiers) | {zwj}
|
flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26))
|
||||||
|
marks = set(emoji_skin_tone_modifiers) | {zwj} | flag_codepoints
|
||||||
not_assigned = set(range(0, sys.maxunicode))
|
not_assigned = set(range(0, sys.maxunicode))
|
||||||
|
|
||||||
|
|
||||||
@@ -103,36 +104,88 @@ def parse_ucd() -> None:
|
|||||||
word_search_map['lamda'] |= word_search_map['lambda']
|
word_search_map['lamda'] |= word_search_map['lambda']
|
||||||
|
|
||||||
|
|
||||||
def split_two(line: str) -> Tuple[Set[int], str]:
|
def parse_range_spec(spec: str) -> Set[int]:
|
||||||
spec, rest = line.split(';', 1)
|
spec = spec.strip()
|
||||||
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
|
||||||
if '..' in spec:
|
if '..' in spec:
|
||||||
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
|
||||||
chars = set(range(chars_[0], chars_[1] + 1))
|
chars = set(range(chars_[0], chars_[1] + 1))
|
||||||
else:
|
else:
|
||||||
chars = {int(spec, 16)}
|
chars = {int(spec, 16)}
|
||||||
return chars, rest
|
return chars
|
||||||
|
|
||||||
|
|
||||||
|
def split_two(line: str) -> Tuple[Set[int], str]:
|
||||||
|
spec, rest = line.split(';', 1)
|
||||||
|
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
|
||||||
|
return parse_range_spec(spec), rest
|
||||||
|
|
||||||
|
|
||||||
all_emoji: Set[int] = set()
|
all_emoji: Set[int] = set()
|
||||||
emoji_categories: Dict[str, Set[int]] = {}
|
|
||||||
emoji_presentation_bases: Set[int] = set()
|
emoji_presentation_bases: Set[int] = set()
|
||||||
|
narrow_emoji: Set[int] = set()
|
||||||
|
wide_emoji: Set[int] = set()
|
||||||
|
flags: Dict[int, List[int]] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_basic_emoji(spec: str) -> None:
|
||||||
|
parts = list(filter(None, spec.split()))
|
||||||
|
has_emoji_presentation = len(parts) < 2
|
||||||
|
chars = parse_range_spec(parts[0])
|
||||||
|
all_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
(wide_emoji if has_emoji_presentation else narrow_emoji).update(chars)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_keycap_sequence(spec: str) -> None:
|
||||||
|
base, fe0f, cc = list(filter(None, spec.split()))
|
||||||
|
chars = parse_range_spec(base)
|
||||||
|
all_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
narrow_emoji.update(chars)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_flag_emoji_sequence(spec: str) -> None:
|
||||||
|
a, b = list(filter(None, spec.split()))
|
||||||
|
left, right = int(a, 16), int(b, 16)
|
||||||
|
chars = {left, right}
|
||||||
|
all_emoji.update(chars)
|
||||||
|
wide_emoji.update(chars)
|
||||||
|
emoji_presentation_bases.update(chars)
|
||||||
|
flags.setdefault(left, []).append(right)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_emoji_tag_sequence(spec: str) -> None:
|
||||||
|
a = int(spec.split()[0], 16)
|
||||||
|
all_emoji.add(a)
|
||||||
|
wide_emoji.add(a)
|
||||||
|
emoji_presentation_bases.add(a)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_emoji_modifier_sequence(spec: str) -> None:
|
||||||
|
a, b = list(filter(None, spec.split()))
|
||||||
|
char, mod = int(a, 16), int(b, 16)
|
||||||
|
mod
|
||||||
|
all_emoji.add(char)
|
||||||
|
wide_emoji.add(char)
|
||||||
|
emoji_presentation_bases.add(char)
|
||||||
|
|
||||||
|
|
||||||
def parse_emoji() -> None:
|
def parse_emoji() -> None:
|
||||||
for line in get_data('emoji-data.txt', 'emoji'):
|
for line in get_data('emoji-sequences.txt', 'emoji'):
|
||||||
chars, rest = split_two(line)
|
parts = [x.strip() for x in line.split(';')]
|
||||||
s = emoji_categories.setdefault(rest, set())
|
if len(parts) < 2:
|
||||||
s.update(chars)
|
|
||||||
all_emoji.update(chars)
|
|
||||||
for line in get_data('emoji-variation-sequences.txt', 'emoji'):
|
|
||||||
parts = line.split()
|
|
||||||
base, var = parts[0], parts[1]
|
|
||||||
if base.startswith('#'):
|
|
||||||
continue
|
continue
|
||||||
if var.upper() == 'FE0F':
|
data, etype = parts[:2]
|
||||||
ibase = int(base, 16)
|
if etype == 'Basic_Emoji':
|
||||||
emoji_presentation_bases.add(ibase)
|
parse_basic_emoji(data)
|
||||||
|
elif etype == 'Emoji_Keycap_Sequence':
|
||||||
|
parse_keycap_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Flag_Sequence':
|
||||||
|
parse_flag_emoji_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Tag_Sequence':
|
||||||
|
parse_emoji_tag_sequence(data)
|
||||||
|
elif etype == 'RGI_Emoji_Modifier_Sequence':
|
||||||
|
parse_emoji_modifier_sequence(data)
|
||||||
|
|
||||||
|
|
||||||
doublewidth: Set[int] = set()
|
doublewidth: Set[int] = set()
|
||||||
@@ -204,15 +257,6 @@ def gen_emoji() -> None:
|
|||||||
p('\t}')
|
p('\t}')
|
||||||
p('\treturn false;\n}')
|
p('\treturn false;\n}')
|
||||||
|
|
||||||
p('static inline bool\nis_emoji_modifier(char_type code) {')
|
|
||||||
p('\tswitch(code) {')
|
|
||||||
for spec in get_ranges(list(emoji_categories['Emoji_Modifier'])):
|
|
||||||
write_case(spec, p)
|
|
||||||
p('\t\t\treturn true;')
|
|
||||||
p('\t\tdefault: return false;')
|
|
||||||
p('\t}')
|
|
||||||
p('\treturn false;\n}')
|
|
||||||
|
|
||||||
p('static inline bool\nis_symbol(char_type code) {')
|
p('static inline bool\nis_symbol(char_type code) {')
|
||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
for spec in get_ranges(list(all_symbols)):
|
for spec in get_ranges(list(all_symbols)):
|
||||||
@@ -427,7 +471,7 @@ def gen_names() -> None:
|
|||||||
def gen_wcwidth() -> None:
|
def gen_wcwidth() -> None:
|
||||||
seen: Set[int] = set()
|
seen: Set[int] = set()
|
||||||
|
|
||||||
def add(p: Callable, comment: str, chars_: Set[int], ret: int) -> None:
|
def add(p: Callable, comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int) -> None:
|
||||||
chars = chars_ - seen
|
chars = chars_ - seen
|
||||||
seen.update(chars)
|
seen.update(chars)
|
||||||
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
|
||||||
@@ -441,13 +485,14 @@ def gen_wcwidth() -> None:
|
|||||||
p('\tswitch(code) {')
|
p('\tswitch(code) {')
|
||||||
|
|
||||||
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
|
||||||
|
add(p, 'Flags', flag_codepoints, 2)
|
||||||
add(p, 'Marks', marks | {0}, 0)
|
add(p, 'Marks', marks | {0}, 0)
|
||||||
add(p, 'Non-printing characters', non_printing, -1)
|
add(p, 'Non-printing characters', non_printing, -1)
|
||||||
add(p, 'Private use', class_maps['Co'], -3)
|
add(p, 'Private use', class_maps['Co'], -3)
|
||||||
add(p, 'Text Presentation', emoji_categories['Emoji'] - emoji_categories['Emoji_Presentation'], 1)
|
add(p, 'Text Presentation', narrow_emoji, 1)
|
||||||
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
add(p, 'East Asian ambiguous width', ambiguous, -2)
|
||||||
add(p, 'East Asian double width', doublewidth, 2)
|
add(p, 'East Asian double width', doublewidth, 2)
|
||||||
add(p, 'Emoji Presentation', emoji_categories['Emoji_Presentation'], 2)
|
add(p, 'Emoji Presentation', wide_emoji, 2)
|
||||||
|
|
||||||
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
|
add(p, 'Not assigned in the unicode character database', not_assigned, -4)
|
||||||
|
|
||||||
|
|||||||
@@ -1133,7 +1133,7 @@ is_ascii_control_char(char x) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwInputScroll(window, deltaX, deltaY, flags);
|
_glfwInputScroll(window, deltaX, deltaY, flags, translateFlags([event modifierFlags]));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ def wayland_protocol_file_name(base: str, ext: str = 'c') -> str:
|
|||||||
|
|
||||||
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_compile: Callable, module: str = 'x11') -> Env:
|
||||||
ans = env.copy()
|
ans = env.copy()
|
||||||
ans.cflags.append('-fpic')
|
ans.cflags.append('-fPIC')
|
||||||
ans.cppflags.append('-D_GLFW_' + module.upper())
|
ans.cppflags.append('-D_GLFW_' + module.upper())
|
||||||
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
ans.cppflags.append('-D_GLFW_BUILD_DLL')
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ def init_env(env: Env, pkg_config: Callable, at_least_version: Callable, test_co
|
|||||||
for p in ans.wayland_protocols:
|
for p in ans.wayland_protocols:
|
||||||
ans.sources.append(wayland_protocol_file_name(p))
|
ans.sources.append(wayland_protocol_file_name(p))
|
||||||
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
ans.all_headers.append(wayland_protocol_file_name(p, 'h'))
|
||||||
for dep in 'wayland-egl wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
for dep in 'wayland-client wayland-cursor xkbcommon dbus-1'.split():
|
||||||
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
ans.cflags.extend(pkg_config(dep, '--cflags-only-I'))
|
||||||
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
ans.ldpaths.extend(pkg_config(dep, '--libs'))
|
||||||
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
has_memfd_create = test_compile(env.cc, '-Werror', src='''#define _GNU_SOURCE
|
||||||
|
|||||||
3
glfw/glfw3.h
vendored
3
glfw/glfw3.h
vendored
@@ -1550,6 +1550,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
||||||
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
||||||
* scrolling cancelled and value 6 if scrolling may begin soon.
|
* scrolling cancelled and value 6 if scrolling may begin soon.
|
||||||
|
* @param[int] mods The keyboard modifiers
|
||||||
*
|
*
|
||||||
* @sa @ref scrolling
|
* @sa @ref scrolling
|
||||||
* @sa @ref glfwSetScrollCallback
|
* @sa @ref glfwSetScrollCallback
|
||||||
@@ -1559,7 +1560,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
*
|
*
|
||||||
* @ingroup input
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||||
|
|
||||||
/*! @brief The function pointer type for key callbacks.
|
/*! @brief The function pointer type for key callbacks.
|
||||||
*
|
*
|
||||||
|
|||||||
4
glfw/input.c
vendored
4
glfw/input.c
vendored
@@ -300,10 +300,10 @@ void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
|
|||||||
|
|
||||||
// Notifies shared code of a scroll event
|
// Notifies shared code of a scroll event
|
||||||
//
|
//
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
|
||||||
{
|
{
|
||||||
if (window->callbacks.scroll)
|
if (window->callbacks.scroll)
|
||||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
|
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifies shared code of a mouse button click event
|
// Notifies shared code of a mouse button click event
|
||||||
|
|||||||
2
glfw/internal.h
vendored
2
glfw/internal.h
vendored
@@ -755,7 +755,7 @@ void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
|||||||
|
|
||||||
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int native_key, int action, int mods);
|
||||||
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev);
|
||||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
|
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods);
|
||||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
||||||
|
|||||||
2
glfw/wl_init.c
vendored
2
glfw/wl_init.c
vendored
@@ -334,7 +334,7 @@ static void pointerHandleAxis(void* data UNUSED,
|
|||||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||||
y = wl_fixed_to_double(value) * -1;
|
y = wl_fixed_to_double(value) * -1;
|
||||||
|
|
||||||
_glfwInputScroll(window, x, y, 1);
|
_glfwInputScroll(window, x, y, 1, _glfw.wl.xkb.states.modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_pointer_listener pointerListener = {
|
static const struct wl_pointer_listener pointerListener = {
|
||||||
|
|||||||
4
glfw/x11_init.c
vendored
4
glfw/x11_init.c
vendored
@@ -502,8 +502,10 @@ static Window createHelperWindow(void)
|
|||||||
|
|
||||||
// X error handler
|
// X error handler
|
||||||
//
|
//
|
||||||
static int errorHandler(Display *display UNUSED, XErrorEvent* event)
|
static int errorHandler(Display *display, XErrorEvent* event)
|
||||||
{
|
{
|
||||||
|
if (_glfw.x11.display != display)
|
||||||
|
return 0;
|
||||||
_glfw.x11.errorCode = event->error_code;
|
_glfw.x11.errorCode = event->error_code;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
43
glfw/x11_window.c
vendored
43
glfw/x11_window.c
vendored
@@ -1075,6 +1075,21 @@ static void onConfigChange(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_atom_names(Atom *atoms, int count, char **atom_names) {
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
XGetAtomNames(_glfw.x11.display, atoms, count, atom_names);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) {
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
|
atom_names[i] = XGetAtomName(_glfw.x11.display, atoms[i]);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) atom_names[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process the specified X event
|
// Process the specified X event
|
||||||
//
|
//
|
||||||
static void processEvent(XEvent *event)
|
static void processEvent(XEvent *event)
|
||||||
@@ -1250,13 +1265,13 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
// Modern X provides scroll events as mouse button presses
|
// Modern X provides scroll events as mouse button presses
|
||||||
else if (event->xbutton.button == Button4)
|
else if (event->xbutton.button == Button4)
|
||||||
_glfwInputScroll(window, 0.0, 1.0, 0);
|
_glfwInputScroll(window, 0.0, 1.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button5)
|
else if (event->xbutton.button == Button5)
|
||||||
_glfwInputScroll(window, 0.0, -1.0, 0);
|
_glfwInputScroll(window, 0.0, -1.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button6)
|
else if (event->xbutton.button == Button6)
|
||||||
_glfwInputScroll(window, 1.0, 0.0, 0);
|
_glfwInputScroll(window, 1.0, 0.0, 0, mods);
|
||||||
else if (event->xbutton.button == Button7)
|
else if (event->xbutton.button == Button7)
|
||||||
_glfwInputScroll(window, -1.0, 0.0, 0);
|
_glfwInputScroll(window, -1.0, 0.0, 0, mods);
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1393,12 +1408,18 @@ static void processEvent(XEvent *event)
|
|||||||
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
|
if (!event->xany.send_event && window->x11.parent != _glfw.x11.root)
|
||||||
{
|
{
|
||||||
Window dummy;
|
Window dummy;
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display,
|
XTranslateCoordinates(_glfw.x11.display,
|
||||||
window->x11.parent,
|
window->x11.parent,
|
||||||
_glfw.x11.root,
|
_glfw.x11.root,
|
||||||
xpos, ypos,
|
xpos, ypos,
|
||||||
&xpos, &ypos,
|
&xpos, &ypos,
|
||||||
&dummy);
|
&dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to translate ConfigureNotiy co-ords for reparented window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
||||||
@@ -1474,7 +1495,7 @@ static void processEvent(XEvent *event)
|
|||||||
}
|
}
|
||||||
char **atom_names = calloc(count, sizeof(char**));
|
char **atom_names = calloc(count, sizeof(char**));
|
||||||
if (atom_names) {
|
if (atom_names) {
|
||||||
XGetAtomNames(_glfw.x11.display, formats, count, atom_names);
|
get_atom_names(formats, count, atom_names);
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -1535,17 +1556,21 @@ static void processEvent(XEvent *event)
|
|||||||
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
|
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
|
||||||
const int yabs = (event->xclient.data.l[2]) & 0xffff;
|
const int yabs = (event->xclient.data.l[2]) & 0xffff;
|
||||||
Window dummy;
|
Window dummy;
|
||||||
int xpos, ypos;
|
int xpos = 0, ypos = 0;
|
||||||
|
|
||||||
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display,
|
XTranslateCoordinates(_glfw.x11.display,
|
||||||
_glfw.x11.root,
|
_glfw.x11.root,
|
||||||
window->x11.handle,
|
window->x11.handle,
|
||||||
xabs, yabs,
|
xabs, yabs,
|
||||||
&xpos, &ypos,
|
&xpos, &ypos,
|
||||||
&dummy);
|
&dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success)
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get DND event position");
|
||||||
|
|
||||||
_glfwInputCursorPos(window, xpos, ypos);
|
_glfwInputCursorPos(window, xpos, ypos);
|
||||||
|
|
||||||
@@ -1973,10 +1998,14 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
|||||||
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
|
||||||
{
|
{
|
||||||
Window dummy;
|
Window dummy;
|
||||||
int x, y;
|
int x = 0, y = 0;
|
||||||
|
|
||||||
|
_glfwGrabErrorHandlerX11();
|
||||||
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
|
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
|
||||||
0, 0, &x, &y, &dummy);
|
0, 0, &x, &y, &dummy);
|
||||||
|
_glfwReleaseErrorHandlerX11();
|
||||||
|
if (_glfw.x11.errorCode != Success)
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "X11: Failed to get window position");
|
||||||
|
|
||||||
if (xpos)
|
if (xpos)
|
||||||
*xpos = x;
|
*xpos = x;
|
||||||
|
|||||||
3
glfw/xkb_glfw.c
vendored
3
glfw/xkb_glfw.c
vendored
@@ -620,6 +620,9 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
|||||||
}
|
}
|
||||||
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
if (key_text[0]) { debug("%s: %s ", text_type, key_text); }
|
||||||
}
|
}
|
||||||
|
if (xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
int glfw_sym = glfw_key_for_sym(xkb_sym);
|
||||||
bool is_fallback = false;
|
bool is_fallback = false;
|
||||||
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
|
if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from .config_data import all_options, type_convert
|
|||||||
|
|
||||||
defaults: Optional[DiffOptions] = None
|
defaults: Optional[DiffOptions] = None
|
||||||
|
|
||||||
formats = {
|
formats: Dict[str, str] = {
|
||||||
'title': '',
|
'title': '',
|
||||||
'margin': '',
|
'margin': '',
|
||||||
'text': '',
|
'text': '',
|
||||||
@@ -35,6 +35,7 @@ def set_formats(opts: DiffOptions) -> None:
|
|||||||
formats['added'] = '48' + color_as_sgr(opts.added_bg)
|
formats['added'] = '48' + color_as_sgr(opts.added_bg)
|
||||||
formats['removed'] = '48' + color_as_sgr(opts.removed_bg)
|
formats['removed'] = '48' + color_as_sgr(opts.removed_bg)
|
||||||
formats['filler'] = '48' + color_as_sgr(opts.filler_bg)
|
formats['filler'] = '48' + color_as_sgr(opts.filler_bg)
|
||||||
|
formats['margin_filler'] = '48' + color_as_sgr(opts.margin_filler_bg or opts.filler_bg)
|
||||||
formats['hunk_margin'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_margin_bg)
|
formats['hunk_margin'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_margin_bg)
|
||||||
formats['hunk'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_bg)
|
formats['hunk'] = '38' + color_as_sgr(opts.margin_fg) + ';48' + color_as_sgr(opts.hunk_bg)
|
||||||
formats['removed_highlight'] = '48' + color_as_sgr(opts.highlight_removed_bg)
|
formats['removed_highlight'] = '48' + color_as_sgr(opts.highlight_removed_bg)
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ from gettext import gettext as _
|
|||||||
from typing import Any, Dict, Sequence, Union
|
from typing import Any, Dict, Sequence, Union
|
||||||
|
|
||||||
from kitty.conf.definition import Option, Shortcut, option_func
|
from kitty.conf.definition import Option, Shortcut, option_func
|
||||||
from kitty.conf.utils import positive_int, python_string, to_color
|
from kitty.conf.utils import (
|
||||||
|
positive_int, python_string, to_color, to_color_or_none
|
||||||
|
)
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
@@ -78,6 +80,8 @@ c('highlight_added_bg', '#acf2bd')
|
|||||||
c('added_margin_bg', '#cdffd8')
|
c('added_margin_bg', '#cdffd8')
|
||||||
|
|
||||||
c('filler_bg', '#fafbfc', long_text=_('Filler (empty) line background'))
|
c('filler_bg', '#fafbfc', long_text=_('Filler (empty) line background'))
|
||||||
|
c('margin_filler_bg', 'none', option_type=to_color_or_none, long_text=_(
|
||||||
|
'Filler (empty) line background in margins, defaults to the filler background'))
|
||||||
|
|
||||||
c('hunk_margin_bg', '#dbedff', long_text=_('Hunk header colors'))
|
c('hunk_margin_bg', '#dbedff', long_text=_('Hunk header colors'))
|
||||||
c('hunk_bg', '#f1f8ff')
|
c('hunk_bg', '#f1f8ff')
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ removed_format = format_func('removed')
|
|||||||
removed_margin_format = format_func('removed_margin')
|
removed_margin_format = format_func('removed_margin')
|
||||||
added_margin_format = format_func('added_margin')
|
added_margin_format = format_func('added_margin')
|
||||||
filler_format = format_func('filler')
|
filler_format = format_func('filler')
|
||||||
|
margin_filler_format = format_func('margin_filler')
|
||||||
hunk_margin_format = format_func('hunk_margin')
|
hunk_margin_format = format_func('hunk_margin')
|
||||||
hunk_format = format_func('hunk')
|
hunk_format = format_func('hunk')
|
||||||
highlight_map = {'remove': ('removed_highlight', 'removed'), 'add': ('added_highlight', 'added')}
|
highlight_map = {'remove': ('removed_highlight', 'removed'), 'add': ('added_highlight', 'added')}
|
||||||
@@ -214,7 +215,7 @@ def split_with_highlights(line: str, width: int, highlights: List, bg_highlight:
|
|||||||
return _split_with_highlights(line, truncate_pts, highlights, bg_highlight)
|
return _split_with_highlights(line, truncate_pts, highlights, bg_highlight)
|
||||||
|
|
||||||
|
|
||||||
margin_bg_map = {'filler': filler_format, 'remove': removed_margin_format, 'add': added_margin_format, 'context': margin_format}
|
margin_bg_map = {'filler': margin_filler_format, 'remove': removed_margin_format, 'add': added_margin_format, 'context': margin_format}
|
||||||
text_bg_map = {'filler': filler_format, 'remove': removed_format, 'add': added_format, 'context': text_format}
|
text_bg_map = {'filler': filler_format, 'remove': removed_format, 'add': added_format, 'context': text_format}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ def functions_for(args: HintsCLIOptions) -> Tuple[str, List[PostprocessorFunc]]:
|
|||||||
pattern = '[0-9a-f]{7,128}'
|
pattern = '[0-9a-f]{7,128}'
|
||||||
elif args.type == 'word':
|
elif args.type == 'word':
|
||||||
chars = args.word_characters
|
chars = args.word_characters
|
||||||
if not chars:
|
if chars is None:
|
||||||
chars = kitty_common_opts()['select_by_word_characters']
|
chars = kitty_common_opts()['select_by_word_characters']
|
||||||
pattern = r'(?u)[{}\w]{{{},}}'.format(escape(chars), args.minimum_match_length)
|
pattern = r'(?u)[{}\w]{{{},}}'.format(escape(chars), args.minimum_match_length)
|
||||||
post_processors.extend((brackets, quotes))
|
post_processors.extend((brackets, quotes))
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ def convert(
|
|||||||
if scaled or width > available_width or height > available_height:
|
if scaled or width > available_width or height > available_height:
|
||||||
width, height = fit_image(width, height, available_width, available_height)
|
width, height = fit_image(width, height, available_width, available_height)
|
||||||
cmd += ['-resize', '{}x{}!'.format(width, height)]
|
cmd += ['-resize', '{}x{}!'.format(width, height)]
|
||||||
|
cmd += ['-depth', '8']
|
||||||
with NamedTemporaryFile(prefix='icat-', suffix='.' + m.mode, delete=False, dir=tdir) as outfile:
|
with NamedTemporaryFile(prefix='icat-', suffix='.' + m.mode, delete=False, dir=tdir) as outfile:
|
||||||
run_imagemagick(path, cmd + [outfile.name])
|
run_imagemagick(path, cmd + [outfile.name])
|
||||||
# ImageMagick sometimes generated rgba images smaller than the specified
|
# ImageMagick sometimes generated rgba images smaller than the specified
|
||||||
|
|||||||
56991
kittens/unicode_input/names.h
generated
56991
kittens/unicode_input/names.h
generated
File diff suppressed because one or more lines are too long
@@ -6,7 +6,6 @@ from enum import IntFlag
|
|||||||
from itertools import chain
|
from itertools import chain
|
||||||
from typing import List, Optional, Sequence, Tuple
|
from typing import List, Optional, Sequence, Tuple
|
||||||
|
|
||||||
from .constants import WindowGeometry
|
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
BORDERS_PROGRAM, add_borders_rect, compile_program, init_borders_program,
|
BORDERS_PROGRAM, add_borders_rect, compile_program, init_borders_program,
|
||||||
os_window_has_background_image
|
os_window_has_background_image
|
||||||
@@ -22,22 +21,38 @@ class BorderColor(IntFlag):
|
|||||||
|
|
||||||
|
|
||||||
def vertical_edge(os_window_id: int, tab_id: int, color: int, width: int, top: int, bottom: int, left: int) -> None:
|
def vertical_edge(os_window_id: int, tab_id: int, color: int, width: int, top: int, bottom: int, left: int) -> None:
|
||||||
add_borders_rect(os_window_id, tab_id, left, top, left + width, bottom, color)
|
if width > 0:
|
||||||
|
add_borders_rect(os_window_id, tab_id, left, top, left + width, bottom, color)
|
||||||
|
|
||||||
|
|
||||||
def horizontal_edge(os_window_id: int, tab_id: int, color: int, height: int, left: int, right: int, top: int) -> None:
|
def horizontal_edge(os_window_id: int, tab_id: int, color: int, height: int, left: int, right: int, top: int) -> None:
|
||||||
add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color)
|
if height > 0:
|
||||||
|
add_borders_rect(os_window_id, tab_id, left, top, right, top + height, color)
|
||||||
|
|
||||||
|
|
||||||
def draw_edges(os_window_id: int, tab_id: int, colors: Sequence[int], width: int, geometry: 'WindowGeometry', base_width: int = 0) -> None:
|
def draw_edges(os_window_id: int, tab_id: int, colors: Sequence[int], window: WindowType, borders: bool = False) -> None:
|
||||||
left = geometry.left - (width + base_width)
|
geometry = window.geometry
|
||||||
top = geometry.top - (width + base_width)
|
pl, pt = window.effective_padding('left'), window.effective_padding('top')
|
||||||
right = geometry.right + (width + base_width)
|
pr, pb = window.effective_padding('right'), window.effective_padding('bottom')
|
||||||
bottom = geometry.bottom + (width + base_width)
|
left = geometry.left - pl
|
||||||
horizontal_edge(os_window_id, tab_id, colors[1], width, left, right, top)
|
top = geometry.top - pt
|
||||||
horizontal_edge(os_window_id, tab_id, colors[3], width, left, right, geometry.bottom + base_width)
|
lr = geometry.right
|
||||||
vertical_edge(os_window_id, tab_id, colors[0], width, top, bottom, left)
|
right = lr + pr
|
||||||
vertical_edge(os_window_id, tab_id, colors[2], width, top, bottom, geometry.right + base_width)
|
bt = geometry.bottom
|
||||||
|
bottom = bt + pb
|
||||||
|
if borders:
|
||||||
|
width = window.effective_border()
|
||||||
|
bt = bottom
|
||||||
|
lr = right
|
||||||
|
left -= width
|
||||||
|
top -= width
|
||||||
|
right += width
|
||||||
|
bottom += width
|
||||||
|
pl = pr = pb = pt = width
|
||||||
|
horizontal_edge(os_window_id, tab_id, colors[1], pt, left, right, top)
|
||||||
|
horizontal_edge(os_window_id, tab_id, colors[3], pb, left, right, bt)
|
||||||
|
vertical_edge(os_window_id, tab_id, colors[0], pl, top, bottom, left)
|
||||||
|
vertical_edge(os_window_id, tab_id, colors[2], pr, top, bottom, lr)
|
||||||
|
|
||||||
|
|
||||||
def load_borders_program() -> None:
|
def load_borders_program() -> None:
|
||||||
@@ -58,8 +73,6 @@ class Borders:
|
|||||||
active_window: Optional[WindowType],
|
active_window: Optional[WindowType],
|
||||||
current_layout: LayoutType,
|
current_layout: LayoutType,
|
||||||
extra_blank_rects: Sequence[Tuple[int, int, int, int]],
|
extra_blank_rects: Sequence[Tuple[int, int, int, int]],
|
||||||
padding_width: int,
|
|
||||||
border_width: int,
|
|
||||||
draw_window_borders: bool = True,
|
draw_window_borders: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
add_borders_rect(self.os_window_id, self.tab_id, 0, 0, 0, 0, BorderColor.default_bg)
|
add_borders_rect(self.os_window_id, self.tab_id, 0, 0, 0, 0, BorderColor.default_bg)
|
||||||
@@ -68,15 +81,14 @@ class Borders:
|
|||||||
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
for br in chain(current_layout.blank_rects, extra_blank_rects):
|
||||||
left, top, right, bottom = br
|
left, top, right, bottom = br
|
||||||
add_borders_rect(self.os_window_id, self.tab_id, left, top, right, bottom, BorderColor.default_bg)
|
add_borders_rect(self.os_window_id, self.tab_id, left, top, right, bottom, BorderColor.default_bg)
|
||||||
bw, pw = border_width, padding_width
|
bw = 0
|
||||||
if bw + pw <= 0:
|
if windows:
|
||||||
return
|
bw = windows[0].effective_border()
|
||||||
draw_borders = bw > 0 and draw_window_borders
|
draw_borders = bw > 0 and draw_window_borders
|
||||||
if draw_borders:
|
if draw_borders:
|
||||||
border_data = current_layout.resolve_borders(windows, active_window)
|
border_data = current_layout.resolve_borders(windows, active_window)
|
||||||
|
|
||||||
for i, w in enumerate(windows):
|
for i, w in enumerate(windows):
|
||||||
g = w.geometry
|
|
||||||
window_bg = w.screen.color_profile.default_bg
|
window_bg = w.screen.color_profile.default_bg
|
||||||
window_bg = (window_bg << 8) | BorderColor.window_bg
|
window_bg = (window_bg << 8) | BorderColor.window_bg
|
||||||
if draw_borders:
|
if draw_borders:
|
||||||
@@ -85,14 +97,15 @@ class Borders:
|
|||||||
color = BorderColor.active
|
color = BorderColor.active
|
||||||
else:
|
else:
|
||||||
color = BorderColor.bell if w.needs_attention else BorderColor.inactive
|
color = BorderColor.bell if w.needs_attention else BorderColor.inactive
|
||||||
colors = tuple(color if needed else window_bg for needed in next(border_data))
|
try:
|
||||||
draw_edges(
|
colors = tuple(color if needed else window_bg for needed in next(border_data))
|
||||||
self.os_window_id, self.tab_id, colors, bw, g, base_width=pw)
|
draw_edges(self.os_window_id, self.tab_id, colors, w, borders=True)
|
||||||
if pw > 0 and not has_background_image:
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
if not has_background_image:
|
||||||
# Draw the background rectangles over the padding region
|
# Draw the background rectangles over the padding region
|
||||||
colors = (window_bg, window_bg, window_bg, window_bg)
|
colors = window_bg, window_bg, window_bg, window_bg
|
||||||
draw_edges(
|
draw_edges(self.os_window_id, self.tab_id, colors, w)
|
||||||
self.os_window_id, self.tab_id, colors, pw, g)
|
|
||||||
|
|
||||||
color = BorderColor.inactive
|
color = BorderColor.inactive
|
||||||
for (left, top, right, bottom) in current_layout.window_independent_borders(windows, active_window):
|
for (left, top, right, bottom) in current_layout.window_independent_borders(windows, active_window):
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class Boss:
|
|||||||
os_window_id = create_os_window(
|
os_window_id = create_os_window(
|
||||||
initial_window_size_func(opts_for_size, self.cached_values),
|
initial_window_size_func(opts_for_size, self.cached_values),
|
||||||
pre_show_callback,
|
pre_show_callback,
|
||||||
appname, wname or self.args.name or wclass, wclass)
|
self.args.title or appname, wname or self.args.name or wclass, wclass)
|
||||||
tm = TabManager(os_window_id, self.opts, self.args, startup_session)
|
tm = TabManager(os_window_id, self.opts, self.args, startup_session)
|
||||||
self.os_window_map[os_window_id] = tm
|
self.os_window_map[os_window_id] = tm
|
||||||
return os_window_id
|
return os_window_id
|
||||||
@@ -336,19 +336,41 @@ class Boss:
|
|||||||
if not getattr(err, 'hide_traceback', False):
|
if not getattr(err, 'hide_traceback', False):
|
||||||
response['tb'] = traceback.format_exc()
|
response['tb'] = traceback.format_exc()
|
||||||
else:
|
else:
|
||||||
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
|
no_response = False
|
||||||
|
try:
|
||||||
|
no_response = json.loads(cmd).get('no_response')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not no_response:
|
||||||
|
response = {'ok': False, 'error': 'Remote control is disabled. Add allow_remote_control to your kitty.conf'}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def remote_control(self, *args: str) -> None:
|
||||||
|
from .remote_control import parse_rc_args
|
||||||
|
from .rc.base import command_for_name, parse_subcommand_cli, PayloadGetter
|
||||||
|
try:
|
||||||
|
global_opts, items = parse_rc_args(['@'] + list(args))
|
||||||
|
if not items:
|
||||||
|
return
|
||||||
|
cmd = items[0]
|
||||||
|
c = command_for_name(cmd)
|
||||||
|
opts, items = parse_subcommand_cli(c, items)
|
||||||
|
payload = c.message_to_kitty(global_opts, opts, items)
|
||||||
|
c.response_from_kitty(self, self.active_window, PayloadGetter(c, payload if isinstance(payload, dict) else {}))
|
||||||
|
except (Exception, SystemExit) as e:
|
||||||
|
self.show_error(_('remote_control mapping failed'), str(e))
|
||||||
|
|
||||||
def peer_message_received(self, msg_bytes: bytes) -> Optional[bytes]:
|
def peer_message_received(self, msg_bytes: bytes) -> Optional[bytes]:
|
||||||
msg = msg_bytes.decode('utf-8')
|
cmd_prefix = b'\x1bP@kitty-cmd'
|
||||||
cmd_prefix = '\x1bP@kitty-cmd'
|
terminator = b'\x1b\\'
|
||||||
if msg.startswith(cmd_prefix):
|
if msg_bytes.startswith(cmd_prefix) and msg_bytes.endswith(terminator):
|
||||||
cmd = msg[len(cmd_prefix):-2]
|
cmd = msg_bytes[len(cmd_prefix):-len(terminator)].decode('utf-8')
|
||||||
response = self._handle_remote_command(cmd, from_peer=True)
|
response = self._handle_remote_command(cmd, from_peer=True)
|
||||||
if response is None:
|
if response is None:
|
||||||
return None
|
return None
|
||||||
return (cmd_prefix + json.dumps(response) + '\x1b\\').encode('utf-8')
|
return cmd_prefix + json.dumps(response).encode('utf-8') + terminator
|
||||||
data = json.loads(msg)
|
|
||||||
|
data = json.loads(msg_bytes.decode('utf-8'))
|
||||||
if isinstance(data, dict) and data.get('cmd') == 'new_instance':
|
if isinstance(data, dict) and data.get('cmd') == 'new_instance':
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
startup_id = data.get('startup_id')
|
startup_id = data.get('startup_id')
|
||||||
@@ -534,7 +556,9 @@ class Boss:
|
|||||||
sz = os_window_font_size(os_window_id)
|
sz = os_window_font_size(os_window_id)
|
||||||
if sz:
|
if sz:
|
||||||
os_window_font_size(os_window_id, sz, True)
|
os_window_font_size(os_window_id, sz, True)
|
||||||
tm.update_dpi_based_sizes()
|
for tab in tm:
|
||||||
|
for window in tab:
|
||||||
|
window.on_dpi_change(sz)
|
||||||
tm.resize()
|
tm.resize()
|
||||||
|
|
||||||
def _set_os_window_background_opacity(self, os_window_id: int, opacity: float) -> None:
|
def _set_os_window_background_opacity(self, os_window_id: int, opacity: float) -> None:
|
||||||
@@ -700,6 +724,9 @@ class Boss:
|
|||||||
text = '\n'.join(parse_uri_list(text))
|
text = '\n'.join(parse_uri_list(text))
|
||||||
w.paste(text)
|
w.paste(text)
|
||||||
|
|
||||||
|
def confirm_os_window_close(self, os_window_id: int) -> None:
|
||||||
|
mark_os_window_for_close(os_window_id)
|
||||||
|
|
||||||
def on_os_window_closed(self, os_window_id: int, viewport_width: int, viewport_height: int) -> None:
|
def on_os_window_closed(self, os_window_id: int, viewport_width: int, viewport_height: int) -> None:
|
||||||
self.cached_values['window-size'] = viewport_width, viewport_height
|
self.cached_values['window-size'] = viewport_width, viewport_height
|
||||||
tm = self.os_window_map.pop(os_window_id, None)
|
tm = self.os_window_map.pop(os_window_id, None)
|
||||||
@@ -755,7 +782,7 @@ class Boss:
|
|||||||
window: Optional[Window] = None,
|
window: Optional[Window] = None,
|
||||||
custom_callback: Optional[Callable] = None,
|
custom_callback: Optional[Callable] = None,
|
||||||
action_on_removal: Optional[Callable] = None
|
action_on_removal: Optional[Callable] = None
|
||||||
) -> Optional[Window]:
|
) -> Any:
|
||||||
orig_args, args = list(args), list(args)
|
orig_args, args = list(args), list(args)
|
||||||
from kittens.runner import create_kitten_handler
|
from kittens.runner import create_kitten_handler
|
||||||
end_kitten = create_kitten_handler(kitten, orig_args)
|
end_kitten = create_kitten_handler(kitten, orig_args)
|
||||||
@@ -766,8 +793,7 @@ class Boss:
|
|||||||
w = window
|
w = window
|
||||||
tab = w.tabref() if w else None
|
tab = w.tabref() if w else None
|
||||||
if end_kitten.no_ui:
|
if end_kitten.no_ui:
|
||||||
end_kitten(None, getattr(w, 'id', None), self)
|
return end_kitten(None, getattr(w, 'id', None), self)
|
||||||
return None
|
|
||||||
|
|
||||||
if w is not None and tab is not None and w.overlay_for is None:
|
if w is not None and tab is not None and w.overlay_for is None:
|
||||||
args[0:0] = [config_dir, kitten]
|
args[0:0] = [config_dir, kitten]
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ void main() {
|
|||||||
|
|
||||||
// Background {{{
|
// Background {{{
|
||||||
#ifdef NEEDS_BACKROUND
|
#ifdef NEEDS_BACKROUND
|
||||||
float cell_has_non_default_bg = step(1, float(abs(bg_as_uint - default_colors[bg_index])));
|
float cell_has_non_default_bg = step(1, float(abs(bg_as_uint - default_colors[1])));
|
||||||
draw_bg = 1;
|
draw_bg = 1;
|
||||||
|
|
||||||
#if defined(BACKGROUND)
|
#if defined(BACKGROUND)
|
||||||
|
|||||||
@@ -523,17 +523,6 @@ change_menubar_title(PyObject *title UNUSED) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
|
||||||
update_window_title(Window *w, OSWindow *os_window) {
|
|
||||||
if (w->title && w->title != os_window->window_title) {
|
|
||||||
os_window->window_title = w->title;
|
|
||||||
Py_INCREF(os_window->window_title);
|
|
||||||
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) {
|
prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *active_window_id, color_type *active_window_bg, unsigned int *num_visible_windows, bool *all_windows_have_same_bg) {
|
||||||
#define TD os_window->tab_bar_render_data
|
#define TD os_window->tab_bar_render_data
|
||||||
@@ -577,7 +566,7 @@ prepare_to_render_os_window(OSWindow *os_window, monotonic_t now, unsigned int *
|
|||||||
*active_window_id = w->id;
|
*active_window_id = w->id;
|
||||||
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
|
collect_cursor_info(&WD.screen->cursor_render_info, w, now, os_window);
|
||||||
if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true;
|
if (w->cursor_visible_at_last_render != WD.screen->cursor_render_info.is_visible || w->last_cursor_x != WD.screen->cursor_render_info.x || w->last_cursor_y != WD.screen->cursor_render_info.y || w->last_cursor_shape != WD.screen->cursor_render_info.shape) needs_render = true;
|
||||||
update_window_title(w, os_window);
|
set_os_window_title_from_window(w, os_window);
|
||||||
*active_window_bg = window_bg;
|
*active_window_bg = window_bg;
|
||||||
} else WD.screen->cursor_render_info.is_visible = false;
|
} else WD.screen->cursor_render_info.is_visible = false;
|
||||||
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
|
if (send_cell_data_to_gpu(WD.vao_idx, WD.gvao_idx, WD.xstart, WD.ystart, WD.dx, WD.dy, WD.screen, os_window)) needs_render = true;
|
||||||
@@ -625,15 +614,6 @@ render_os_window(OSWindow *os_window, monotonic_t now, unsigned int active_windo
|
|||||||
#undef TD
|
#undef TD
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
update_os_window_title(OSWindow *os_window) {
|
|
||||||
Tab *tab = os_window->tabs + os_window->active_tab;
|
|
||||||
if (tab->num_windows) {
|
|
||||||
Window *w = tab->windows + tab->active_window;
|
|
||||||
update_window_title(w, os_window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_resizing_text(OSWindow *w) {
|
draw_resizing_text(OSWindow *w) {
|
||||||
char text[32] = {0};
|
char text[32] = {0};
|
||||||
@@ -649,7 +629,7 @@ draw_resizing_text(OSWindow *w) {
|
|||||||
static inline bool
|
static inline bool
|
||||||
no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) {
|
no_render_frame_received_recently(OSWindow *w, monotonic_t now, monotonic_t max_wait) {
|
||||||
bool ans = now - w->last_render_frame_received_at > max_wait;
|
bool ans = now - w->last_render_frame_received_at > max_wait;
|
||||||
if (ans) log_error("No render frame received in %.2f seconds, re-requesting at: %f", monotonic_t_to_s_double(max_wait), monotonic_t_to_s_double(now));
|
if (ans && global_state.debug_rendering) log_error("No render frame received in %.2f seconds, re-requesting at: %f", monotonic_t_to_s_double(max_wait), monotonic_t_to_s_double(now));
|
||||||
return ans;
|
return ans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,25 +845,42 @@ process_pending_resizes(monotonic_t now) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
close_all_windows(void) {
|
close_all_windows(void) {
|
||||||
for (size_t w = 0; w < global_state.num_os_windows; w++) mark_os_window_for_close(&global_state.os_windows[w], true);
|
for (size_t w = 0; w < global_state.num_os_windows; w++) mark_os_window_for_close(&global_state.os_windows[w], IMPERATIVE_CLOSE_REQUESTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
close_os_window(ChildMonitor *self, OSWindow *os_window) {
|
||||||
|
destroy_os_window(os_window);
|
||||||
|
call_boss(on_os_window_closed, "Kii", os_window->id, os_window->window_width, os_window->window_height);
|
||||||
|
for (size_t t=0; t < os_window->num_tabs; t++) {
|
||||||
|
Tab *tab = os_window->tabs + t;
|
||||||
|
for (size_t w = 0; w < tab->num_windows; w++) mark_child_for_close(self, tab->windows[w].id);
|
||||||
|
}
|
||||||
|
remove_os_window(os_window->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
process_pending_closes(ChildMonitor *self) {
|
process_pending_closes(ChildMonitor *self) {
|
||||||
global_state.has_pending_closes = false;
|
|
||||||
bool has_open_windows = false;
|
bool has_open_windows = false;
|
||||||
for (size_t w = global_state.num_os_windows; w > 0; w--) {
|
for (size_t w = global_state.num_os_windows; w > 0; w--) {
|
||||||
OSWindow *os_window = global_state.os_windows + w - 1;
|
OSWindow *os_window = global_state.os_windows + w - 1;
|
||||||
if (should_os_window_close(os_window)) {
|
switch(os_window->close_request) {
|
||||||
destroy_os_window(os_window);
|
case NO_CLOSE_REQUESTED:
|
||||||
call_boss(on_os_window_closed, "Kii", os_window->id, os_window->window_width, os_window->window_height);
|
has_open_windows = true;
|
||||||
for (size_t t=0; t < os_window->num_tabs; t++) {
|
break;
|
||||||
Tab *tab = os_window->tabs + t;
|
case CONFIRMABLE_CLOSE_REQUESTED:
|
||||||
for (size_t w = 0; w < tab->num_windows; w++) mark_child_for_close(self, tab->windows[w].id);
|
os_window->close_request = NO_CLOSE_REQUESTED;
|
||||||
}
|
call_boss(confirm_os_window_close, "K", os_window->id);
|
||||||
remove_os_window(os_window->id);
|
if (os_window->close_request == IMPERATIVE_CLOSE_REQUESTED) {
|
||||||
} else has_open_windows = true;
|
close_os_window(self, os_window);
|
||||||
|
} else has_open_windows = true;
|
||||||
|
break;
|
||||||
|
case IMPERATIVE_CLOSE_REQUESTED:
|
||||||
|
close_os_window(self, os_window);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
global_state.has_pending_closes = false;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (!OPT(macos_quit_when_last_window_closed)) {
|
if (!OPT(macos_quit_when_last_window_closed)) {
|
||||||
if (!has_open_windows && !application_quit_requested()) has_open_windows = true;
|
if (!has_open_windows && !application_quit_requested()) has_open_windows = true;
|
||||||
@@ -1279,7 +1276,7 @@ typedef struct {
|
|||||||
char *data;
|
char *data;
|
||||||
size_t capacity, used;
|
size_t capacity, used;
|
||||||
int fd;
|
int fd;
|
||||||
bool finished, close_socket;
|
bool finished, close_socket, is_peer_command;
|
||||||
} PeerReadData;
|
} PeerReadData;
|
||||||
static PeerReadData empty_prd = {.fd = -1, 0};
|
static PeerReadData empty_prd = {.fd = -1, 0};
|
||||||
|
|
||||||
@@ -1329,6 +1326,41 @@ accept_peer(int listen_fd, bool shutting_down) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KITTY_CMD_PREFIX "\x1bP@kitty-cmd{"
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
queue_peer_message(ChildMonitor *self, char *buf, size_t sz, int fd) {
|
||||||
|
children_mutex(lock);
|
||||||
|
ensure_space_for(self, messages, Message, self->messages_count + 1, messages_capacity, 16, true);
|
||||||
|
Message *m = self->messages + self->messages_count++;
|
||||||
|
m->data = buf; m->sz = sz; m->fd = fd;
|
||||||
|
children_mutex(unlock);
|
||||||
|
wakeup_main_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
dispatch_peer_command(ChildMonitor *self, PeerReadData *rd, int fd) {
|
||||||
|
size_t end = 0;
|
||||||
|
for (size_t i = 0; i < rd->used - 1; i++) {
|
||||||
|
if (rd->data[i] == 0x1b && rd->data[i+1] == '\\') {
|
||||||
|
end = i + 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!end) return;
|
||||||
|
char *buf = malloc(end + 8);
|
||||||
|
if (buf) {
|
||||||
|
memcpy(buf, rd->data, end);
|
||||||
|
queue_peer_message(self, buf, end, fd);
|
||||||
|
}
|
||||||
|
rd->is_peer_command = false;
|
||||||
|
if (rd->used > end) {
|
||||||
|
rd->used -= end;
|
||||||
|
memmove(rd->data, rd->data + end, rd->used);
|
||||||
|
if (rd->used >= sizeof(KITTY_CMD_PREFIX) - 1 && memcmp(rd->data, KITTY_CMD_PREFIX, sizeof(KITTY_CMD_PREFIX)-1) == 0) rd->is_peer_command = true;
|
||||||
|
} else rd->used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
read_from_peer(ChildMonitor *self, int s) {
|
read_from_peer(ChildMonitor *self, int s) {
|
||||||
bool read_finished = false;
|
bool read_finished = false;
|
||||||
@@ -1337,26 +1369,28 @@ read_from_peer(ChildMonitor *self, int s) {
|
|||||||
#define failed(msg) { read_finished = true; log_error("%s", msg); rd->finished = true; rd->close_socket = true; break; }
|
#define failed(msg) { read_finished = true; log_error("%s", msg); rd->finished = true; rd->close_socket = true; break; }
|
||||||
if (rd->fd == s) {
|
if (rd->fd == s) {
|
||||||
if (rd->used >= rd->capacity) {
|
if (rd->used >= rd->capacity) {
|
||||||
if (rd->capacity >= 1024 * 1024) failed("Ignoring too large message from peer");
|
if (rd->capacity >= 64 * 1024) failed("Ignoring too large message from peer");
|
||||||
rd->capacity = MAX(8192u, rd->capacity * 2);
|
rd->capacity = MAX(8192u, rd->capacity * 2);
|
||||||
rd->data = realloc(rd->data, rd->capacity);
|
rd->data = realloc(rd->data, rd->capacity);
|
||||||
if (!rd->data) failed("Out of memory");
|
if (!rd->data) failed("Out of memory");
|
||||||
}
|
}
|
||||||
ssize_t n = recv(s, rd->data + rd->used, rd->capacity - rd->used, 0);
|
ssize_t n = recv(s, rd->data + rd->used, rd->capacity - rd->used, 0);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
while (rd->is_peer_command) dispatch_peer_command(self, rd, s);
|
||||||
read_finished = true; rd->finished = true;
|
read_finished = true; rd->finished = true;
|
||||||
children_mutex(lock);
|
if (rd->used) queue_peer_message(self, rd->data, rd->used, s);
|
||||||
ensure_space_for(self, messages, Message, self->messages_count + 1, messages_capacity, 16, true);
|
else free(rd->data);
|
||||||
Message *m = self->messages + self->messages_count++;
|
rd->data = NULL;
|
||||||
m->data = rd->data; rd->data = NULL; m->sz = rd->used; m->fd = s;
|
|
||||||
children_mutex(unlock);
|
|
||||||
wakeup_main_loop();
|
|
||||||
} else if (n < 0) {
|
} else if (n < 0) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
perror("Error reading from talk peer");
|
perror("Error reading from talk peer");
|
||||||
failed("");
|
failed("");
|
||||||
}
|
}
|
||||||
} else rd->used += n;
|
} else {
|
||||||
|
if (!rd->used && memcmp(rd->data, KITTY_CMD_PREFIX, sizeof(KITTY_CMD_PREFIX)-1) == 0) rd->is_peer_command = true;
|
||||||
|
rd->used += n;
|
||||||
|
while (rd->is_peer_command) dispatch_peer_command(self, rd, s);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
19
kitty/cli.py
19
kitty/cli.py
@@ -409,7 +409,10 @@ def as_type_stub(seq: OptionSpecSeq, disabled: OptionSpecSeq, class_name: str, e
|
|||||||
elif otype == 'list':
|
elif otype == 'list':
|
||||||
t = 'typing.Sequence[str]'
|
t = 'typing.Sequence[str]'
|
||||||
elif otype in ('choice', 'choices'):
|
elif otype in ('choice', 'choices'):
|
||||||
t = 'str'
|
if opt['choices']:
|
||||||
|
t = 'typing.Literal[{}]'.format(','.join(f'{x!r}' for x in opt['choices']))
|
||||||
|
else:
|
||||||
|
t = 'str'
|
||||||
elif otype.startswith('bool-'):
|
elif otype.startswith('bool-'):
|
||||||
t = 'bool'
|
t = 'bool'
|
||||||
else:
|
else:
|
||||||
@@ -624,12 +627,15 @@ Tell kitty to listen on the specified address for control
|
|||||||
messages. For example, :option:`{appname} --listen-on`=unix:/tmp/mykitty or
|
messages. For example, :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. To control kitty, you can send
|
:option:`{appname} --listen-on`=unix:@mykitty. Environment variables
|
||||||
|
in the setting are expanded and relative paths are resolved with
|
||||||
|
respect to the temporary directory. To control kitty, you can send
|
||||||
it commands with :italic:`kitty @` using the :option:`kitty @ --to` option to
|
it commands with :italic:`kitty @` using the :option:`kitty @ --to` option to
|
||||||
specify this address. This option will be ignored, unless you set
|
specify this address. This option will be ignored, unless you set
|
||||||
:opt:`allow_remote_control` to yes in :file:`kitty.conf`. Note that if you run
|
:opt:`allow_remote_control` to yes in :file:`kitty.conf`. Note that if you run
|
||||||
:italic:`kitty @` within a kitty window, there is no need to specify the :italic:`--to`
|
:italic:`kitty @` within a kitty window, there is no need to specify the :italic:`--to`
|
||||||
option as it is read automatically from the environment.
|
option as it is read automatically from the environment. For UNIX sockets, this
|
||||||
|
can also be specified in :file:`kitty.conf`.
|
||||||
|
|
||||||
|
|
||||||
--start-as
|
--start-as
|
||||||
@@ -662,10 +668,11 @@ can open a new kitty window to replay the commands with::
|
|||||||
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-gl
|
--debug-rendering --debug-gl
|
||||||
type=bool-set
|
type=bool-set
|
||||||
Debug OpenGL 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. Useful when debugging rendering problems
|
instead of ignoring them. Also prints out miscellaneous debug information.
|
||||||
|
Useful when debugging rendering problems
|
||||||
|
|
||||||
|
|
||||||
--debug-keyboard
|
--debug-keyboard
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ your shell's rc file.
|
|||||||
|
|
||||||
2) Add an input_parser function, this takes the input from
|
2) Add an input_parser function, this takes the input from
|
||||||
the shell for the text being completed and returns a list of words
|
the shell for the text being completed and returns a list of words
|
||||||
alongwith a boolean indicating if we are on a new word or not. This
|
and a boolean indicating if we are on a new word or not. This
|
||||||
is passed to kitty's completion system.
|
is passed to kitty's completion system.
|
||||||
|
|
||||||
3) An output_serializer function that is responsible for
|
3) An output_serializer function that is responsible for
|
||||||
@@ -47,12 +47,32 @@ def debug(*a: Any, **kw: Any) -> None:
|
|||||||
print(*a, **kw)
|
print(*a, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
class Delegate:
|
||||||
|
|
||||||
|
def __init__(self, words: Sequence[str] = (), pos: int = -1, new_word: bool = False):
|
||||||
|
self.words: Sequence[str] = words
|
||||||
|
self.pos = pos
|
||||||
|
self.num_of_unknown_args = len(words) - pos
|
||||||
|
self.new_word = new_word
|
||||||
|
|
||||||
|
def __bool__(self) -> bool:
|
||||||
|
return self.pos > -1 and self.num_of_unknown_args > 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def precommand(self) -> str:
|
||||||
|
try:
|
||||||
|
return self.words[self.pos]
|
||||||
|
except IndexError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
class Completions:
|
class Completions:
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.match_groups: Dict[str, MathGroup] = {}
|
self.match_groups: Dict[str, MathGroup] = {}
|
||||||
self.no_space_groups: Set[str] = set()
|
self.no_space_groups: Set[str] = set()
|
||||||
self.files_groups: Set[str] = set()
|
self.files_groups: Set[str] = set()
|
||||||
|
self.delegate: Delegate = Delegate()
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=2)
|
@lru_cache(maxsize=2)
|
||||||
@@ -153,6 +173,15 @@ def zsh_output_serializer(ans: Completions) -> str:
|
|||||||
for word in matches:
|
for word in matches:
|
||||||
cmd.append(shlex.quote(word))
|
cmd.append(shlex.quote(word))
|
||||||
lines.append(' '.join(cmd) + ';')
|
lines.append(' '.join(cmd) + ';')
|
||||||
|
|
||||||
|
if ans.delegate:
|
||||||
|
if ans.delegate.num_of_unknown_args == 1 and not ans.delegate.new_word:
|
||||||
|
lines.append('_command_names -e')
|
||||||
|
elif ans.delegate.precommand:
|
||||||
|
for i in range(ans.delegate.pos + 1):
|
||||||
|
lines.append('shift words')
|
||||||
|
lines.append('(( CURRENT-- ))')
|
||||||
|
lines.append(f'_normal -p "{ans.delegate.precommand}"')
|
||||||
# debug('\n'.join(lines))
|
# debug('\n'.join(lines))
|
||||||
return '\n'.join(lines)
|
return '\n'.join(lines)
|
||||||
|
|
||||||
@@ -188,6 +217,8 @@ def completions_for_first_word(ans: Completions, prefix: str, entry_points: Iter
|
|||||||
list(entry_points) + cmds + ['+' + k for k in namespaced_entry_points]
|
list(entry_points) + cmds + ['+' + k for k in namespaced_entry_points]
|
||||||
if not prefix or k.startswith(prefix)
|
if not prefix or k.startswith(prefix)
|
||||||
}
|
}
|
||||||
|
if prefix:
|
||||||
|
ans.delegate = Delegate([prefix], 0)
|
||||||
|
|
||||||
|
|
||||||
def kitty_cli_opts(ans: Completions, prefix: Optional[str] = None) -> None:
|
def kitty_cli_opts(ans: Completions, prefix: Optional[str] = None) -> None:
|
||||||
@@ -201,9 +232,11 @@ def kitty_cli_opts(ans: Completions, prefix: Optional[str] = None) -> None:
|
|||||||
ans.match_groups['Options'] = matches
|
ans.match_groups['Options'] = matches
|
||||||
|
|
||||||
|
|
||||||
def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix: str) -> None:
|
def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||||
prefix = prefix or ''
|
prefix = prefix or ''
|
||||||
if not opt:
|
if not opt:
|
||||||
|
if unknown_args.num_of_unknown_args > 0:
|
||||||
|
ans.delegate = unknown_args
|
||||||
return
|
return
|
||||||
dest = opt['dest']
|
dest = opt['dest']
|
||||||
if dest == 'override':
|
if dest == 'override':
|
||||||
@@ -236,24 +269,24 @@ def complete_kitty_cli_arg(ans: Completions, opt: Optional[OptionDict], prefix:
|
|||||||
complete_files_and_dirs(ans, prefix[len('unix:'):], files_group_name='UNIX sockets', add_prefix='unix:')
|
complete_files_and_dirs(ans, prefix[len('unix:'):], files_group_name='UNIX sockets', add_prefix='unix:')
|
||||||
|
|
||||||
|
|
||||||
CompleteArgsFunc = Callable[[Completions, Optional[OptionDict], str], None]
|
CompleteArgsFunc = Callable[[Completions, Optional[OptionDict], str, Delegate], None]
|
||||||
|
|
||||||
|
|
||||||
def complete_alias_map(
|
def complete_alias_map(
|
||||||
ans: Completions,
|
ans: Completions,
|
||||||
words: Sequence[str],
|
words: Sequence[str],
|
||||||
new_word: str,
|
new_word: bool,
|
||||||
option_map: Dict[str, OptionDict],
|
option_map: Dict[str, OptionDict],
|
||||||
complete_args: Optional[CompleteArgsFunc] = None
|
complete_args: Optional[CompleteArgsFunc] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
expecting_arg = False
|
expecting_arg = False
|
||||||
opt: Optional[OptionDict] = None
|
opt: Optional[OptionDict] = None
|
||||||
last_word = words[-1] if words else ''
|
last_word = words[-1] if words else ''
|
||||||
for w in words:
|
for i, w in enumerate(words):
|
||||||
if expecting_arg:
|
if expecting_arg:
|
||||||
if w is last_word and not new_word:
|
if w is last_word and not new_word:
|
||||||
if opt is not None and complete_args is not None:
|
if opt is not None and complete_args is not None:
|
||||||
complete_args(ans, opt, w)
|
complete_args(ans, opt, w, Delegate())
|
||||||
return
|
return
|
||||||
expecting_arg = False
|
expecting_arg = False
|
||||||
continue
|
continue
|
||||||
@@ -263,27 +296,27 @@ def complete_alias_map(
|
|||||||
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(last_word)}
|
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(last_word)}
|
||||||
else:
|
else:
|
||||||
if complete_args is not None:
|
if complete_args is not None:
|
||||||
complete_args(ans, None, last_word)
|
complete_args(ans, None, last_word, Delegate(words, i))
|
||||||
return
|
return
|
||||||
if opt is None:
|
if opt is None:
|
||||||
if complete_args is not None:
|
if complete_args is not None:
|
||||||
complete_args(ans, None, '' if new_word else last_word)
|
complete_args(ans, None, '' if new_word else last_word, Delegate(words, i, new_word))
|
||||||
return # some non-option word encountered
|
return # some non-option word encountered
|
||||||
expecting_arg = not opt.get('type', '').startswith('bool-')
|
expecting_arg = not opt.get('type', '').startswith('bool-')
|
||||||
if expecting_arg:
|
if expecting_arg:
|
||||||
if opt is not None and complete_args is not None:
|
if opt is not None and complete_args is not None:
|
||||||
complete_args(ans, opt, '' if new_word else last_word)
|
complete_args(ans, opt, '' if new_word else last_word, Delegate())
|
||||||
else:
|
else:
|
||||||
prefix = '' if new_word else last_word
|
prefix = '' if new_word else last_word
|
||||||
if complete_args is not None:
|
if complete_args is not None:
|
||||||
complete_args(ans, None, prefix)
|
complete_args(ans, None, prefix, Delegate())
|
||||||
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(prefix)}
|
ans.match_groups['Options'] = {k: opt['help'] for k, opt in option_map.items() if k.startswith(prefix)}
|
||||||
|
|
||||||
|
|
||||||
def complete_cli(
|
def complete_cli(
|
||||||
ans: Completions,
|
ans: Completions,
|
||||||
words: Sequence[str],
|
words: Sequence[str],
|
||||||
new_word: str,
|
new_word: bool,
|
||||||
seq: OptionSpecSeq,
|
seq: OptionSpecSeq,
|
||||||
complete_args: Optional[CompleteArgsFunc] = None
|
complete_args: Optional[CompleteArgsFunc] = None
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -295,7 +328,7 @@ def complete_cli(
|
|||||||
complete_alias_map(ans, words, new_word, option_map, complete_args)
|
complete_alias_map(ans, words, new_word, option_map, complete_args)
|
||||||
|
|
||||||
|
|
||||||
def complete_remote_command(ans: Completions, cmd_name: str, words: Sequence[str], new_word: str) -> None:
|
def complete_remote_command(ans: Completions, cmd_name: str, words: Sequence[str], new_word: bool) -> None:
|
||||||
aliases, alias_map = options_for_cmd(cmd_name)
|
aliases, alias_map = options_for_cmd(cmd_name)
|
||||||
if not alias_map:
|
if not alias_map:
|
||||||
return
|
return
|
||||||
@@ -358,7 +391,7 @@ def complete_files_and_dirs(
|
|||||||
ans.files_groups.add(files_group_name)
|
ans.files_groups.add(files_group_name)
|
||||||
|
|
||||||
|
|
||||||
def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str) -> None:
|
def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
|
|
||||||
def icat_file_predicate(filename: str) -> bool:
|
def icat_file_predicate(filename: str) -> bool:
|
||||||
@@ -374,7 +407,7 @@ def complete_icat_args(ans: Completions, opt: Optional[OptionDict], prefix: str)
|
|||||||
def remote_files_completer(spec: Tuple[str, Tuple[str, ...]]) -> CompleteArgsFunc:
|
def remote_files_completer(spec: Tuple[str, Tuple[str, ...]]) -> CompleteArgsFunc:
|
||||||
name, matchers = spec
|
name, matchers = spec
|
||||||
|
|
||||||
def complete_files_map(ans: Completions, opt: Optional[OptionDict], prefix: str) -> None:
|
def complete_files_map(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||||
|
|
||||||
def predicate(filename: str) -> bool:
|
def predicate(filename: str) -> bool:
|
||||||
for m in matchers:
|
for m in matchers:
|
||||||
@@ -392,14 +425,14 @@ def config_file_predicate(filename: str) -> bool:
|
|||||||
return filename.endswith('.conf')
|
return filename.endswith('.conf')
|
||||||
|
|
||||||
|
|
||||||
def complete_diff_args(ans: Completions, opt: Optional[OptionDict], prefix: str) -> None:
|
def complete_diff_args(ans: Completions, opt: Optional[OptionDict], prefix: str, unknown_args: Delegate) -> None:
|
||||||
if opt is None:
|
if opt is None:
|
||||||
complete_files_and_dirs(ans, prefix, 'Files')
|
complete_files_and_dirs(ans, prefix, 'Files')
|
||||||
elif opt['dest'] == 'config':
|
elif opt['dest'] == 'config':
|
||||||
complete_files_and_dirs(ans, prefix, 'Config Files', config_file_predicate)
|
complete_files_and_dirs(ans, prefix, 'Config Files', config_file_predicate)
|
||||||
|
|
||||||
|
|
||||||
def complete_kitten(ans: Completions, kitten: str, words: Sequence[str], new_word: str) -> None:
|
def complete_kitten(ans: Completions, kitten: str, words: Sequence[str], new_word: bool) -> None:
|
||||||
try:
|
try:
|
||||||
cd = get_kitten_cli_docs(kitten)
|
cd = get_kitten_cli_docs(kitten)
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
@@ -419,7 +452,7 @@ def complete_kitten(ans: Completions, kitten: str, words: Sequence[str], new_wor
|
|||||||
}.get(kitten))
|
}.get(kitten))
|
||||||
|
|
||||||
|
|
||||||
def find_completions(words: Sequence[str], new_word: str, entry_points: Iterable[str], namespaced_entry_points: Iterable[str]) -> Completions:
|
def find_completions(words: Sequence[str], new_word: bool, entry_points: Iterable[str], namespaced_entry_points: Iterable[str]) -> Completions:
|
||||||
ans = Completions()
|
ans = Completions()
|
||||||
if not words or words[0] != 'kitty':
|
if not words or words[0] != 'kitty':
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from typing import (
|
|||||||
Set, Tuple, Union, get_type_hints
|
Set, Tuple, Union, get_type_hints
|
||||||
)
|
)
|
||||||
|
|
||||||
from .utils import to_bool
|
from .utils import Choice, to_bool
|
||||||
|
|
||||||
|
|
||||||
def to_string(x: str) -> str:
|
def to_string(x: str) -> str:
|
||||||
@@ -56,6 +56,8 @@ class Option:
|
|||||||
|
|
||||||
if type(self.option_type) is type:
|
if type(self.option_type) is type:
|
||||||
return type_name(self.option_type)
|
return type_name(self.option_type)
|
||||||
|
if isinstance(self.option_type, Choice):
|
||||||
|
return 'typing.Literal[{}]'.format(','.join(f'{x!r}' for x in self.option_type.all_choices))
|
||||||
th = get_type_hints(self.option_type)
|
th = get_type_hints(self.option_type)
|
||||||
try:
|
try:
|
||||||
rettype = th['return']
|
rettype = th['return']
|
||||||
|
|||||||
@@ -68,17 +68,21 @@ def python_string(text: str) -> str:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def choices(*choices: str) -> Callable[[str], str]:
|
class Choice:
|
||||||
defval = choices[0]
|
|
||||||
uc = frozenset(choices)
|
|
||||||
|
|
||||||
def choice(x: str) -> str:
|
def __init__(self, choices: Sequence[str]):
|
||||||
|
self.defval = choices[0]
|
||||||
|
self.all_choices = frozenset(choices)
|
||||||
|
|
||||||
|
def __call__(self, x: str) -> str:
|
||||||
x = x.lower()
|
x = x.lower()
|
||||||
if x not in uc:
|
if x not in self.all_choices:
|
||||||
x = defval
|
x = self.defval
|
||||||
return x
|
return x
|
||||||
|
|
||||||
return choice
|
|
||||||
|
def choices(*choices: str) -> Choice:
|
||||||
|
return Choice(choices)
|
||||||
|
|
||||||
|
|
||||||
def parse_line(
|
def parse_line(
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import sys
|
|||||||
from contextlib import contextmanager, suppress
|
from contextlib import contextmanager, suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, Generator, Iterable, List, Match, NamedTuple,
|
Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional,
|
||||||
Optional, Sequence, Set, Tuple, Type, Union
|
Sequence, Set, Tuple, Type, Union
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import fast_data_types as defines
|
from . import fast_data_types as defines
|
||||||
@@ -23,8 +23,8 @@ from .config_data import all_options, parse_mods, type_convert
|
|||||||
from .constants import cache_dir, defconf, is_macos
|
from .constants import cache_dir, defconf, is_macos
|
||||||
from .key_names import get_key_name_lookup, key_name_aliases
|
from .key_names import get_key_name_lookup, key_name_aliases
|
||||||
from .options_stub import Options as OptionsStub
|
from .options_stub import Options as OptionsStub
|
||||||
from .typing import TypedDict
|
from .typing import EdgeLiteral, TypedDict
|
||||||
from .utils import log_error
|
from .utils import expandvars, log_error
|
||||||
|
|
||||||
KeySpec = Tuple[int, bool, int]
|
KeySpec = Tuple[int, bool, int]
|
||||||
KeyMap = Dict[KeySpec, 'KeyAction']
|
KeyMap = Dict[KeySpec, 'KeyAction']
|
||||||
@@ -240,6 +240,15 @@ def set_colors(func: str, rest: str) -> FuncArgsType:
|
|||||||
return func, r
|
return func, r
|
||||||
|
|
||||||
|
|
||||||
|
@func_with_args('remote_control')
|
||||||
|
def remote_control(func: str, rest: str) -> FuncArgsType:
|
||||||
|
import shlex
|
||||||
|
r = shlex.split(rest)
|
||||||
|
if len(r) < 1:
|
||||||
|
log_error('Too few arguments to remote_control function')
|
||||||
|
return func, r
|
||||||
|
|
||||||
|
|
||||||
@func_with_args('nth_window')
|
@func_with_args('nth_window')
|
||||||
def nth_window(func: str, rest: str) -> FuncArgsType:
|
def nth_window(func: str, rest: str) -> FuncArgsType:
|
||||||
try:
|
try:
|
||||||
@@ -576,20 +585,6 @@ def handle_deprecated_macos_show_window_title_in_menubar_alias(key: str, val: st
|
|||||||
ans['macos_show_window_title_in'] = macos_show_window_title_in
|
ans['macos_show_window_title_in'] = macos_show_window_title_in
|
||||||
|
|
||||||
|
|
||||||
def expandvars(val: str, env: Dict[str, str]) -> str:
|
|
||||||
|
|
||||||
def sub(m: Match) -> str:
|
|
||||||
key = m.group(1)
|
|
||||||
result = env.get(key)
|
|
||||||
if result is None:
|
|
||||||
result = os.environ.get(key)
|
|
||||||
if result is None:
|
|
||||||
result = m.group()
|
|
||||||
return result
|
|
||||||
|
|
||||||
return re.sub(r'\$\{(\S+?)\}', sub, val)
|
|
||||||
|
|
||||||
|
|
||||||
@special_handler
|
@special_handler
|
||||||
def handle_env(key: str, val: str, ans: Dict[str, Any]) -> None:
|
def handle_env(key: str, val: str, ans: Dict[str, Any]) -> None:
|
||||||
key, val = val.partition('=')[::2]
|
key, val = val.partition('=')[::2]
|
||||||
@@ -730,12 +725,23 @@ def initial_window_size_func(opts: OptionsStub, cached_values: Dict) -> Callable
|
|||||||
# scaling is not needed on Wayland, but is needed on macOS. Not
|
# scaling is not needed on Wayland, but is needed on macOS. Not
|
||||||
# sure about X11.
|
# sure about X11.
|
||||||
xscale = yscale = 1
|
xscale = yscale = 1
|
||||||
|
|
||||||
|
def effective_margin(which: EdgeLiteral) -> float:
|
||||||
|
ans: float = getattr(opts.single_window_margin_width, which)
|
||||||
|
if ans < 0:
|
||||||
|
ans = getattr(opts.window_margin_width, which)
|
||||||
|
return ans
|
||||||
|
|
||||||
if w_unit == 'cells':
|
if w_unit == 'cells':
|
||||||
width = cell_width * w / xscale + (dpi_x / 72) * (opts.window_margin_width + opts.window_padding_width) + 1
|
spacing = effective_margin('left') + effective_margin('right')
|
||||||
|
spacing += opts.window_padding_width.left + opts.window_padding_width.right
|
||||||
|
width = cell_width * w / xscale + (dpi_x / 72) * spacing + 1
|
||||||
else:
|
else:
|
||||||
width = w
|
width = w
|
||||||
if h_unit == 'cells':
|
if h_unit == 'cells':
|
||||||
height = cell_height * h / yscale + (dpi_y / 72) * (opts.window_margin_width + opts.window_padding_width) + 1
|
spacing = effective_margin('top') + effective_margin('bottom')
|
||||||
|
spacing += opts.window_padding_width.top + opts.window_padding_width.bottom
|
||||||
|
height = cell_height * h / yscale + (dpi_y / 72) * spacing + 1
|
||||||
else:
|
else:
|
||||||
height = h
|
height = h
|
||||||
return int(width), int(height)
|
return int(width), int(height)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
import os
|
import os
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set, Tuple,
|
Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set,
|
||||||
TypeVar, Union
|
Tuple, TypeVar, Union
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import fast_data_types as defines
|
from . import fast_data_types as defines
|
||||||
@@ -16,7 +16,7 @@ from .conf.utils import (
|
|||||||
choices, positive_float, positive_int, to_bool, to_cmdline, to_color,
|
choices, positive_float, positive_int, to_bool, to_cmdline, to_color,
|
||||||
to_color_or_none, unit_float
|
to_color_or_none, unit_float
|
||||||
)
|
)
|
||||||
from .constants import config_dir, is_macos
|
from .constants import FloatEdges, config_dir, is_macos
|
||||||
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
from .fast_data_types import CURSOR_BEAM, CURSOR_BLOCK, CURSOR_UNDERLINE
|
||||||
from .layout import all_layouts
|
from .layout import all_layouts
|
||||||
from .rgb import Color, color_as_int, color_as_sharp, color_from_int
|
from .rgb import Color, color_as_int, color_as_sharp, color_from_int
|
||||||
@@ -548,7 +548,7 @@ rectangular block with the mouse)'''))
|
|||||||
o('terminal_select_modifiers', 'shift', option_type=to_modifiers, long_text=_('''
|
o('terminal_select_modifiers', 'shift', option_type=to_modifiers, long_text=_('''
|
||||||
The modifiers to override mouse selection even when a terminal application has grabbed the mouse'''))
|
The modifiers to override mouse selection even when a terminal application has grabbed the mouse'''))
|
||||||
|
|
||||||
o('select_by_word_characters', ':@-./_~?&=%+#', long_text=_('''
|
o('select_by_word_characters', '@-./_~?&=%+#', long_text=_('''
|
||||||
Characters considered part of a word when double clicking. In addition to these characters
|
Characters considered part of a word when double clicking. In addition to these characters
|
||||||
any character that is marked as an alphanumeric character in the unicode
|
any character that is marked as an alphanumeric character in the unicode
|
||||||
database will be matched.'''))
|
database will be matched.'''))
|
||||||
@@ -675,15 +675,42 @@ that separate the inactive window from a neighbor. Note that setting
|
|||||||
a non-zero window margin overrides this and causes all borders to be drawn.
|
a non-zero window margin overrides this and causes all borders to be drawn.
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
o('window_margin_width', 0.0, option_type=positive_float, long_text=_('''
|
|
||||||
The window margin (in pts) (blank area outside the border)'''))
|
|
||||||
|
|
||||||
o('single_window_margin_width', -1000.0, option_type=float, long_text=_('''
|
def edge_width(x: str, converter: Callable[[str], float] = positive_float) -> FloatEdges:
|
||||||
|
parts = str(x).split()
|
||||||
|
num = len(parts)
|
||||||
|
if num == 1:
|
||||||
|
val = converter(parts[0])
|
||||||
|
return FloatEdges(val, val, val, val)
|
||||||
|
if num == 2:
|
||||||
|
v = converter(parts[0])
|
||||||
|
h = converter(parts[1])
|
||||||
|
return FloatEdges(h, v, h, v)
|
||||||
|
if num == 3:
|
||||||
|
top, h, bottom = map(converter, parts)
|
||||||
|
return FloatEdges(h, top, h, bottom)
|
||||||
|
top, right, bottom, left = map(converter, parts)
|
||||||
|
return FloatEdges(left, top, right, bottom)
|
||||||
|
|
||||||
|
|
||||||
|
def optional_edge_width(x: str) -> FloatEdges:
|
||||||
|
return edge_width(x, float)
|
||||||
|
|
||||||
|
|
||||||
|
edge_desc = _(
|
||||||
|
'A single value sets all four sides. Two values set the vertical and horizontal sides.'
|
||||||
|
' Three values set top, horizontal and bottom. Four values set top, right, bottom and left.')
|
||||||
|
|
||||||
|
|
||||||
|
o('window_margin_width', '0', option_type=edge_width, long_text=_('''
|
||||||
|
The window margin (in pts) (blank area outside the border). ''' + edge_desc))
|
||||||
|
|
||||||
|
o('single_window_margin_width', '-1', option_type=optional_edge_width, long_text=_('''
|
||||||
The window margin (in pts) to use when only a single window is visible.
|
The window margin (in pts) to use when only a single window is visible.
|
||||||
Negative values will cause the value of :opt:`window_margin_width` to be used instead.'''))
|
Negative values will cause the value of :opt:`window_margin_width` to be used instead. ''' + edge_desc))
|
||||||
|
|
||||||
o('window_padding_width', 0.0, option_type=positive_float, long_text=_('''
|
o('window_padding_width', '0', option_type=edge_width, long_text=_('''
|
||||||
The window padding (in pts) (blank area between the text and the window border)'''))
|
The window padding (in pts) (blank area between the text and the window border). ''' + edge_desc))
|
||||||
|
|
||||||
o('placement_strategy', 'center', option_type=choices('center', 'top-left'), long_text=_('''
|
o('placement_strategy', 'center', option_type=choices('center', 'top-left'), long_text=_('''
|
||||||
When the window size is not an exact multiple of the cell size, the cell area of the terminal
|
When the window size is not an exact multiple of the cell size, the cell area of the terminal
|
||||||
@@ -843,6 +870,11 @@ A template to render the tab title. The default just renders
|
|||||||
the title. If you wish to include the tab-index as well,
|
the title. If you wish to include the tab-index as well,
|
||||||
use something like: :code:`{index}: {title}`. Useful
|
use something like: :code:`{index}: {title}`. Useful
|
||||||
if you have shortcuts mapped for :code:`goto_tab N`.
|
if you have shortcuts mapped for :code:`goto_tab N`.
|
||||||
|
In addition you can use :code:`{layout_name}` for the current
|
||||||
|
layout name and :code:`{num_windows}` for the number of windows
|
||||||
|
in the tab. Note that formatting is done by Python's string formatting
|
||||||
|
machinery, so you can use, for instance, :code:`{layout_name[:2].upper()}` to
|
||||||
|
show only the first two letters of the layout name, upper-cased.
|
||||||
'''))
|
'''))
|
||||||
o('active_tab_title_template', 'none', option_type=active_tab_title_template, long_text=_('''
|
o('active_tab_title_template', 'none', option_type=active_tab_title_template, long_text=_('''
|
||||||
Template to use for active tabs, if not specified falls back
|
Template to use for active tabs, if not specified falls back
|
||||||
@@ -1012,6 +1044,19 @@ you want to prevent programs running on a remote computer over ssh from
|
|||||||
controlling kitty.
|
controlling kitty.
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
|
o('listen_on', 'none', long_text=_('''
|
||||||
|
Tell kitty to listen to the specified unix/tcp socket for remote control
|
||||||
|
connections. Note that this will apply to all kitty instances. It can be
|
||||||
|
overridden by the :option:`kitty --listen-on` command line flag. This
|
||||||
|
option accepts only UNIX sockets, such as unix:${TEMP}/mykitty or (on Linux)
|
||||||
|
unix:@mykitty. Environment variables are expanded. If {kitty_pid} is present
|
||||||
|
then it is replaced by the PID of the kitty process, otherwise the PID of the kitty
|
||||||
|
process is appended to the value, with a hyphen. This option is ignored unless
|
||||||
|
you also set :opt:`allow_remote_control` to enable remote control. See the
|
||||||
|
help for :option:`kitty --listen-on` for more details.
|
||||||
|
'''))
|
||||||
|
|
||||||
o(
|
o(
|
||||||
'+env', '',
|
'+env', '',
|
||||||
add_to_default=False,
|
add_to_default=False,
|
||||||
|
|||||||
@@ -20,13 +20,27 @@ class Version(NamedTuple):
|
|||||||
|
|
||||||
|
|
||||||
appname: str = 'kitty'
|
appname: str = 'kitty'
|
||||||
version: Version = Version(0, 17, 2)
|
version: Version = Version(0, 17, 4)
|
||||||
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
|
||||||
base = os.path.dirname(os.path.abspath(__file__))
|
base = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class Edges(NamedTuple):
|
||||||
|
left: int = 0
|
||||||
|
top: int = 0
|
||||||
|
right: int = 0
|
||||||
|
bottom: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class FloatEdges(NamedTuple):
|
||||||
|
left: float = 0
|
||||||
|
top: float = 0
|
||||||
|
right: float = 0
|
||||||
|
bottom: float = 0
|
||||||
|
|
||||||
|
|
||||||
class ScreenGeometry(NamedTuple):
|
class ScreenGeometry(NamedTuple):
|
||||||
xstart: float
|
xstart: float
|
||||||
ystart: float
|
ystart: float
|
||||||
@@ -43,6 +57,7 @@ class WindowGeometry(NamedTuple):
|
|||||||
bottom: int
|
bottom: int
|
||||||
xnum: int
|
xnum: int
|
||||||
ynum: int
|
ynum: int
|
||||||
|
spaces: Edges = Edges()
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=2)
|
@lru_cache(maxsize=2)
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ harfbuzz_font_for_face(PyObject* s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) {
|
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness, unsigned int* strikethrough_position, unsigned int* strikethrough_thickness) {
|
||||||
// See https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html
|
// See https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html
|
||||||
CTFace *self = (CTFace*)s;
|
CTFace *self = (CTFace*)s;
|
||||||
#define count (128 - 32)
|
#define count (128 - 32)
|
||||||
@@ -332,6 +332,8 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u
|
|||||||
*underline_position = (unsigned int)floor(self->ascent - self->underline_position + 0.5);
|
*underline_position = (unsigned int)floor(self->ascent - self->underline_position + 0.5);
|
||||||
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
*underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness));
|
||||||
*baseline = (unsigned int)self->ascent;
|
*baseline = (unsigned int)self->ascent;
|
||||||
|
*strikethrough_position = (unsigned int)floor(*baseline * 0.65);
|
||||||
|
*strikethrough_thickness = *underline_thickness;
|
||||||
// float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5));
|
// float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5));
|
||||||
// Let CoreText's layout engine calculate the line height. Slower, but hopefully more accurate.
|
// Let CoreText's layout engine calculate the line height. Slower, but hopefully more accurate.
|
||||||
#define W "AQWMH_gyl "
|
#define W "AQWMH_gyl "
|
||||||
@@ -503,10 +505,12 @@ do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_g
|
|||||||
Region src = {.bottom=cell_height, .right=canvas_width}, dest = {.bottom=cell_height, .right=canvas_width};
|
Region src = {.bottom=cell_height, .right=canvas_width}, dest = {.bottom=cell_height, .right=canvas_width};
|
||||||
render_alpha_mask(render_buf, canvas, &src, &dest, canvas_width, canvas_width);
|
render_alpha_mask(render_buf, canvas, &src, &dest, canvas_width, canvas_width);
|
||||||
}
|
}
|
||||||
if (num_cells > 1) {
|
if (num_cells && (center_glyph || (num_cells == 2 && *was_colored))) {
|
||||||
// center glyphs
|
// center glyphs (two cell emoji, PUA glyphs, ligatures, etc)
|
||||||
CGFloat delta = canvas_width - br.size.width;
|
CGFloat delta = (((CGFloat)canvas_width - br.size.width) / 2.f);
|
||||||
if (delta > 1) right_shift_canvas(canvas, canvas_width, cell_height, (unsigned)(delta / 2.f));
|
// FiraCode ligatures result in negative origins
|
||||||
|
if (br.origin.x > 0) delta -= br.origin.x;
|
||||||
|
if (delta >= 1.f) right_shift_canvas(canvas, canvas_width, cell_height, (unsigned)(delta));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ void set_mouse_cursor(MouseShape);
|
|||||||
void enter_event(void);
|
void enter_event(void);
|
||||||
void mouse_event(int, int, int);
|
void mouse_event(int, int, int);
|
||||||
void focus_in_event(void);
|
void focus_in_event(void);
|
||||||
void scroll_event(double, double, int);
|
void scroll_event(double, double, int, int);
|
||||||
void fake_scroll(int, bool);
|
void fake_scroll(int, bool);
|
||||||
void set_special_key_combo(int glfw_key, int mods, bool is_native);
|
void set_special_key_combo(int glfw_key, int mods, bool is_native);
|
||||||
void on_key_input(GLFWkeyevent *ev);
|
void on_key_input(GLFWkeyevent *ev);
|
||||||
|
|||||||
@@ -30,18 +30,22 @@ static void* libsn_handle = NULL;
|
|||||||
static PyObject*
|
static PyObject*
|
||||||
init_x11_startup_notification(PyObject UNUSED *self, PyObject *args) {
|
init_x11_startup_notification(PyObject UNUSED *self, PyObject *args) {
|
||||||
static bool done = false;
|
static bool done = false;
|
||||||
static const char* libname = "libstartup-notification-1.so";
|
|
||||||
// some installs are missing the .so symlink, so try the full name
|
|
||||||
static const char* libname2 = "libstartup-notification-1.so.0";
|
|
||||||
static const char* libname3 = "libstartup-notification-1.so.0.0.0";
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
done = true;
|
done = true;
|
||||||
|
|
||||||
libsn_handle = dlopen(libname, RTLD_LAZY);
|
const char* libnames[] = {
|
||||||
if (libsn_handle == NULL) libsn_handle = dlopen(libname2, RTLD_LAZY);
|
"libstartup-notification-1.so",
|
||||||
if (libsn_handle == NULL) libsn_handle = dlopen(libname3, RTLD_LAZY);
|
// some installs are missing the .so symlink, so try the full name
|
||||||
|
"libstartup-notification-1.so.0",
|
||||||
|
"libstartup-notification-1.so.0.0.0",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
for (int i = 0; libnames[i]; i++) {
|
||||||
|
libsn_handle = dlopen(libnames[i], RTLD_LAZY);
|
||||||
|
if (libsn_handle) break;
|
||||||
|
}
|
||||||
if (libsn_handle == NULL) {
|
if (libsn_handle == NULL) {
|
||||||
PyErr_Format(PyExc_OSError, "Failed to load %s with error: %s", libname, dlerror());
|
PyErr_Format(PyExc_OSError, "Failed to load %s with error: %s", libnames[0], dlerror());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dlerror(); /* Clear any existing error */
|
dlerror(); /* Clear any existing error */
|
||||||
@@ -105,18 +109,22 @@ load_libcanberra_functions(void) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
load_libcanberra(void) {
|
load_libcanberra(void) {
|
||||||
static const char* libname = "libcanberra.so";
|
|
||||||
// some installs are missing the .so symlink, so try the full name
|
|
||||||
static const char* libname2 = "libcanberra.so.0";
|
|
||||||
static const char* libname3 = "libcanberra.so.0.2.5";
|
|
||||||
static bool done = false;
|
static bool done = false;
|
||||||
if (done) return;
|
if (done) return;
|
||||||
done = true;
|
done = true;
|
||||||
libcanberra_handle = dlopen(libname, RTLD_LAZY);
|
const char* libnames[] = {
|
||||||
if (libcanberra_handle == NULL) libcanberra_handle = dlopen(libname2, RTLD_LAZY);
|
"libcanberra.so",
|
||||||
if (libcanberra_handle == NULL) libcanberra_handle = dlopen(libname3, RTLD_LAZY);
|
// some installs are missing the .so symlink, so try the full name
|
||||||
|
"libcanberra.so.0",
|
||||||
|
"libcanberra.so.0.2.5",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
for (int i = 0; libnames[i]; i++) {
|
||||||
|
libcanberra_handle = dlopen(libnames[i], RTLD_LAZY);
|
||||||
|
if (libcanberra_handle) break;
|
||||||
|
}
|
||||||
if (libcanberra_handle == NULL) {
|
if (libcanberra_handle == NULL) {
|
||||||
fprintf(stderr, "Failed to load %s, cannot play beep sound, with error: %s\n", libname, dlerror());
|
fprintf(stderr, "Failed to load %s, cannot play beep sound, with error: %s\n", libnames[0], dlerror());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
load_libcanberra_functions();
|
load_libcanberra_functions();
|
||||||
|
|||||||
259
kitty/emoji.h
generated
259
kitty/emoji.h
generated
@@ -1,4 +1,4 @@
|
|||||||
// unicode data, built from the unicode standard on: 2019-10-01
|
// unicode data, built from the unicode standard on: 2020-04-06
|
||||||
// see gen-wcwidth.py
|
// see gen-wcwidth.py
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
@@ -18,14 +18,10 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0xae:
|
case 0xae:
|
||||||
return true;
|
return true;
|
||||||
case 0x200d:
|
|
||||||
return true;
|
|
||||||
case 0x203c:
|
case 0x203c:
|
||||||
return true;
|
return true;
|
||||||
case 0x2049:
|
case 0x2049:
|
||||||
return true;
|
return true;
|
||||||
case 0x20e3:
|
|
||||||
return true;
|
|
||||||
case 0x2122:
|
case 0x2122:
|
||||||
return true;
|
return true;
|
||||||
case 0x2139:
|
case 0x2139:
|
||||||
@@ -38,8 +34,6 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x2328:
|
case 0x2328:
|
||||||
return true;
|
return true;
|
||||||
case 0x2388:
|
|
||||||
return true;
|
|
||||||
case 0x23cf:
|
case 0x23cf:
|
||||||
return true;
|
return true;
|
||||||
case 0x23e9 ... 0x23f3:
|
case 0x23e9 ... 0x23f3:
|
||||||
@@ -56,15 +50,91 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x25fb ... 0x25fe:
|
case 0x25fb ... 0x25fe:
|
||||||
return true;
|
return true;
|
||||||
case 0x2600 ... 0x2605:
|
case 0x2600 ... 0x2604:
|
||||||
return true;
|
return true;
|
||||||
case 0x2607 ... 0x2612:
|
case 0x260e:
|
||||||
return true;
|
return true;
|
||||||
case 0x2614 ... 0x2685:
|
case 0x2611:
|
||||||
return true;
|
return true;
|
||||||
case 0x2690 ... 0x2705:
|
case 0x2614 ... 0x2615:
|
||||||
return true;
|
return true;
|
||||||
case 0x2708 ... 0x2712:
|
case 0x2618:
|
||||||
|
return true;
|
||||||
|
case 0x261d:
|
||||||
|
return true;
|
||||||
|
case 0x2620:
|
||||||
|
return true;
|
||||||
|
case 0x2622 ... 0x2623:
|
||||||
|
return true;
|
||||||
|
case 0x2626:
|
||||||
|
return true;
|
||||||
|
case 0x262a:
|
||||||
|
return true;
|
||||||
|
case 0x262e ... 0x262f:
|
||||||
|
return true;
|
||||||
|
case 0x2638 ... 0x263a:
|
||||||
|
return true;
|
||||||
|
case 0x2640:
|
||||||
|
return true;
|
||||||
|
case 0x2642:
|
||||||
|
return true;
|
||||||
|
case 0x2648 ... 0x2653:
|
||||||
|
return true;
|
||||||
|
case 0x265f ... 0x2660:
|
||||||
|
return true;
|
||||||
|
case 0x2663:
|
||||||
|
return true;
|
||||||
|
case 0x2665 ... 0x2666:
|
||||||
|
return true;
|
||||||
|
case 0x2668:
|
||||||
|
return true;
|
||||||
|
case 0x267b:
|
||||||
|
return true;
|
||||||
|
case 0x267e ... 0x267f:
|
||||||
|
return true;
|
||||||
|
case 0x2692 ... 0x2697:
|
||||||
|
return true;
|
||||||
|
case 0x2699:
|
||||||
|
return true;
|
||||||
|
case 0x269b ... 0x269c:
|
||||||
|
return true;
|
||||||
|
case 0x26a0 ... 0x26a1:
|
||||||
|
return true;
|
||||||
|
case 0x26a7:
|
||||||
|
return true;
|
||||||
|
case 0x26aa ... 0x26ab:
|
||||||
|
return true;
|
||||||
|
case 0x26b0 ... 0x26b1:
|
||||||
|
return true;
|
||||||
|
case 0x26bd ... 0x26be:
|
||||||
|
return true;
|
||||||
|
case 0x26c4 ... 0x26c5:
|
||||||
|
return true;
|
||||||
|
case 0x26c8:
|
||||||
|
return true;
|
||||||
|
case 0x26ce ... 0x26cf:
|
||||||
|
return true;
|
||||||
|
case 0x26d1:
|
||||||
|
return true;
|
||||||
|
case 0x26d3 ... 0x26d4:
|
||||||
|
return true;
|
||||||
|
case 0x26e9 ... 0x26ea:
|
||||||
|
return true;
|
||||||
|
case 0x26f0 ... 0x26f5:
|
||||||
|
return true;
|
||||||
|
case 0x26f7 ... 0x26fa:
|
||||||
|
return true;
|
||||||
|
case 0x26fd:
|
||||||
|
return true;
|
||||||
|
case 0x2702:
|
||||||
|
return true;
|
||||||
|
case 0x2705:
|
||||||
|
return true;
|
||||||
|
case 0x2708 ... 0x270d:
|
||||||
|
return true;
|
||||||
|
case 0x270f:
|
||||||
|
return true;
|
||||||
|
case 0x2712:
|
||||||
return true;
|
return true;
|
||||||
case 0x2714:
|
case 0x2714:
|
||||||
return true;
|
return true;
|
||||||
@@ -90,7 +160,7 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x2757:
|
case 0x2757:
|
||||||
return true;
|
return true;
|
||||||
case 0x2763 ... 0x2767:
|
case 0x2763 ... 0x2764:
|
||||||
return true;
|
return true;
|
||||||
case 0x2795 ... 0x2797:
|
case 0x2795 ... 0x2797:
|
||||||
return true;
|
return true;
|
||||||
@@ -118,15 +188,11 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x3299:
|
case 0x3299:
|
||||||
return true;
|
return true;
|
||||||
case 0xfe0f:
|
case 0x1f004:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f000 ... 0x1f0ff:
|
case 0x1f0cf:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f10d ... 0x1f10f:
|
case 0x1f170 ... 0x1f171:
|
||||||
return true;
|
|
||||||
case 0x1f12f:
|
|
||||||
return true;
|
|
||||||
case 0x1f16c ... 0x1f171:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f17e ... 0x1f17f:
|
case 0x1f17e ... 0x1f17f:
|
||||||
return true;
|
return true;
|
||||||
@@ -134,9 +200,9 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f191 ... 0x1f19a:
|
case 0x1f191 ... 0x1f19a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f1ad ... 0x1f1ff:
|
case 0x1f1e6 ... 0x1f1ff:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f201 ... 0x1f20f:
|
case 0x1f201 ... 0x1f202:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f21a:
|
case 0x1f21a:
|
||||||
return true;
|
return true;
|
||||||
@@ -144,44 +210,107 @@ is_emoji(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f232 ... 0x1f23a:
|
case 0x1f232 ... 0x1f23a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f23c ... 0x1f23f:
|
case 0x1f250 ... 0x1f251:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f249 ... 0x1f53d:
|
case 0x1f300 ... 0x1f321:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f546 ... 0x1f64f:
|
case 0x1f324 ... 0x1f393:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f680 ... 0x1f6ff:
|
case 0x1f396 ... 0x1f397:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f774 ... 0x1f77f:
|
case 0x1f399 ... 0x1f39b:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f7d5 ... 0x1f7ff:
|
case 0x1f39e ... 0x1f3f0:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f80c ... 0x1f80f:
|
case 0x1f3f3 ... 0x1f3f5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f848 ... 0x1f84f:
|
case 0x1f3f7 ... 0x1f4fd:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f85a ... 0x1f85f:
|
case 0x1f4ff ... 0x1f53d:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f888 ... 0x1f88f:
|
case 0x1f549 ... 0x1f54e:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f8ae ... 0x1f8ff:
|
case 0x1f550 ... 0x1f567:
|
||||||
|
return true;
|
||||||
|
case 0x1f56f ... 0x1f570:
|
||||||
|
return true;
|
||||||
|
case 0x1f573 ... 0x1f57a:
|
||||||
|
return true;
|
||||||
|
case 0x1f587:
|
||||||
|
return true;
|
||||||
|
case 0x1f58a ... 0x1f58d:
|
||||||
|
return true;
|
||||||
|
case 0x1f590:
|
||||||
|
return true;
|
||||||
|
case 0x1f595 ... 0x1f596:
|
||||||
|
return true;
|
||||||
|
case 0x1f5a4 ... 0x1f5a5:
|
||||||
|
return true;
|
||||||
|
case 0x1f5a8:
|
||||||
|
return true;
|
||||||
|
case 0x1f5b1 ... 0x1f5b2:
|
||||||
|
return true;
|
||||||
|
case 0x1f5bc:
|
||||||
|
return true;
|
||||||
|
case 0x1f5c2 ... 0x1f5c4:
|
||||||
|
return true;
|
||||||
|
case 0x1f5d1 ... 0x1f5d3:
|
||||||
|
return true;
|
||||||
|
case 0x1f5dc ... 0x1f5de:
|
||||||
|
return true;
|
||||||
|
case 0x1f5e1:
|
||||||
|
return true;
|
||||||
|
case 0x1f5e3:
|
||||||
|
return true;
|
||||||
|
case 0x1f5e8:
|
||||||
|
return true;
|
||||||
|
case 0x1f5ef:
|
||||||
|
return true;
|
||||||
|
case 0x1f5f3:
|
||||||
|
return true;
|
||||||
|
case 0x1f5fa ... 0x1f64f:
|
||||||
|
return true;
|
||||||
|
case 0x1f680 ... 0x1f6c5:
|
||||||
|
return true;
|
||||||
|
case 0x1f6cb ... 0x1f6d2:
|
||||||
|
return true;
|
||||||
|
case 0x1f6d5 ... 0x1f6d7:
|
||||||
|
return true;
|
||||||
|
case 0x1f6e0 ... 0x1f6e5:
|
||||||
|
return true;
|
||||||
|
case 0x1f6e9:
|
||||||
|
return true;
|
||||||
|
case 0x1f6eb ... 0x1f6ec:
|
||||||
|
return true;
|
||||||
|
case 0x1f6f0:
|
||||||
|
return true;
|
||||||
|
case 0x1f6f3 ... 0x1f6fc:
|
||||||
|
return true;
|
||||||
|
case 0x1f7e0 ... 0x1f7eb:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f90c ... 0x1f93a:
|
case 0x1f90c ... 0x1f93a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f93c ... 0x1f945:
|
case 0x1f93c ... 0x1f945:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f947 ... 0x1fffd:
|
case 0x1f947 ... 0x1f978:
|
||||||
return true;
|
return true;
|
||||||
case 0xe0020 ... 0xe007f:
|
case 0x1f97a ... 0x1f9cb:
|
||||||
return true;
|
return true;
|
||||||
default: return false;
|
case 0x1f9cd ... 0x1f9ff:
|
||||||
}
|
return true;
|
||||||
return false;
|
case 0x1fa70 ... 0x1fa74:
|
||||||
}
|
return true;
|
||||||
static inline bool
|
case 0x1fa78 ... 0x1fa7a:
|
||||||
is_emoji_modifier(char_type code) {
|
return true;
|
||||||
switch(code) {
|
case 0x1fa80 ... 0x1fa86:
|
||||||
case 0x1f3fb ... 0x1f3ff:
|
return true;
|
||||||
|
case 0x1fa90 ... 0x1faa8:
|
||||||
|
return true;
|
||||||
|
case 0x1fab0 ... 0x1fab6:
|
||||||
|
return true;
|
||||||
|
case 0x1fac0 ... 0x1fac2:
|
||||||
|
return true;
|
||||||
|
case 0x1fad0 ... 0x1fad6:
|
||||||
return true;
|
return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
@@ -390,10 +519,12 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x2b76 ... 0x2b95:
|
case 0x2b76 ... 0x2b95:
|
||||||
return true;
|
return true;
|
||||||
case 0x2b98 ... 0x2bff:
|
case 0x2b97 ... 0x2bff:
|
||||||
return true;
|
return true;
|
||||||
case 0x2ce5 ... 0x2cea:
|
case 0x2ce5 ... 0x2cea:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x2e50 ... 0x2e51:
|
||||||
|
return true;
|
||||||
case 0x2e80 ... 0x2e99:
|
case 0x2e80 ... 0x2e99:
|
||||||
return true;
|
return true;
|
||||||
case 0x2e9b ... 0x2ef3:
|
case 0x2e9b ... 0x2ef3:
|
||||||
@@ -450,6 +581,8 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0xab5b:
|
case 0xab5b:
|
||||||
return true;
|
return true;
|
||||||
|
case 0xab6a ... 0xab6b:
|
||||||
|
return true;
|
||||||
case 0xfb29:
|
case 0xfb29:
|
||||||
return true;
|
return true;
|
||||||
case 0xfbb2 ... 0xfbc1:
|
case 0xfbb2 ... 0xfbc1:
|
||||||
@@ -488,7 +621,7 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1018c ... 0x1018e:
|
case 0x1018c ... 0x1018e:
|
||||||
return true;
|
return true;
|
||||||
case 0x10190 ... 0x1019b:
|
case 0x10190 ... 0x1019c:
|
||||||
return true;
|
return true;
|
||||||
case 0x101a0:
|
case 0x101a0:
|
||||||
return true;
|
return true;
|
||||||
@@ -582,9 +715,7 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f0d1 ... 0x1f0f5:
|
case 0x1f0d1 ... 0x1f0f5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f110 ... 0x1f16c:
|
case 0x1f10d ... 0x1f1ad:
|
||||||
return true;
|
|
||||||
case 0x1f170 ... 0x1f1ac:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f1e6 ... 0x1f202:
|
case 0x1f1e6 ... 0x1f202:
|
||||||
return true;
|
return true;
|
||||||
@@ -596,11 +727,11 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f260 ... 0x1f265:
|
case 0x1f260 ... 0x1f265:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f300 ... 0x1f6d5:
|
case 0x1f300 ... 0x1f6d7:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f6e0 ... 0x1f6ec:
|
case 0x1f6e0 ... 0x1f6ec:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f6f0 ... 0x1f6fa:
|
case 0x1f6f0 ... 0x1f6fc:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f700 ... 0x1f773:
|
case 0x1f700 ... 0x1f773:
|
||||||
return true;
|
return true;
|
||||||
@@ -618,29 +749,33 @@ is_symbol(char_type code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f890 ... 0x1f8ad:
|
case 0x1f890 ... 0x1f8ad:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f900 ... 0x1f90b:
|
case 0x1f8b0 ... 0x1f8b1:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f90d ... 0x1f971:
|
case 0x1f900 ... 0x1f978:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f973 ... 0x1f976:
|
case 0x1f97a ... 0x1f9cb:
|
||||||
return true;
|
|
||||||
case 0x1f97a ... 0x1f9a2:
|
|
||||||
return true;
|
|
||||||
case 0x1f9a5 ... 0x1f9aa:
|
|
||||||
return true;
|
|
||||||
case 0x1f9ae ... 0x1f9ca:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f9cd ... 0x1fa53:
|
case 0x1f9cd ... 0x1fa53:
|
||||||
return true;
|
return true;
|
||||||
case 0x1fa60 ... 0x1fa6d:
|
case 0x1fa60 ... 0x1fa6d:
|
||||||
return true;
|
return true;
|
||||||
case 0x1fa70 ... 0x1fa73:
|
case 0x1fa70 ... 0x1fa74:
|
||||||
return true;
|
return true;
|
||||||
case 0x1fa78 ... 0x1fa7a:
|
case 0x1fa78 ... 0x1fa7a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1fa80 ... 0x1fa82:
|
case 0x1fa80 ... 0x1fa86:
|
||||||
return true;
|
return true;
|
||||||
case 0x1fa90 ... 0x1fa95:
|
case 0x1fa90 ... 0x1faa8:
|
||||||
|
return true;
|
||||||
|
case 0x1fab0 ... 0x1fab6:
|
||||||
|
return true;
|
||||||
|
case 0x1fac0 ... 0x1fac2:
|
||||||
|
return true;
|
||||||
|
case 0x1fad0 ... 0x1fad6:
|
||||||
|
return true;
|
||||||
|
case 0x1fb00 ... 0x1fb92:
|
||||||
|
return true;
|
||||||
|
case 0x1fb94 ... 0x1fbca:
|
||||||
return true;
|
return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,6 +327,10 @@ FC_WIDTH_NORMAL: int
|
|||||||
FC_SLANT_ROMAN: int
|
FC_SLANT_ROMAN: int
|
||||||
FC_SLANT_ITALIC: int
|
FC_SLANT_ITALIC: int
|
||||||
BORDERS_PROGRAM: int
|
BORDERS_PROGRAM: int
|
||||||
|
PRESS: int
|
||||||
|
RELEASE: int
|
||||||
|
DRAG: int
|
||||||
|
MOVE: int
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
@@ -546,10 +550,14 @@ def update_window_visibility(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def sync_os_window_title(os_window_id: int) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def set_options(
|
def set_options(
|
||||||
opts: Options,
|
opts: Options,
|
||||||
is_wayland: bool = False,
|
is_wayland: bool = False,
|
||||||
debug_gl: bool = False,
|
debug_rendering: bool = False,
|
||||||
debug_font_fallback: bool = False
|
debug_font_fallback: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
@@ -902,7 +910,7 @@ def set_font_data(
|
|||||||
box_drawing_func: Callable[[int, int, int, float],
|
box_drawing_func: Callable[[int, int, int, float],
|
||||||
Tuple[int, Union[bytearray, bytes, Array]]],
|
Tuple[int, Union[bytearray, bytes, Array]]],
|
||||||
prerender_func: Callable[
|
prerender_func: Callable[
|
||||||
[int, int, int, int, int, float, float, float, float],
|
[int, int, int, int, int, int, int, float, float, float, float],
|
||||||
Tuple[Union[Array, int], ...]],
|
Tuple[Union[Array, int], ...]],
|
||||||
descriptor_for_idx: Callable[[int], Tuple[FontObject, bool, bool]],
|
descriptor_for_idx: Callable[[int], Tuple[FontObject, bool, bool]],
|
||||||
bold: int, italic: int, bold_italic: int, num_symbol_fonts: int,
|
bold: int, italic: int, bold_italic: int, num_symbol_fonts: int,
|
||||||
@@ -1128,3 +1136,7 @@ def spawn(
|
|||||||
|
|
||||||
def key_to_bytes(glfw_key: int, smkx: bool, extended: bool, mods: int, action: int) -> bytes:
|
def key_to_bytes(glfw_key: int, smkx: bool, extended: bool, mods: int, action: int) -> bytes:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def set_window_padding(os_window_id: int, tab_id: int, window_id: int, left: int, top: int, right: int, bottom: int) -> None:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
FONTS_DATA_HEAD
|
FONTS_DATA_HEAD
|
||||||
id_type id;
|
id_type id;
|
||||||
unsigned int baseline, underline_position, underline_thickness;
|
unsigned int baseline, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
|
||||||
size_t fonts_capacity, fonts_count, fallback_fonts_count;
|
size_t fonts_capacity, fonts_count, fallback_fonts_count;
|
||||||
ssize_t medium_font_idx, bold_font_idx, italic_font_idx, bi_font_idx, first_symbol_font_idx, first_fallback_font_idx;
|
ssize_t medium_font_idx, bold_font_idx, italic_font_idx, bi_font_idx, first_symbol_font_idx, first_fallback_font_idx;
|
||||||
Font *fonts;
|
Font *fonts;
|
||||||
@@ -422,8 +422,8 @@ python_send_to_gpu(FONTS_DATA_HANDLE fg, unsigned int x, unsigned int y, unsigne
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
calc_cell_metrics(FontGroup *fg) {
|
calc_cell_metrics(FontGroup *fg) {
|
||||||
unsigned int cell_height, cell_width, baseline, underline_position, underline_thickness;
|
unsigned int cell_height, cell_width, baseline, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
|
||||||
cell_metrics(fg->fonts[fg->medium_font_idx].face, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness);
|
cell_metrics(fg->fonts[fg->medium_font_idx].face, &cell_width, &cell_height, &baseline, &underline_position, &underline_thickness, &strikethrough_position, &strikethrough_thickness);
|
||||||
if (!cell_width) fatal("Failed to calculate cell width for the specified font");
|
if (!cell_width) fatal("Failed to calculate cell width for the specified font");
|
||||||
unsigned int before_cell_height = cell_height;
|
unsigned int before_cell_height = cell_height;
|
||||||
int cw = cell_width, ch = cell_height;
|
int cw = cell_width, ch = cell_height;
|
||||||
@@ -455,7 +455,7 @@ calc_cell_metrics(FontGroup *fg) {
|
|||||||
}
|
}
|
||||||
sprite_tracker_set_layout(&fg->sprite_tracker, cell_width, cell_height);
|
sprite_tracker_set_layout(&fg->sprite_tracker, cell_width, cell_height);
|
||||||
fg->cell_width = cell_width; fg->cell_height = cell_height;
|
fg->cell_width = cell_width; fg->cell_height = cell_height;
|
||||||
fg->baseline = baseline; fg->underline_position = underline_position; fg->underline_thickness = underline_thickness;
|
fg->baseline = baseline; fg->underline_position = underline_position; fg->underline_thickness = underline_thickness, fg->strikethrough_position = strikethrough_position, fg->strikethrough_thickness = strikethrough_thickness;
|
||||||
free(fg->canvas);
|
free(fg->canvas);
|
||||||
fg->canvas = calloc(CELLS_IN_CANVAS * fg->cell_width * fg->cell_height, sizeof(pixel));
|
fg->canvas = calloc(CELLS_IN_CANVAS * fg->cell_width * fg->cell_height, sizeof(pixel));
|
||||||
if (!fg->canvas) fatal("Out of memory allocating canvas for font group");
|
if (!fg->canvas) fatal("Out of memory allocating canvas for font group");
|
||||||
@@ -1004,14 +1004,20 @@ merge_groups_for_pua_space_ligature(void) {
|
|||||||
G(groups)->is_space_ligature = true;
|
G(groups)->is_space_ligature = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_group_calt_ligature(const Group *group) {
|
||||||
|
GPUCell *first_cell = G(first_gpu_cell) + group->first_cell_idx;
|
||||||
|
return group->num_cells > 1 && group->has_special_glyph && (first_cell->attrs & WIDTH_MASK) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
split_run_at_offset(index_type cursor_offset, index_type *left, index_type *right) {
|
split_run_at_offset(index_type cursor_offset, index_type *left, index_type *right) {
|
||||||
*left = 0; *right = 0;
|
*left = 0; *right = 0;
|
||||||
for (unsigned idx = 0; idx < G(group_idx) + 1; idx++) {
|
for (unsigned idx = 0; idx < G(group_idx) + 1; idx++) {
|
||||||
Group *group = G(groups) + idx;
|
Group *group = G(groups) + idx;
|
||||||
if (group->first_cell_idx <= cursor_offset && cursor_offset < group->first_cell_idx + group->num_cells) {
|
if (group->first_cell_idx <= cursor_offset && cursor_offset < group->first_cell_idx + group->num_cells) {
|
||||||
GPUCell *first_cell = G(first_gpu_cell) + group->first_cell_idx;
|
if (is_group_calt_ligature(group)) {
|
||||||
if (group->num_cells > 1 && group->has_special_glyph && (first_cell->attrs & WIDTH_MASK) == 1) {
|
|
||||||
// likely a calt ligature
|
// likely a calt ligature
|
||||||
*left = group->first_cell_idx; *right = group->first_cell_idx + group->num_cells;
|
*left = group->first_cell_idx; *right = group->first_cell_idx + group->num_cells;
|
||||||
}
|
}
|
||||||
@@ -1039,6 +1045,11 @@ render_groups(FontGroup *fg, Font *font, bool center_glyph) {
|
|||||||
// there exist stupid fonts like Powerline that have no space glyph,
|
// there exist stupid fonts like Powerline that have no space glyph,
|
||||||
// so special case it: https://github.com/kovidgoyal/kitty/issues/1225
|
// so special case it: https://github.com/kovidgoyal/kitty/issues/1225
|
||||||
unsigned int num_glyphs = group->is_space_ligature ? 1 : group->num_glyphs;
|
unsigned int num_glyphs = group->is_space_ligature ? 1 : group->num_glyphs;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// FiraCode ligatures need to be centered on macOS
|
||||||
|
// see https://github.com/kovidgoyal/kitty/issues/2591
|
||||||
|
if (is_group_calt_ligature(group)) center_glyph = true;
|
||||||
|
#endif
|
||||||
render_group(fg, group->num_cells, num_glyphs, G(first_cpu_cell) + group->first_cell_idx, G(first_gpu_cell) + group->first_cell_idx, G(info) + group->first_glyph_idx, G(positions) + group->first_glyph_idx, font, primary, &ed, center_glyph);
|
render_group(fg, group->num_cells, num_glyphs, G(first_cpu_cell) + group->first_cell_idx, G(first_gpu_cell) + group->first_cell_idx, G(info) + group->first_glyph_idx, G(positions) + group->first_glyph_idx, font, primary, &ed, center_glyph);
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@@ -1243,7 +1254,7 @@ send_prerendered_sprites(FontGroup *fg) {
|
|||||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas);
|
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas);
|
||||||
do_increment(fg, &error);
|
do_increment(fg, &error);
|
||||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||||
PyObject *args = PyObject_CallFunction(prerender_function, "IIIIIffdd", fg->cell_width, fg->cell_height, fg->baseline, fg->underline_position, fg->underline_thickness, OPT(cursor_beam_thickness), OPT(cursor_underline_thickness), fg->logical_dpi_x, fg->logical_dpi_y);
|
PyObject *args = PyObject_CallFunction(prerender_function, "IIIIIIIffdd", fg->cell_width, fg->cell_height, fg->baseline, fg->underline_position, fg->underline_thickness, fg->strikethrough_position, fg->strikethrough_thickness, OPT(cursor_beam_thickness), OPT(cursor_underline_thickness), fg->logical_dpi_x, fg->logical_dpi_y);
|
||||||
if (args == NULL) { PyErr_Print(); fatal("Failed to pre-render cells"); }
|
if (args == NULL) { PyErr_Print(); fatal("Failed to pre-render cells"); }
|
||||||
for (ssize_t i = 0; i < PyTuple_GET_SIZE(args) - 1; i++) {
|
for (ssize_t i = 0; i < PyTuple_GET_SIZE(args) - 1; i++) {
|
||||||
x = fg->sprite_tracker.x; y = fg->sprite_tracker.y; z = fg->sprite_tracker.z;
|
x = fg->sprite_tracker.x; y = fg->sprite_tracker.y; z = fg->sprite_tracker.z;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ int get_glyph_width(PyObject *, glyph_index);
|
|||||||
bool is_glyph_empty(PyObject *, glyph_index);
|
bool is_glyph_empty(PyObject *, glyph_index);
|
||||||
hb_font_t* harfbuzz_font_for_face(PyObject*);
|
hb_font_t* harfbuzz_font_for_face(PyObject*);
|
||||||
bool set_size_for_face(PyObject*, unsigned int, bool, FONTS_DATA_HANDLE);
|
bool set_size_for_face(PyObject*, unsigned int, bool, FONTS_DATA_HANDLE);
|
||||||
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
|
||||||
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, bool center_glyph);
|
bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE, bool center_glyph);
|
||||||
PyObject* create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg);
|
PyObject* create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg);
|
||||||
PyObject* specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE);
|
PyObject* specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE);
|
||||||
|
|||||||
@@ -191,7 +191,9 @@ def render_special(
|
|||||||
cell_width: int = 0, cell_height: int = 0,
|
cell_width: int = 0, cell_height: int = 0,
|
||||||
baseline: int = 0,
|
baseline: int = 0,
|
||||||
underline_position: int = 0,
|
underline_position: int = 0,
|
||||||
underline_thickness: int = 0
|
underline_thickness: int = 0,
|
||||||
|
strikethrough_position: int = 0,
|
||||||
|
strikethrough_thickness: int = 0
|
||||||
) -> ctypes.Array:
|
) -> ctypes.Array:
|
||||||
underline_position = min(underline_position, cell_height - underline_thickness)
|
underline_position = min(underline_position, cell_height - underline_thickness)
|
||||||
CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
|
||||||
@@ -216,8 +218,7 @@ def render_special(
|
|||||||
t = max(1, min(cell_height - underline_position - 1, t))
|
t = max(1, min(cell_height - underline_position - 1, t))
|
||||||
dl([add_line, add_line, add_dline, add_curl][underline], underline_position, t, cell_height)
|
dl([add_line, add_line, add_dline, add_curl][underline], underline_position, t, cell_height)
|
||||||
if strikethrough:
|
if strikethrough:
|
||||||
pos = int(0.65 * baseline)
|
dl(add_line, strikethrough_position, strikethrough_thickness, cell_height)
|
||||||
dl(add_line, pos, underline_thickness, cell_height)
|
|
||||||
|
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
@@ -268,6 +269,8 @@ def prerender_function(
|
|||||||
baseline: int,
|
baseline: int,
|
||||||
underline_position: int,
|
underline_position: int,
|
||||||
underline_thickness: int,
|
underline_thickness: int,
|
||||||
|
strikethrough_position: int,
|
||||||
|
strikethrough_thickness: int,
|
||||||
cursor_beam_thickness: float,
|
cursor_beam_thickness: float,
|
||||||
cursor_underline_thickness: float,
|
cursor_underline_thickness: float,
|
||||||
dpi_x: float,
|
dpi_x: float,
|
||||||
@@ -276,7 +279,8 @@ def prerender_function(
|
|||||||
# Pre-render the special underline, strikethrough and missing and cursor cells
|
# Pre-render the special underline, strikethrough and missing and cursor cells
|
||||||
f = partial(
|
f = partial(
|
||||||
render_special, cell_width=cell_width, cell_height=cell_height, baseline=baseline,
|
render_special, cell_width=cell_width, cell_height=cell_height, baseline=baseline,
|
||||||
underline_position=underline_position, underline_thickness=underline_thickness)
|
underline_position=underline_position, underline_thickness=underline_thickness,
|
||||||
|
strikethrough_position=strikethrough_position, strikethrough_thickness=strikethrough_thickness)
|
||||||
c = partial(
|
c = partial(
|
||||||
render_cursor, cursor_beam_thickness=cursor_beam_thickness,
|
render_cursor, cursor_beam_thickness=cursor_beam_thickness,
|
||||||
cursor_underline_thickness=cursor_underline_thickness, cell_width=cell_width,
|
cursor_underline_thickness=cursor_underline_thickness, cell_width=cell_width,
|
||||||
|
|||||||
@@ -22,12 +22,13 @@
|
|||||||
|
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#include FT_BITMAP_H
|
#include FT_BITMAP_H
|
||||||
|
#include FT_TRUETYPE_TABLES_H
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
|
||||||
FT_Face face;
|
FT_Face face;
|
||||||
unsigned int units_per_EM;
|
unsigned int units_per_EM;
|
||||||
int ascender, descender, height, max_advance_width, max_advance_height, underline_position, underline_thickness;
|
int ascender, descender, height, max_advance_width, max_advance_height, underline_position, underline_thickness, strikethrough_position, strikethrough_thickness;
|
||||||
int hinting, hintstyle, index;
|
int hinting, hintstyle, index;
|
||||||
bool is_scalable, has_color;
|
bool is_scalable, has_color;
|
||||||
float size_in_pts;
|
float size_in_pts;
|
||||||
@@ -207,6 +208,12 @@ init_ft_face(Face *self, PyObject *path, int hinting, int hintstyle, FONTS_DATA_
|
|||||||
if (self->harfbuzz_font == NULL) { PyErr_NoMemory(); return false; }
|
if (self->harfbuzz_font == NULL) { PyErr_NoMemory(); return false; }
|
||||||
hb_ft_font_set_load_flags(self->harfbuzz_font, get_load_flags(self->hinting, self->hintstyle, FT_LOAD_DEFAULT));
|
hb_ft_font_set_load_flags(self->harfbuzz_font, get_load_flags(self->hinting, self->hintstyle, FT_LOAD_DEFAULT));
|
||||||
|
|
||||||
|
TT_OS2 *os2 = (TT_OS2*)FT_Get_Sfnt_Table(self->face, FT_SFNT_OS2);
|
||||||
|
if (os2 != NULL) {
|
||||||
|
self->strikethrough_position = os2->yStrikeoutPosition;
|
||||||
|
self->strikethrough_thickness = os2->yStrikeoutSize;
|
||||||
|
}
|
||||||
|
|
||||||
self->path = path;
|
self->path = path;
|
||||||
Py_INCREF(self->path);
|
Py_INCREF(self->path);
|
||||||
self->index = self->face->face_index & 0xFFFF;
|
self->index = self->face->face_index & 0xFFFF;
|
||||||
@@ -263,11 +270,11 @@ static PyObject *
|
|||||||
repr(Face *self) {
|
repr(Face *self) {
|
||||||
const char *ps_name = FT_Get_Postscript_Name(self->face);
|
const char *ps_name = FT_Get_Postscript_Name(self->face);
|
||||||
return PyUnicode_FromFormat(
|
return PyUnicode_FromFormat(
|
||||||
"Face(family=%s, style=%s, ps_name=%s, path=%S, index=%d, is_scalable=%S, has_color=%S, ascender=%i, descender=%i, height=%i, underline_position=%i, underline_thickness=%i)",
|
"Face(family=%s, style=%s, ps_name=%s, path=%S, index=%d, is_scalable=%S, has_color=%S, ascender=%i, descender=%i, height=%i, underline_position=%i, underline_thickness=%i, strikethrough_position=%i, strikethrough_thickness=%i)",
|
||||||
self->face->family_name ? self->face->family_name : "", self->face->style_name ? self->face->style_name : "",
|
self->face->family_name ? self->face->family_name : "", self->face->style_name ? self->face->style_name : "",
|
||||||
ps_name ? ps_name: "",
|
ps_name ? ps_name: "",
|
||||||
self->path, self->index, self->is_scalable ? Py_True : Py_False, self->has_color ? Py_True : Py_False,
|
self->path, self->index, self->is_scalable ? Py_True : Py_False, self->has_color ? Py_True : Py_False,
|
||||||
self->ascender, self->descender, self->height, self->underline_position, self->underline_thickness
|
self->ascender, self->descender, self->height, self->underline_position, self->underline_thickness, self->strikethrough_position, self->strikethrough_thickness
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,13 +299,24 @@ calc_cell_width(Face *self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness) {
|
cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, unsigned int* baseline, unsigned int* underline_position, unsigned int* underline_thickness, unsigned int* strikethrough_position, unsigned int* strikethrough_thickness) {
|
||||||
Face *self = (Face*)s;
|
Face *self = (Face*)s;
|
||||||
*cell_width = calc_cell_width(self);
|
*cell_width = calc_cell_width(self);
|
||||||
*cell_height = calc_cell_height(self, true);
|
*cell_height = calc_cell_height(self, true);
|
||||||
*baseline = font_units_to_pixels_y(self, self->ascender);
|
*baseline = font_units_to_pixels_y(self, self->ascender);
|
||||||
*underline_position = MIN(*cell_height - 1, (unsigned int)font_units_to_pixels_y(self, MAX(0, self->ascender - self->underline_position)));
|
*underline_position = MIN(*cell_height - 1, (unsigned int)font_units_to_pixels_y(self, MAX(0, self->ascender - self->underline_position)));
|
||||||
*underline_thickness = MAX(1, font_units_to_pixels_y(self, self->underline_thickness));
|
*underline_thickness = MAX(1, font_units_to_pixels_y(self, self->underline_thickness));
|
||||||
|
|
||||||
|
if (self->strikethrough_position != 0) {
|
||||||
|
*strikethrough_position = MIN(*cell_height - 1, (unsigned int)font_units_to_pixels_y(self, MAX(0, self->ascender - self->strikethrough_position)));
|
||||||
|
} else {
|
||||||
|
*strikethrough_position = (unsigned int)floor(*baseline * 0.65);
|
||||||
|
}
|
||||||
|
if (self->strikethrough_thickness > 0) {
|
||||||
|
*strikethrough_thickness = MAX(1, font_units_to_pixels_y(self, self->strikethrough_thickness));
|
||||||
|
} else {
|
||||||
|
*strikethrough_thickness = *underline_thickness;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
@@ -659,6 +677,8 @@ static PyMemberDef members[] = {
|
|||||||
MEM(max_advance_height, T_INT),
|
MEM(max_advance_height, T_INT),
|
||||||
MEM(underline_position, T_INT),
|
MEM(underline_position, T_INT),
|
||||||
MEM(underline_thickness, T_INT),
|
MEM(underline_thickness, T_INT),
|
||||||
|
MEM(strikethrough_position, T_INT),
|
||||||
|
MEM(strikethrough_thickness, T_INT),
|
||||||
MEM(is_scalable, T_BOOL),
|
MEM(is_scalable, T_BOOL),
|
||||||
MEM(path, T_OBJECT_EX),
|
MEM(path, T_OBJECT_EX),
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ gl_init() {
|
|||||||
if (!gl_version) {
|
if (!gl_version) {
|
||||||
fatal("Loading the OpenGL library failed");
|
fatal("Loading the OpenGL library failed");
|
||||||
}
|
}
|
||||||
if (!global_state.debug_gl) {
|
if (!global_state.debug_rendering) {
|
||||||
gladUninstallGLDebug();
|
gladUninstallGLDebug();
|
||||||
}
|
}
|
||||||
gladSetGLPostCallback(check_for_gl_error);
|
gladSetGLPostCallback(check_for_gl_error);
|
||||||
@@ -59,7 +59,7 @@ gl_init() {
|
|||||||
glad_loaded = true;
|
glad_loaded = true;
|
||||||
int gl_major = GLAD_VERSION_MAJOR(gl_version);
|
int gl_major = GLAD_VERSION_MAJOR(gl_version);
|
||||||
int gl_minor = GLAD_VERSION_MINOR(gl_version);
|
int gl_minor = GLAD_VERSION_MINOR(gl_version);
|
||||||
if (global_state.debug_gl) printf("GL version string: '%s' Detected version: %d.%d\n", glGetString(GL_VERSION), gl_major, gl_minor);
|
if (global_state.debug_rendering) printf("GL version string: '%s' Detected version: %d.%d\n", glGetString(GL_VERSION), gl_major, gl_minor);
|
||||||
if (gl_major < OPENGL_REQUIRED_VERSION_MAJOR || (gl_major == OPENGL_REQUIRED_VERSION_MAJOR && gl_minor < OPENGL_REQUIRED_VERSION_MINOR)) {
|
if (gl_major < OPENGL_REQUIRED_VERSION_MAJOR || (gl_major == OPENGL_REQUIRED_VERSION_MAJOR && gl_minor < OPENGL_REQUIRED_VERSION_MINOR)) {
|
||||||
fatal("OpenGL version is %d.%d, version >= 3.3 required for kitty", gl_major, gl_minor);
|
fatal("OpenGL version is %d.%d, version >= 3.3 required for kitty", gl_major, gl_minor);
|
||||||
}
|
}
|
||||||
|
|||||||
3
kitty/glfw-wrapper.h
generated
3
kitty/glfw-wrapper.h
generated
@@ -1313,6 +1313,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
* value 2 for stationary momentum scrolling, value 3 for momentum scrolling
|
||||||
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
* in progress, value 4 for momentum scrolling ended, value 5 for momentum
|
||||||
* scrolling cancelled and value 6 if scrolling may begin soon.
|
* scrolling cancelled and value 6 if scrolling may begin soon.
|
||||||
|
* @param[int] mods The keyboard modifiers
|
||||||
*
|
*
|
||||||
* @sa @ref scrolling
|
* @sa @ref scrolling
|
||||||
* @sa @ref glfwSetScrollCallback
|
* @sa @ref glfwSetScrollCallback
|
||||||
@@ -1322,7 +1323,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
|||||||
*
|
*
|
||||||
* @ingroup input
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||||
|
|
||||||
/*! @brief The function pointer type for key callbacks.
|
/*! @brief The function pointer type for key callbacks.
|
||||||
*
|
*
|
||||||
|
|||||||
41
kitty/glfw.c
41
kitty/glfw.c
@@ -153,6 +153,10 @@ static void
|
|||||||
window_close_callback(GLFWwindow* window) {
|
window_close_callback(GLFWwindow* window) {
|
||||||
if (!set_callback_window(window)) return;
|
if (!set_callback_window(window)) return;
|
||||||
global_state.has_pending_closes = true;
|
global_state.has_pending_closes = true;
|
||||||
|
if (global_state.callback_os_window->close_request < CONFIRMABLE_CLOSE_REQUESTED) {
|
||||||
|
global_state.callback_os_window->close_request = CONFIRMABLE_CLOSE_REQUESTED;
|
||||||
|
}
|
||||||
|
glfwSetWindowShouldClose(window, false);
|
||||||
request_tick_callback();
|
request_tick_callback();
|
||||||
global_state.callback_os_window = NULL;
|
global_state.callback_os_window = NULL;
|
||||||
}
|
}
|
||||||
@@ -287,12 +291,12 @@ cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) {
|
scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags, int mods) {
|
||||||
if (!set_callback_window(w)) return;
|
if (!set_callback_window(w)) return;
|
||||||
show_mouse_cursor(w);
|
show_mouse_cursor(w);
|
||||||
monotonic_t now = monotonic();
|
monotonic_t now = monotonic();
|
||||||
global_state.callback_os_window->last_mouse_activity_at = now;
|
global_state.callback_os_window->last_mouse_activity_at = now;
|
||||||
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags);
|
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags, mods);
|
||||||
request_tick_callback();
|
request_tick_callback();
|
||||||
global_state.callback_os_window = NULL;
|
global_state.callback_os_window = NULL;
|
||||||
}
|
}
|
||||||
@@ -323,23 +327,17 @@ window_focus_callback(GLFWwindow *w, int focused) {
|
|||||||
static int
|
static int
|
||||||
drop_callback(GLFWwindow *w, const char *mime, const char *data, size_t sz) {
|
drop_callback(GLFWwindow *w, const char *mime, const char *data, size_t sz) {
|
||||||
if (!set_callback_window(w)) return 0;
|
if (!set_callback_window(w)) return 0;
|
||||||
|
#define RETURN(x) { global_state.callback_os_window = NULL; return x; }
|
||||||
if (!data) {
|
if (!data) {
|
||||||
if (strcmp(mime, "text/uri-list") == 0) return 3;
|
if (strcmp(mime, "text/uri-list") == 0) RETURN(3);
|
||||||
if (strcmp(mime, "text/plain;charset=utf-8") == 0) return 2;
|
if (strcmp(mime, "text/plain;charset=utf-8") == 0) RETURN(2);
|
||||||
if (strcmp(mime, "text/plain") == 0) return 1;
|
if (strcmp(mime, "text/plain") == 0) RETURN(1);
|
||||||
return 0;
|
RETURN(0);
|
||||||
}
|
}
|
||||||
WINDOW_CALLBACK(on_drop, "sy#", mime, data, (int)sz);
|
WINDOW_CALLBACK(on_drop, "sy#", mime, data, (Py_ssize_t)sz);
|
||||||
request_tick_callback();
|
request_tick_callback();
|
||||||
/* PyObject *s = PyTuple_New(count); */
|
RETURN(0);
|
||||||
/* if (s) { */
|
#undef RETURN
|
||||||
/* for (int i = 0; i < count; i++) PyTuple_SET_ITEM(s, i, PyUnicode_FromString(strings[i])); */
|
|
||||||
/* WINDOW_CALLBACK(on_drop, "O", s); */
|
|
||||||
/* Py_CLEAR(s); */
|
|
||||||
/* request_tick_callback(); */
|
|
||||||
/* } */
|
|
||||||
global_state.callback_os_window = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
@@ -979,12 +977,6 @@ wakeup_main_loop() {
|
|||||||
glfwPostEmptyEvent();
|
glfwPostEmptyEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
mark_os_window_for_close(OSWindow* w, bool yes) {
|
|
||||||
global_state.has_pending_closes = true;
|
|
||||||
glfwSetWindowShouldClose(w->handle, yes);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
should_os_window_be_rendered(OSWindow* w) {
|
should_os_window_be_rendered(OSWindow* w) {
|
||||||
return (
|
return (
|
||||||
@@ -994,11 +986,6 @@ should_os_window_be_rendered(OSWindow* w) {
|
|||||||
) ? false : true;
|
) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
should_os_window_close(OSWindow* w) {
|
|
||||||
return glfwWindowShouldClose(w->handle) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
primary_monitor_size(PYNOARG) {
|
primary_monitor_size(PYNOARG) {
|
||||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
|||||||
@@ -939,7 +939,7 @@ static PyMethodDef methods[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PyMemberDef members[] = {
|
static PyMemberDef members[] = {
|
||||||
{"image_count", T_UINT, offsetof(GraphicsManager, image_count), 0, "image_count"},
|
{"image_count", T_PYSSIZET, offsetof(GraphicsManager, image_count), 0, "image_count"},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ 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 window in the current tab,
|
||||||
a new tab, or a new OS window or an overlay over the current window.
|
a new tab, or a new OS window or an overlay over the current window.
|
||||||
Note that if the current window already has an overlay, then it will
|
Note that if the current window already has an overlay, then it will
|
||||||
open a new window. The value of none means the process will be
|
open a new window. The value of background means the process will be
|
||||||
run in the background. The values clipboard and primary are meant
|
run in the background. The values clipboard and primary are meant
|
||||||
to work with :option:`launch --stdin-source` to copy data to the system
|
to work with :option:`launch --stdin-source` to copy data to the system
|
||||||
clipboard or primary selection.
|
clipboard or primary selection.
|
||||||
@@ -275,8 +275,11 @@ def launch(boss: Boss, opts: LaunchCLIOptions, args: List[str], target_tab: Opti
|
|||||||
kw['cmd'] = final_cmd
|
kw['cmd'] = final_cmd
|
||||||
if opts.type == 'overlay' and active and not active.overlay_window_id:
|
if opts.type == 'overlay' and active and not active.overlay_window_id:
|
||||||
kw['overlay_for'] = active.id
|
kw['overlay_for'] = active.id
|
||||||
if opts.stdin_source and opts.stdin_source != 'none':
|
if opts.stdin_source != 'none':
|
||||||
q = opts.stdin_source
|
q = str(opts.stdin_source)
|
||||||
|
if opts.stdin_add_formatting:
|
||||||
|
if q in ('@screen', '@screen_scrollback', '@alternate', '@alternate_scrollback'):
|
||||||
|
q = '@ansi_' + q[1:]
|
||||||
if opts.stdin_add_line_wrap_markers:
|
if opts.stdin_add_line_wrap_markers:
|
||||||
q += '_wrap'
|
q += '_wrap'
|
||||||
penv, stdin = boss.process_stdin_source(window=active, stdin=q)
|
penv, stdin = boss.process_stdin_source(window=active, stdin=q)
|
||||||
|
|||||||
693
kitty/layout.py
693
kitty/layout.py
File diff suppressed because it is too large
Load Diff
46
kitty/line.c
46
kitty/line.c
@@ -684,6 +684,33 @@ report_marker_error(PyObject *marker) {
|
|||||||
} else PyErr_Clear();
|
} else PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
apply_mark(Line *line, const attrs_type mark, index_type *cell_pos, unsigned int *match_pos) {
|
||||||
|
#define MARK { line->gpu_cells[x].attrs &= ATTRS_MASK_WITHOUT_MARK; line->gpu_cells[x].attrs |= mark; }
|
||||||
|
index_type x = *cell_pos;
|
||||||
|
MARK;
|
||||||
|
if (line->cpu_cells[x].ch) {
|
||||||
|
(*match_pos)++;
|
||||||
|
if (line->cpu_cells[x].ch == '\t') {
|
||||||
|
unsigned num_cells_to_skip_for_tab = line->cpu_cells[x].cc_idx[0];
|
||||||
|
while (num_cells_to_skip_for_tab && x + 1 < line->xnum && line->cpu_cells[x+1].ch == ' ') {
|
||||||
|
x++;
|
||||||
|
num_cells_to_skip_for_tab--;
|
||||||
|
MARK;
|
||||||
|
}
|
||||||
|
} else if ((line->gpu_cells[x].attrs & WIDTH_MASK) > 1 && x + 1 < line->xnum && !line->cpu_cells[x+1].ch) {
|
||||||
|
x++;
|
||||||
|
MARK;
|
||||||
|
} else {
|
||||||
|
for (index_type i = 0; i < arraysz(line->cpu_cells[x].cc_idx); i++) {
|
||||||
|
if (line->cpu_cells[x].cc_idx[i]) (*match_pos)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*cell_pos = x + 1;
|
||||||
|
#undef MARK
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
apply_marker(PyObject *marker, Line *line, const PyObject *text) {
|
apply_marker(PyObject *marker, Line *line, const PyObject *text) {
|
||||||
unsigned int l=0, r=0, col=0, match_pos=0;
|
unsigned int l=0, r=0, col=0, match_pos=0;
|
||||||
@@ -695,33 +722,20 @@ apply_marker(PyObject *marker, Line *line, const PyObject *text) {
|
|||||||
if (iter == NULL) { report_marker_error(marker); return; }
|
if (iter == NULL) { report_marker_error(marker); return; }
|
||||||
PyObject *match;
|
PyObject *match;
|
||||||
index_type x = 0;
|
index_type x = 0;
|
||||||
#define INCREMENT_MATCH_POS { \
|
|
||||||
if (line->cpu_cells[x].ch) { \
|
|
||||||
match_pos++; \
|
|
||||||
for (index_type i = 0; i < arraysz(line->cpu_cells[x].cc_idx); i++) { \
|
|
||||||
if (line->cpu_cells[x].cc_idx[i]) match_pos++; \
|
|
||||||
}}}
|
|
||||||
|
|
||||||
while ((match = PyIter_Next(iter)) && x < line->xnum) {
|
while ((match = PyIter_Next(iter)) && x < line->xnum) {
|
||||||
Py_DECREF(match);
|
Py_DECREF(match);
|
||||||
while (match_pos < l && x < line->xnum) {
|
while (match_pos < l && x < line->xnum) {
|
||||||
line->gpu_cells[x].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
apply_mark(line, 0, &x, &match_pos);
|
||||||
INCREMENT_MATCH_POS;
|
|
||||||
x++;
|
|
||||||
}
|
}
|
||||||
attrs_type am = (col & MARK_MASK) << MARK_SHIFT;
|
attrs_type am = (col & MARK_MASK) << MARK_SHIFT;
|
||||||
while(x < line->xnum && match_pos <= r) {
|
while(x < line->xnum && match_pos <= r) {
|
||||||
line->gpu_cells[x].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
apply_mark(line, am, &x, &match_pos);
|
||||||
line->gpu_cells[x].attrs |= am;
|
|
||||||
INCREMENT_MATCH_POS;
|
|
||||||
x++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
while(x < line->xnum) line->gpu_cells[x++].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
|
||||||
Py_DECREF(iter);
|
Py_DECREF(iter);
|
||||||
|
while(x < line->xnum) line->gpu_cells[x++].attrs &= ATTRS_MASK_WITHOUT_MARK;
|
||||||
if (PyErr_Occurred()) report_marker_error(marker);
|
if (PyErr_Occurred()) report_marker_error(marker);
|
||||||
#undef INCREMENT_MATCH_POS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from contextlib import contextmanager, suppress
|
from contextlib import contextmanager, suppress
|
||||||
from typing import Generator, List, Mapping, Optional, Tuple, Sequence
|
from typing import Generator, List, Mapping, Optional, Sequence, Tuple
|
||||||
|
|
||||||
from .borders import load_borders_program
|
from .borders import load_borders_program
|
||||||
from .boss import Boss
|
from .boss import Boss
|
||||||
@@ -29,7 +29,7 @@ from .fonts.box_drawing import set_scale
|
|||||||
from .fonts.render import set_font_family
|
from .fonts.render import set_font_family
|
||||||
from .options_stub import Options as OptionsStub
|
from .options_stub import Options as OptionsStub
|
||||||
from .utils import (
|
from .utils import (
|
||||||
detach, log_error, read_shell_environment, single_instance,
|
detach, expandvars, log_error, read_shell_environment, single_instance,
|
||||||
startup_notification_handler, unix_socket_paths
|
startup_notification_handler, unix_socket_paths
|
||||||
)
|
)
|
||||||
from .window import load_shader_programs
|
from .window import load_shader_programs
|
||||||
@@ -131,7 +131,7 @@ def _run_app(opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] =
|
|||||||
window_id = create_os_window(
|
window_id = create_os_window(
|
||||||
run_app.initial_window_size_func(opts, cached_values),
|
run_app.initial_window_size_func(opts, cached_values),
|
||||||
pre_show_callback,
|
pre_show_callback,
|
||||||
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)
|
args.cls or appname, load_all_shaders)
|
||||||
boss = Boss(opts, args, cached_values, new_os_window_trigger)
|
boss = Boss(opts, args, cached_values, new_os_window_trigger)
|
||||||
boss.start(window_id)
|
boss.start(window_id)
|
||||||
@@ -152,7 +152,7 @@ class AppRunner:
|
|||||||
|
|
||||||
def __call__(self, opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None:
|
def __call__(self, opts: OptionsStub, args: CLIOptions, bad_lines: Sequence[BadLine] = ()) -> None:
|
||||||
set_scale(opts.box_drawing_scale)
|
set_scale(opts.box_drawing_scale)
|
||||||
set_options(opts, is_wayland(), args.debug_gl, args.debug_font_fallback)
|
set_options(opts, is_wayland(), args.debug_rendering, args.debug_font_fallback)
|
||||||
set_font_family(opts, debug_font_matching=args.debug_font_fallback)
|
set_font_family(opts, debug_font_matching=args.debug_font_fallback)
|
||||||
try:
|
try:
|
||||||
_run_app(opts, args, bad_lines)
|
_run_app(opts, args, bad_lines)
|
||||||
@@ -230,6 +230,22 @@ def get_editor_from_env(shell_env: Mapping[str, str]) -> Optional[str]:
|
|||||||
return editor
|
return editor
|
||||||
|
|
||||||
|
|
||||||
|
def expand_listen_on(listen_on: str, from_config_file: bool) -> str:
|
||||||
|
listen_on = expandvars(listen_on)
|
||||||
|
if '{kitty_pid}' not in listen_on and from_config_file:
|
||||||
|
listen_on += '-{kitty_pid}'
|
||||||
|
listen_on = listen_on.replace('{kitty_pid}', str(os.getpid()))
|
||||||
|
if listen_on.startswith('unix:'):
|
||||||
|
path = listen_on[len('unix:'):]
|
||||||
|
if not path.startswith('@'):
|
||||||
|
if path.startswith('~'):
|
||||||
|
listen_on = f'unix:{os.path.expanduser(path)}'
|
||||||
|
elif not os.path.isabs(path):
|
||||||
|
import tempfile
|
||||||
|
listen_on = f'unix:{os.path.join(tempfile.gettempdir(), path)}'
|
||||||
|
return listen_on
|
||||||
|
|
||||||
|
|
||||||
def setup_environment(opts: OptionsStub, cli_opts: CLIOptions) -> None:
|
def setup_environment(opts: OptionsStub, cli_opts: CLIOptions) -> None:
|
||||||
extra_env = opts.env.copy()
|
extra_env = opts.env.copy()
|
||||||
if opts.editor == '.':
|
if opts.editor == '.':
|
||||||
@@ -241,7 +257,12 @@ def setup_environment(opts: OptionsStub, cli_opts: CLIOptions) -> None:
|
|||||||
os.environ['EDITOR'] = editor
|
os.environ['EDITOR'] = editor
|
||||||
else:
|
else:
|
||||||
os.environ['EDITOR'] = opts.editor
|
os.environ['EDITOR'] = opts.editor
|
||||||
if cli_opts.listen_on:
|
from_config_file = False
|
||||||
|
if not cli_opts.listen_on and opts.listen_on.startswith('unix:'):
|
||||||
|
cli_opts.listen_on = opts.listen_on
|
||||||
|
from_config_file = True
|
||||||
|
if cli_opts.listen_on and opts.allow_remote_control != 'n':
|
||||||
|
cli_opts.listen_on = expand_listen_on(cli_opts.listen_on, from_config_file)
|
||||||
os.environ['KITTY_LISTEN_ON'] = cli_opts.listen_on
|
os.environ['KITTY_LISTEN_ON'] = cli_opts.listen_on
|
||||||
set_default_env(extra_env)
|
set_default_env(extra_env)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "control-codes.h"
|
#include "control-codes.h"
|
||||||
#include "monotonic.h"
|
#include "monotonic.h"
|
||||||
|
|
||||||
|
extern PyTypeObject Screen_Type;
|
||||||
|
|
||||||
static MouseShape mouse_cursor_shape = BEAM;
|
static MouseShape mouse_cursor_shape = BEAM;
|
||||||
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
|
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
|
||||||
|
|
||||||
@@ -95,37 +97,37 @@ encode_mouse_event(Window *w, int button, MouseAction action, int mods) {
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
static inline double
|
static inline unsigned int
|
||||||
window_left(Window *w, OSWindow *os_window) {
|
window_left(Window *w) {
|
||||||
return w->geometry.left - OPT(window_padding_width) * (os_window->logical_dpi_x / 72.0);
|
return w->geometry.left - w->padding.left;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double
|
static inline unsigned int
|
||||||
window_right(Window *w, OSWindow *os_window) {
|
window_right(Window *w) {
|
||||||
return w->geometry.right + OPT(window_padding_width) * (os_window->logical_dpi_x / 72.0);
|
return w->geometry.right + w->padding.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double
|
static inline unsigned int
|
||||||
window_top(Window *w, OSWindow *os_window) {
|
window_top(Window *w) {
|
||||||
return w->geometry.top - OPT(window_padding_width) * (os_window->logical_dpi_y / 72.0);
|
return w->geometry.top - w->padding.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double
|
static inline unsigned int
|
||||||
window_bottom(Window *w, OSWindow *os_window) {
|
window_bottom(Window *w) {
|
||||||
return w->geometry.bottom + OPT(window_padding_width) * (os_window->logical_dpi_y / 72.0);
|
return w->geometry.bottom + w->padding.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
contains_mouse(Window *w, OSWindow *os_window) {
|
contains_mouse(Window *w) {
|
||||||
double x = global_state.callback_os_window->mouse_x, y = global_state.callback_os_window->mouse_y;
|
double x = global_state.callback_os_window->mouse_x, y = global_state.callback_os_window->mouse_y;
|
||||||
return (w->visible && window_left(w, os_window) <= x && x <= window_right(w, os_window) && window_top(w, os_window) <= y && y <= window_bottom(w, os_window));
|
return (w->visible && window_left(w) <= x && x <= window_right(w) && window_top(w) <= y && y <= window_bottom(w));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline double
|
static inline double
|
||||||
distance_to_window(Window *w, OSWindow *os_window) {
|
distance_to_window(Window *w) {
|
||||||
double x = global_state.callback_os_window->mouse_x, y = global_state.callback_os_window->mouse_y;
|
double x = global_state.callback_os_window->mouse_x, y = global_state.callback_os_window->mouse_y;
|
||||||
double cx = (window_left(w, os_window) + window_right(w, os_window)) / 2.0;
|
double cx = (window_left(w) + window_right(w)) / 2.0;
|
||||||
double cy = (window_top(w, os_window) + window_bottom(w, os_window)) / 2.0;
|
double cy = (window_top(w) + window_bottom(w)) / 2.0;
|
||||||
return (x - cx) * (x - cx) + (y - cy) * (y - cy);
|
return (x - cx) * (x - cx) + (y - cy) * (y - cy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +142,7 @@ cell_for_pos(Window *w, unsigned int *x, unsigned int *y, bool *in_left_half_of_
|
|||||||
bool in_left_half = true;
|
bool in_left_half = true;
|
||||||
double mouse_x = global_state.callback_os_window->mouse_x;
|
double mouse_x = global_state.callback_os_window->mouse_x;
|
||||||
double mouse_y = global_state.callback_os_window->mouse_y;
|
double mouse_y = global_state.callback_os_window->mouse_y;
|
||||||
double left = window_left(w, os_window), top = window_top(w, os_window), right = window_right(w, os_window), bottom = window_bottom(w, os_window);
|
double left = window_left(w), top = window_top(w), right = window_right(w), bottom = window_bottom(w);
|
||||||
if (clamp_to_window) {
|
if (clamp_to_window) {
|
||||||
mouse_x = MIN(MAX(mouse_x, left), right);
|
mouse_x = MIN(MAX(mouse_x, left), right);
|
||||||
mouse_y = MIN(MAX(mouse_y, top), bottom);
|
mouse_y = MIN(MAX(mouse_y, top), bottom);
|
||||||
@@ -511,8 +513,9 @@ window_for_event(unsigned int *window_idx, bool *in_tab_bar) {
|
|||||||
if (!*in_tab_bar && global_state.callback_os_window->num_tabs > 0) {
|
if (!*in_tab_bar && global_state.callback_os_window->num_tabs > 0) {
|
||||||
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 (unsigned int i = 0; i < t->num_windows; i++) {
|
for (unsigned int i = 0; i < t->num_windows; i++) {
|
||||||
if (contains_mouse(t->windows + i, global_state.callback_os_window) && t->windows[i].render_data.screen) {
|
if (contains_mouse(t->windows + i) && t->windows[i].render_data.screen) {
|
||||||
*window_idx = i; return t->windows + i;
|
*window_idx = i;
|
||||||
|
return t->windows + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -527,8 +530,10 @@ closest_window_for_event(unsigned int *window_idx) {
|
|||||||
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 (unsigned int i = 0; i < t->num_windows; i++) {
|
for (unsigned int i = 0; i < t->num_windows; i++) {
|
||||||
Window *w = t->windows + i;
|
Window *w = t->windows + i;
|
||||||
double d = distance_to_window(w, global_state.callback_os_window);
|
if (w->visible) {
|
||||||
if (d < closest_distance) { ans = w; closest_distance = d; *window_idx = i; }
|
double d = distance_to_window(w);
|
||||||
|
if (d < closest_distance) { ans = w; closest_distance = d; *window_idx = i; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ans;
|
return ans;
|
||||||
@@ -608,7 +613,7 @@ mouse_event(int button, int modifiers, int action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
scroll_event(double UNUSED xoffset, double yoffset, int flags) {
|
scroll_event(double UNUSED xoffset, double yoffset, int flags, int modifiers) {
|
||||||
bool in_tab_bar;
|
bool in_tab_bar;
|
||||||
static id_type window_for_momentum_scroll = 0;
|
static id_type window_for_momentum_scroll = 0;
|
||||||
static bool main_screen_for_momentum_scroll = false;
|
static bool main_screen_for_momentum_scroll = false;
|
||||||
@@ -685,7 +690,7 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
|
|||||||
screen_history_scroll(screen, abs(s), upwards);
|
screen_history_scroll(screen, abs(s), upwards);
|
||||||
} else {
|
} else {
|
||||||
if (screen->modes.mouse_tracking_mode) {
|
if (screen->modes.mouse_tracking_mode) {
|
||||||
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0);
|
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, modifiers);
|
||||||
if (sz > 0) {
|
if (sz > 0) {
|
||||||
mouse_event_buf[sz] = 0;
|
mouse_event_buf[sz] = 0;
|
||||||
for (s = abs(s); s > 0; s--) {
|
for (s = abs(s); s > 0; s--) {
|
||||||
@@ -698,6 +703,25 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
send_mouse_event(PyObject *self UNUSED, PyObject *args) {
|
||||||
|
Screen *screen;
|
||||||
|
unsigned int x, y;
|
||||||
|
int button, action, mods;
|
||||||
|
if (!PyArg_ParseTuple(args, "O!IIiii", &Screen_Type, &screen, &x, &y, &button, &action, &mods)) return NULL;
|
||||||
|
|
||||||
|
MouseTrackingMode mode = screen->modes.mouse_tracking_mode;
|
||||||
|
if (mode == ANY_MODE || (mode == MOTION_MODE && action != MOVE) || (mode == BUTTON_MODE && (action == PRESS || action == RELEASE))) {
|
||||||
|
int sz = encode_mouse_event_impl(x + 1, y + 1, screen->modes.mouse_tracking_protocol, button, action, mods);
|
||||||
|
if (sz > 0) {
|
||||||
|
mouse_event_buf[sz] = 0;
|
||||||
|
write_escape_code_to_child(screen, CSI, mouse_event_buf);
|
||||||
|
Py_RETURN_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
test_encode_mouse(PyObject *self UNUSED, PyObject *args) {
|
test_encode_mouse(PyObject *self UNUSED, PyObject *args) {
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
@@ -732,6 +756,7 @@ send_mock_mouse_event_to_window(PyObject *self UNUSED, PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
|
METHODB(send_mouse_event, METH_VARARGS),
|
||||||
METHODB(test_encode_mouse, METH_VARARGS),
|
METHODB(test_encode_mouse, METH_VARARGS),
|
||||||
METHODB(send_mock_mouse_event_to_window, METH_VARARGS),
|
METHODB(send_mock_mouse_event_to_window, METH_VARARGS),
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
@@ -739,6 +764,10 @@ static PyMethodDef module_methods[] = {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
init_mouse(PyObject *module) {
|
init_mouse(PyObject *module) {
|
||||||
|
PyModule_AddIntMacro(module, PRESS);
|
||||||
|
PyModule_AddIntMacro(module, RELEASE);
|
||||||
|
PyModule_AddIntMacro(module, DRAG);
|
||||||
|
PyModule_AddIntMacro(module, MOVE);
|
||||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
28
kitty/parse-graphics-command.h
generated
28
kitty/parse-graphics-command.h
generated
@@ -11,7 +11,7 @@ static inline void parse_graphics_code(Screen *screen,
|
|||||||
unsigned int i, code;
|
unsigned int i, code;
|
||||||
uint64_t lcode;
|
uint64_t lcode;
|
||||||
bool is_negative;
|
bool is_negative;
|
||||||
zero_at_ptr(&g);
|
memset(&g, 0, sizeof(g));
|
||||||
size_t sz;
|
size_t sz;
|
||||||
static uint8_t payload[4096];
|
static uint8_t payload[4096];
|
||||||
|
|
||||||
@@ -39,6 +39,8 @@ static inline void parse_graphics_code(Screen *screen,
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum KEYS key = 'a';
|
enum KEYS key = 'a';
|
||||||
|
if (screen->parser_buf[pos] == ';')
|
||||||
|
state = AFTER_VALUE;
|
||||||
|
|
||||||
while (pos < screen->parser_buf_pos) {
|
while (pos < screen->parser_buf_pos) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -129,8 +131,8 @@ static inline void parse_graphics_code(Screen *screen,
|
|||||||
|
|
||||||
case action: {
|
case action: {
|
||||||
g.action = screen->parser_buf[pos++] & 0xff;
|
g.action = screen->parser_buf[pos++] & 0xff;
|
||||||
if (g.action != 'q' && g.action != 'd' && g.action != 't' &&
|
if (g.action != 't' && g.action != 'd' && g.action != 'p' &&
|
||||||
g.action != 'T' && g.action != 'p') {
|
g.action != 'q' && g.action != 'T') {
|
||||||
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
||||||
"value for action: 0x%x",
|
"value for action: 0x%x",
|
||||||
g.action);
|
g.action);
|
||||||
@@ -140,14 +142,14 @@ static inline void parse_graphics_code(Screen *screen,
|
|||||||
|
|
||||||
case delete_action: {
|
case delete_action: {
|
||||||
g.delete_action = screen->parser_buf[pos++] & 0xff;
|
g.delete_action = screen->parser_buf[pos++] & 0xff;
|
||||||
if (g.delete_action != 'q' && g.delete_action != 'c' &&
|
if (g.delete_action != 'X' && g.delete_action != 'y' &&
|
||||||
g.delete_action != 'Z' && g.delete_action != 'z' &&
|
g.delete_action != 'i' && g.delete_action != 'I' &&
|
||||||
g.delete_action != 'x' && g.delete_action != 'X' &&
|
g.delete_action != 'A' && g.delete_action != 'p' &&
|
||||||
g.delete_action != 'I' && g.delete_action != 'i' &&
|
g.delete_action != 'Y' && g.delete_action != 'z' &&
|
||||||
g.delete_action != 'P' && g.delete_action != 'y' &&
|
g.delete_action != 'a' && g.delete_action != 'P' &&
|
||||||
g.delete_action != 'a' && g.delete_action != 'A' &&
|
g.delete_action != 'x' && g.delete_action != 'q' &&
|
||||||
g.delete_action != 'Q' && g.delete_action != 'C' &&
|
g.delete_action != 'Z' && g.delete_action != 'Q' &&
|
||||||
g.delete_action != 'p' && g.delete_action != 'Y') {
|
g.delete_action != 'c' && g.delete_action != 'C') {
|
||||||
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
||||||
"value for delete_action: 0x%x",
|
"value for delete_action: 0x%x",
|
||||||
g.delete_action);
|
g.delete_action);
|
||||||
@@ -157,8 +159,8 @@ static inline void parse_graphics_code(Screen *screen,
|
|||||||
|
|
||||||
case transmission_type: {
|
case transmission_type: {
|
||||||
g.transmission_type = screen->parser_buf[pos++] & 0xff;
|
g.transmission_type = screen->parser_buf[pos++] & 0xff;
|
||||||
if (g.transmission_type != 's' && g.transmission_type != 'f' &&
|
if (g.transmission_type != 'f' && g.transmission_type != 'd' &&
|
||||||
g.transmission_type != 't' && g.transmission_type != 'd') {
|
g.transmission_type != 's' && g.transmission_type != 't') {
|
||||||
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
|
||||||
"value for transmission_type: 0x%x",
|
"value for transmission_type: 0x%x",
|
||||||
g.transmission_type);
|
g.transmission_type);
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ class Kitten(RemoteCommand):
|
|||||||
'Run a kitten over the specified window (active window by default).'
|
'Run a kitten over the specified window (active window by default).'
|
||||||
' The :italic:`kitten_name` can be either the name of a builtin kitten'
|
' The :italic:`kitten_name` can be either the name of a builtin kitten'
|
||||||
' or the path to a python file containing a custom kitten. If a relative path'
|
' or the path to a python file containing a custom kitten. If a relative path'
|
||||||
' is used it is searched for in the kitty config directory.'
|
' is used it is searched for in the kitty config directory. If the kitten is a'
|
||||||
|
' no_ui kitten and its handle response method returns a string or boolean, this'
|
||||||
|
' is printed out to stdout.'
|
||||||
)
|
)
|
||||||
options_spec = MATCH_WINDOW_OPTION
|
options_spec = MATCH_WINDOW_OPTION
|
||||||
argspec = 'kitten_name'
|
argspec = 'kitten_name'
|
||||||
@@ -43,10 +45,13 @@ class Kitten(RemoteCommand):
|
|||||||
windows = list(boss.match_windows(match))
|
windows = list(boss.match_windows(match))
|
||||||
if not windows:
|
if not windows:
|
||||||
raise MatchError(match)
|
raise MatchError(match)
|
||||||
|
retval = None
|
||||||
for window in windows:
|
for window in windows:
|
||||||
if window:
|
if window:
|
||||||
boss._run_kitten(payload_get('kitten'), args=tuple(payload_get('args') or ()), window=window)
|
retval = boss._run_kitten(payload_get('kitten'), args=tuple(payload_get('args') or ()), window=window)
|
||||||
break
|
break
|
||||||
|
if isinstance(retval, (str, bool)):
|
||||||
|
return retval
|
||||||
|
|
||||||
|
|
||||||
kitten = Kitten()
|
kitten = Kitten()
|
||||||
|
|||||||
124
kitty/rc/set_spacing.py
Normal file
124
kitty/rc/set_spacing.py
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, Dict, Optional, List
|
||||||
|
|
||||||
|
from .base import (
|
||||||
|
MATCH_TAB_OPTION, MATCH_WINDOW_OPTION, ArgsType, Boss, PayloadGetType,
|
||||||
|
PayloadType, RCOptions, RemoteCommand, ResponseType, Window
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from kitty.cli_stub import SetSpacingRCOptions as CLIOptions
|
||||||
|
from kitty.options_stub import Options
|
||||||
|
|
||||||
|
|
||||||
|
def patch_window_edges(w: Window, s: Dict[str, Optional[float]]) -> None:
|
||||||
|
for k, v in s.items():
|
||||||
|
which, edge = k.lower().split('-', 1)
|
||||||
|
if edge == 'left':
|
||||||
|
w.patch_edge_width(which, 'left', v)
|
||||||
|
elif edge == 'right':
|
||||||
|
w.patch_edge_width(which, 'right', v)
|
||||||
|
elif edge == 'top':
|
||||||
|
w.patch_edge_width(which, 'top', v)
|
||||||
|
elif edge == 'bottom':
|
||||||
|
w.patch_edge_width(which, 'bottom', v)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_configured_edges(opts: 'Options', s: Dict[str, Optional[float]]) -> None:
|
||||||
|
for k, val in s.items():
|
||||||
|
if val is None:
|
||||||
|
continue
|
||||||
|
which, edge = k.lower().split('-', 1)
|
||||||
|
q = f'window_{which}_width'
|
||||||
|
new_edges = getattr(opts, q)._replace(**{edge: val})
|
||||||
|
setattr(opts, q, new_edges)
|
||||||
|
|
||||||
|
|
||||||
|
class SetSpacing(RemoteCommand):
|
||||||
|
|
||||||
|
'''
|
||||||
|
settings+: An object mapping margins/paddings using canonical form {'margin-top': 50, 'padding-left': null} etc
|
||||||
|
match_window: Window to change colors in
|
||||||
|
match_tab: Tab to change colors in
|
||||||
|
all: Boolean indicating change colors everywhere or not
|
||||||
|
configured: Boolean indicating whether to change the configured colors. Must be True if reset is True
|
||||||
|
'''
|
||||||
|
|
||||||
|
short_desc = 'Set window padding and margins'
|
||||||
|
desc = (
|
||||||
|
'Set the padding and margins for the specified windows (defaults to active window).'
|
||||||
|
' For example: margin=20 or padding-left=10 or margin-h=30. The shorthand form sets'
|
||||||
|
' all values, the :code:`*-h` and :code:`*-v` variants set horizontal and vertical values.'
|
||||||
|
' The special value "default" resets to using the default value.'
|
||||||
|
' If you specify a tab rather than a window, all windows in that tab are affected.'
|
||||||
|
)
|
||||||
|
options_spec = '''\
|
||||||
|
--all -a
|
||||||
|
type=bool-set
|
||||||
|
By default, settings are only changed for the currently active window. This option will
|
||||||
|
cause colors to be changed in all windows.
|
||||||
|
|
||||||
|
|
||||||
|
--configured -c
|
||||||
|
type=bool-set
|
||||||
|
Also change the configured padding and margins (i.e. the settings kitty will use for new
|
||||||
|
windows).
|
||||||
|
''' + '\n\n' + MATCH_WINDOW_OPTION + '\n\n' + MATCH_TAB_OPTION.replace('--match -m', '--match-tab -t')
|
||||||
|
argspec = 'MARGIN_OR_PADDING ...'
|
||||||
|
|
||||||
|
def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType:
|
||||||
|
settings: Dict[str, Optional[float]] = {}
|
||||||
|
mapper: Dict[str, List[str]] = {}
|
||||||
|
for q in ('margin', 'padding'):
|
||||||
|
mapper[q] = f'{q}-left {q}-top {q}-right {q}-bottom'.split()
|
||||||
|
mapper[f'{q}-h'] = mapper[f'{q}-horizontal'] = f'{q}-left {q}-right'.split()
|
||||||
|
mapper[f'{q}-v'] = mapper[f'{q}-vertical'] = f'{q}-top {q}-bottom'.split()
|
||||||
|
for edge in ('left', 'top', 'right', 'bottom'):
|
||||||
|
mapper[f'{q}-{edge}'] = [f'{q}-{edge}']
|
||||||
|
if not args:
|
||||||
|
self.fatal('At least one setting must be specified')
|
||||||
|
for spec in args:
|
||||||
|
parts = spec.split('=', 1)
|
||||||
|
if len(parts) != 2:
|
||||||
|
self.fatal(f'{spec} is not a valid setting')
|
||||||
|
which = mapper.get(parts[0].lower())
|
||||||
|
if not which:
|
||||||
|
self.fatal(f'{parts[0]} is not a valid edge specification')
|
||||||
|
if parts[1].lower() == 'default':
|
||||||
|
val = None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
val = float(parts[1])
|
||||||
|
except Exception:
|
||||||
|
self.fatal(f'{parts[1]} is not a number')
|
||||||
|
for q in which:
|
||||||
|
settings[q] = val
|
||||||
|
ans = {
|
||||||
|
'match_window': opts.match, 'match_tab': opts.match_tab,
|
||||||
|
'all': opts.all, 'configured': opts.configured,
|
||||||
|
'settings': settings
|
||||||
|
}
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType:
|
||||||
|
windows = self.windows_for_payload(boss, window, payload_get)
|
||||||
|
settings: Dict[str, Optional[float]] = payload_get('settings')
|
||||||
|
dirtied_tabs = {}
|
||||||
|
if payload_get('configured'):
|
||||||
|
patch_configured_edges(boss.opts, settings)
|
||||||
|
|
||||||
|
for w in windows:
|
||||||
|
patch_window_edges(w, settings)
|
||||||
|
tab = w.tabref()
|
||||||
|
if tab is not None:
|
||||||
|
dirtied_tabs[tab.id] = tab
|
||||||
|
|
||||||
|
for tab in dirtied_tabs.values():
|
||||||
|
tab.relayout()
|
||||||
|
|
||||||
|
|
||||||
|
set_spacing = SetSpacing()
|
||||||
115
kitty/screen.c
115
kitty/screen.c
@@ -357,6 +357,31 @@ selection_has_screen_line(Selection *s, int y) {
|
|||||||
return top <= y && y <= bottom;
|
return top <= y && y <= bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_flag_pair(char_type a, char_type b) {
|
||||||
|
return is_flag_codepoint(a) && is_flag_codepoint(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
draw_second_flag_codepoint(Screen *self, char_type ch) {
|
||||||
|
index_type xpos = 0, ypos = 0;
|
||||||
|
if (self->cursor->x > 1) {
|
||||||
|
ypos = self->cursor->y;
|
||||||
|
xpos = self->cursor->x - 2;
|
||||||
|
} else if (self->cursor->y > 0 && self->columns > 1) {
|
||||||
|
ypos = self->cursor->y - 1;
|
||||||
|
xpos = self->columns - 2;
|
||||||
|
} else return false;
|
||||||
|
|
||||||
|
linebuf_init_line(self->linebuf, ypos);
|
||||||
|
CPUCell *cell = self->linebuf->line->cpu_cells + xpos;
|
||||||
|
if (!is_flag_pair(cell->ch, ch) || cell->cc_idx[0]) return false;
|
||||||
|
line_add_combining_char(self->linebuf->line, ch, xpos);
|
||||||
|
self->is_dirty = true;
|
||||||
|
if (selection_has_screen_line(&self->selection, ypos)) self->selection = EMPTY_SELECTION;
|
||||||
|
linebuf_mark_line_dirty(self->linebuf, ypos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
draw_combining_char(Screen *self, char_type ch) {
|
draw_combining_char(Screen *self, char_type ch) {
|
||||||
bool has_prev_char = false;
|
bool has_prev_char = false;
|
||||||
@@ -372,6 +397,17 @@ draw_combining_char(Screen *self, char_type ch) {
|
|||||||
xpos = self->columns - 1;
|
xpos = self->columns - 1;
|
||||||
has_prev_char = true;
|
has_prev_char = true;
|
||||||
}
|
}
|
||||||
|
if (self->cursor->x > 0) {
|
||||||
|
ypos = self->cursor->y;
|
||||||
|
linebuf_init_line(self->linebuf, ypos);
|
||||||
|
xpos = self->cursor->x - 1;
|
||||||
|
has_prev_char = true;
|
||||||
|
} else if (self->cursor->y > 0) {
|
||||||
|
ypos = self->cursor->y - 1;
|
||||||
|
linebuf_init_line(self->linebuf, ypos);
|
||||||
|
xpos = self->columns - 1;
|
||||||
|
has_prev_char = true;
|
||||||
|
}
|
||||||
if (has_prev_char) {
|
if (has_prev_char) {
|
||||||
line_add_combining_char(self->linebuf->line, ch, xpos);
|
line_add_combining_char(self->linebuf->line, ch, xpos);
|
||||||
self->is_dirty = true;
|
self->is_dirty = true;
|
||||||
@@ -412,6 +448,10 @@ screen_draw(Screen *self, uint32_t och) {
|
|||||||
draw_combining_char(self, ch);
|
draw_combining_char(self, ch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool is_flag = is_flag_codepoint(ch);
|
||||||
|
if (UNLIKELY(is_flag)) {
|
||||||
|
if (draw_second_flag_codepoint(self, ch)) return;
|
||||||
|
}
|
||||||
int char_width = wcwidth_std(ch);
|
int char_width = wcwidth_std(ch);
|
||||||
if (UNLIKELY(char_width < 1)) {
|
if (UNLIKELY(char_width < 1)) {
|
||||||
if (char_width == 0) return;
|
if (char_width == 0) return;
|
||||||
@@ -1827,37 +1867,54 @@ screen_wcswidth(PyObject UNUSED *self, PyObject *str) {
|
|||||||
unsigned long ans = 0;
|
unsigned long ans = 0;
|
||||||
char_type prev_ch = 0;
|
char_type prev_ch = 0;
|
||||||
int prev_width = 0;
|
int prev_width = 0;
|
||||||
bool in_sgr = false;
|
typedef enum {NORMAL, IN_SGR, FLAG_PAIR_STARTED} WCSState;
|
||||||
|
WCSState state = NORMAL;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
char_type ch = PyUnicode_READ(kind, data, i);
|
char_type ch = PyUnicode_READ(kind, data, i);
|
||||||
if (in_sgr) {
|
switch(state) {
|
||||||
if (ch == 'm') in_sgr = false;
|
case IN_SGR: {
|
||||||
continue;
|
if (ch == 'm') state = NORMAL;
|
||||||
}
|
} continue;
|
||||||
if (ch == 0x1b && i + 1 < len && PyUnicode_READ(kind, data, i + 1) == '[') { in_sgr = true; continue; }
|
|
||||||
if (ch == 0xfe0f) {
|
case FLAG_PAIR_STARTED: {
|
||||||
if (is_emoji_presentation_base(prev_ch) && prev_width == 1) {
|
state = NORMAL;
|
||||||
ans += 1;
|
if (is_flag_pair(prev_ch, ch)) break;
|
||||||
prev_width = 2;
|
} /* fallthrough */
|
||||||
} else prev_width = 0;
|
|
||||||
} else if (ch == 0xfe0e) {
|
case NORMAL: {
|
||||||
if (is_emoji_presentation_base(prev_ch) && prev_width == 2) {
|
if (ch == 0x1b && i + 1 < len && PyUnicode_READ(kind, data, i + 1) == '[') { state = IN_SGR; continue; }
|
||||||
ans -= 1;
|
switch(ch) {
|
||||||
prev_width = 1;
|
case 0xfe0f: {
|
||||||
} else prev_width = 0;
|
if (is_emoji_presentation_base(prev_ch) && prev_width == 1) {
|
||||||
} else {
|
ans += 1;
|
||||||
int w = wcwidth_std(ch);
|
prev_width = 2;
|
||||||
switch(w) {
|
} else prev_width = 0;
|
||||||
case -1:
|
} break;
|
||||||
case 0:
|
|
||||||
prev_width = 0; break;
|
case 0xfe0e: {
|
||||||
case 2:
|
if (is_emoji_presentation_base(prev_ch) && prev_width == 2) {
|
||||||
prev_width = 2; break;
|
ans -= 1;
|
||||||
default:
|
prev_width = 1;
|
||||||
prev_width = 1; break;
|
} else prev_width = 0;
|
||||||
}
|
} break;
|
||||||
ans += prev_width;
|
|
||||||
}
|
default: {
|
||||||
|
if (is_flag_codepoint(ch)) state = FLAG_PAIR_STARTED;
|
||||||
|
int w = wcwidth_std(ch);
|
||||||
|
switch(w) {
|
||||||
|
case -1:
|
||||||
|
case 0:
|
||||||
|
prev_width = 0; break;
|
||||||
|
case 2:
|
||||||
|
prev_width = 2; break;
|
||||||
|
default:
|
||||||
|
prev_width = 1; break;
|
||||||
|
}
|
||||||
|
ans += prev_width;
|
||||||
|
} break;
|
||||||
|
} break; // switch(ch)
|
||||||
|
} break; // case NORMAL
|
||||||
|
} // switch(state)
|
||||||
prev_ch = ch;
|
prev_ch = ch;
|
||||||
}
|
}
|
||||||
return PyLong_FromUnsignedLong(ans);
|
return PyLong_FromUnsignedLong(ans);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from typing import Generator, List, NamedTuple, Optional, Tuple, Union
|
|||||||
|
|
||||||
from .cli_stub import CLIOptions
|
from .cli_stub import CLIOptions
|
||||||
from .config_data import to_layout_names
|
from .config_data import to_layout_names
|
||||||
from .constants import kitty_exe
|
from .constants import FloatEdges, kitty_exe
|
||||||
from .layout import all_layouts
|
from .layout import all_layouts
|
||||||
from .options_stub import Options
|
from .options_stub import Options
|
||||||
from .typing import SpecialWindowInstance
|
from .typing import SpecialWindowInstance
|
||||||
@@ -19,8 +19,8 @@ class WindowSizeOpts(NamedTuple):
|
|||||||
|
|
||||||
initial_window_width: Tuple[int, str]
|
initial_window_width: Tuple[int, str]
|
||||||
initial_window_height: Tuple[int, str]
|
initial_window_height: Tuple[int, str]
|
||||||
window_margin_width: float
|
window_margin_width: FloatEdges
|
||||||
window_padding_width: float
|
window_padding_width: FloatEdges
|
||||||
remember_window_size: bool
|
remember_window_size: bool
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class Session:
|
|||||||
self.tabs[-1].next_title = title.strip()
|
self.tabs[-1].next_title = title.strip()
|
||||||
|
|
||||||
def set_layout(self, val: str) -> None:
|
def set_layout(self, val: str) -> None:
|
||||||
if val not in all_layouts:
|
if val.partition(':')[0] not in all_layouts:
|
||||||
raise ValueError('{} is not a valid layout'.format(val))
|
raise ValueError('{} is not a valid layout'.format(val))
|
||||||
self.tabs[-1].layout = val
|
self.tabs[-1].layout = val
|
||||||
|
|
||||||
|
|||||||
@@ -465,7 +465,11 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind
|
|||||||
bind_program(CELL_BG_PROGRAM);
|
bind_program(CELL_BG_PROGRAM);
|
||||||
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3);
|
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 3);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
|
||||||
} else if (OPT(background_tint) > 0) draw_tint(false, screen, xstart, ystart, width, height);
|
} else if (OPT(background_tint) > 0) {
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||||
|
draw_tint(false, screen, xstart, ystart, width, height);
|
||||||
|
BLEND_ONTO_OPAQUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (screen->grman->num_of_below_refs || has_bgimage(w)) {
|
if (screen->grman->num_of_below_refs || has_bgimage(w)) {
|
||||||
if (screen->grman->num_of_below_refs) draw_graphics(
|
if (screen->grman->num_of_below_refs) draw_graphics(
|
||||||
|
|||||||
@@ -27,13 +27,26 @@ GlobalState global_state = {{0}};
|
|||||||
#define END_WITH_OS_WINDOW break; }}
|
#define END_WITH_OS_WINDOW break; }}
|
||||||
|
|
||||||
#define WITH_TAB(os_window_id, tab_id) \
|
#define WITH_TAB(os_window_id, tab_id) \
|
||||||
for (size_t o = 0; o < global_state.num_os_windows; o++) { \
|
for (size_t o = 0, tab_found = 0; o < global_state.num_os_windows && !tab_found; o++) { \
|
||||||
OSWindow *osw = global_state.os_windows + o; \
|
OSWindow *osw = global_state.os_windows + o; \
|
||||||
if (osw->id == os_window_id) { \
|
if (osw->id == os_window_id) { \
|
||||||
for (size_t t = 0; t < osw->num_tabs; t++) { \
|
for (size_t t = 0; t < osw->num_tabs; t++) { \
|
||||||
if (osw->tabs[t].id == tab_id) { \
|
if (osw->tabs[t].id == tab_id) { \
|
||||||
Tab *tab = osw->tabs + t;
|
Tab *tab = osw->tabs + t;
|
||||||
#define END_WITH_TAB break; }}}}
|
#define END_WITH_TAB tab_found = 1; break; }}}}
|
||||||
|
|
||||||
|
#define WITH_WINDOW(os_window_id, tab_id, window_id) \
|
||||||
|
for (size_t o = 0, window_found = 0; o < global_state.num_os_windows && !window_found; o++) { \
|
||||||
|
OSWindow *osw = global_state.os_windows + o; \
|
||||||
|
if (osw->id == os_window_id) { \
|
||||||
|
for (size_t t = 0; t < osw->num_tabs && !window_found; t++) { \
|
||||||
|
if (osw->tabs[t].id == tab_id) { \
|
||||||
|
Tab *tab = osw->tabs + t; \
|
||||||
|
for (size_t w = 0; w < tab->num_windows; w++) { \
|
||||||
|
if (tab->windows[w].id == window_id) { \
|
||||||
|
Window *window = tab->windows + w;
|
||||||
|
#define END_WITH_WINDOW window_found = 1; break; }}}}}}
|
||||||
|
|
||||||
|
|
||||||
#define WITH_OS_WINDOW_REFS \
|
#define WITH_OS_WINDOW_REFS \
|
||||||
id_type cb_window_id = 0, focused_window_id = 0; \
|
id_type cb_window_id = 0, focused_window_id = 0; \
|
||||||
@@ -201,6 +214,27 @@ update_window_title(id_type os_window_id, id_type tab_id, id_type window_id, PyO
|
|||||||
END_WITH_TAB;
|
END_WITH_TAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_os_window_title_from_window(Window *w, OSWindow *os_window) {
|
||||||
|
if (w->title && w->title != os_window->window_title) {
|
||||||
|
Py_XDECREF(os_window->window_title);
|
||||||
|
os_window->window_title = w->title;
|
||||||
|
Py_INCREF(os_window->window_title);
|
||||||
|
set_os_window_title(os_window, PyUnicode_AsUTF8(w->title));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
update_os_window_title(OSWindow *os_window) {
|
||||||
|
if (os_window->num_tabs) {
|
||||||
|
Tab *tab = os_window->tabs + os_window->active_tab;
|
||||||
|
if (tab->num_windows) {
|
||||||
|
Window *w = tab->windows + tab->active_window;
|
||||||
|
set_os_window_title_from_window(w, os_window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
destroy_window(Window *w) {
|
destroy_window(Window *w) {
|
||||||
Py_CLEAR(w->render_data.screen); Py_CLEAR(w->title);
|
Py_CLEAR(w->render_data.screen); Py_CLEAR(w->title);
|
||||||
@@ -410,6 +444,14 @@ os_window_regions(OSWindow *os_window, Region *central, Region *tab_bar) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mark_os_window_for_close(OSWindow* w, CloseRequest cr) {
|
||||||
|
global_state.has_pending_closes = true;
|
||||||
|
w->close_request = cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Python API {{{
|
// Python API {{{
|
||||||
#define PYWRAP0(name) static PyObject* py##name(PYNOARG)
|
#define PYWRAP0(name) static PyObject* py##name(PYNOARG)
|
||||||
@@ -577,14 +619,14 @@ PYWRAP1(handle_for_window_id) {
|
|||||||
|
|
||||||
PYWRAP1(set_options) {
|
PYWRAP1(set_options) {
|
||||||
PyObject *ret, *opts;
|
PyObject *ret, *opts;
|
||||||
int is_wayland = 0, debug_gl = 0, debug_font_fallback = 0;
|
int is_wayland = 0, debug_rendering = 0, debug_font_fallback = 0;
|
||||||
PA("O|ppp", &opts, &is_wayland, &debug_gl, &debug_font_fallback);
|
PA("O|ppp", &opts, &is_wayland, &debug_rendering, &debug_font_fallback);
|
||||||
global_state.is_wayland = is_wayland ? true : false;
|
global_state.is_wayland = is_wayland ? true : false;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
global_state.has_render_frames = true;
|
global_state.has_render_frames = true;
|
||||||
#endif
|
#endif
|
||||||
if (global_state.is_wayland) global_state.has_render_frames = true;
|
if (global_state.is_wayland) global_state.has_render_frames = true;
|
||||||
global_state.debug_gl = debug_gl ? true : false;
|
global_state.debug_rendering = debug_rendering ? true : false;
|
||||||
global_state.debug_font_fallback = debug_font_fallback ? true : false;
|
global_state.debug_font_fallback = debug_font_fallback ? true : false;
|
||||||
#define GA(name) ret = PyObject_GetAttrString(opts, #name); if (ret == NULL) return NULL;
|
#define GA(name) ret = PyObject_GetAttrString(opts, #name); if (ret == NULL) return NULL;
|
||||||
#define SS(name, dest, convert) { GA(name); dest = convert(ret); Py_DECREF(ret); if (PyErr_Occurred()) return NULL; }
|
#define SS(name, dest, convert) { GA(name); dest = convert(ret); Py_DECREF(ret); if (PyErr_Occurred()) return NULL; }
|
||||||
@@ -603,7 +645,6 @@ PYWRAP1(set_options) {
|
|||||||
S(dim_opacity, PyFloat_AsFloat);
|
S(dim_opacity, PyFloat_AsFloat);
|
||||||
S(dynamic_background_opacity, PyObject_IsTrue);
|
S(dynamic_background_opacity, PyObject_IsTrue);
|
||||||
S(inactive_text_alpha, PyFloat_AsFloat);
|
S(inactive_text_alpha, PyFloat_AsFloat);
|
||||||
S(window_padding_width, PyFloat_AsFloat);
|
|
||||||
S(scrollback_pager_history_size, PyLong_AsUnsignedLong);
|
S(scrollback_pager_history_size, PyLong_AsUnsignedLong);
|
||||||
S(cursor_shape, PyLong_AsLong);
|
S(cursor_shape, PyLong_AsLong);
|
||||||
S(cursor_beam_thickness, PyFloat_AsFloat);
|
S(cursor_beam_thickness, PyFloat_AsFloat);
|
||||||
@@ -772,10 +813,10 @@ PYWRAP1(os_window_has_background_image) {
|
|||||||
|
|
||||||
PYWRAP1(mark_os_window_for_close) {
|
PYWRAP1(mark_os_window_for_close) {
|
||||||
id_type os_window_id;
|
id_type os_window_id;
|
||||||
int yes = 1;
|
CloseRequest cr = IMPERATIVE_CLOSE_REQUESTED;
|
||||||
PA("K|p", &os_window_id, &yes);
|
PA("K|i", &os_window_id, &cr);
|
||||||
WITH_OS_WINDOW(os_window_id)
|
WITH_OS_WINDOW(os_window_id)
|
||||||
mark_os_window_for_close(os_window, yes ? true : false);
|
mark_os_window_for_close(os_window, cr);
|
||||||
Py_RETURN_TRUE;
|
Py_RETURN_TRUE;
|
||||||
END_WITH_OS_WINDOW
|
END_WITH_OS_WINDOW
|
||||||
Py_RETURN_FALSE;
|
Py_RETURN_FALSE;
|
||||||
@@ -839,6 +880,16 @@ fix_window_idx(Tab *tab, id_type window_id, unsigned int *window_idx) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYWRAP1(set_window_padding) {
|
||||||
|
id_type os_window_id, tab_id, window_id;
|
||||||
|
unsigned int left, top, right, bottom;
|
||||||
|
PA("KKKIIII", &os_window_id, &tab_id, &window_id, &left, &top, &right, &bottom);
|
||||||
|
WITH_WINDOW(os_window_id, tab_id, window_id);
|
||||||
|
window->padding.left = left; window->padding.top = top; window->padding.right = right; window->padding.bottom = bottom;
|
||||||
|
END_WITH_WINDOW;
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
PYWRAP1(set_window_render_data) {
|
PYWRAP1(set_window_render_data) {
|
||||||
#define A(name) &(d.name)
|
#define A(name) &(d.name)
|
||||||
#define B(name) &(g.name)
|
#define B(name) &(g.name)
|
||||||
@@ -878,6 +929,17 @@ PYWRAP1(update_window_visibility) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PYWRAP1(sync_os_window_title) {
|
||||||
|
id_type os_window_id;
|
||||||
|
PA("K", &os_window_id);
|
||||||
|
WITH_OS_WINDOW(os_window_id)
|
||||||
|
update_os_window_title(os_window);
|
||||||
|
END_WITH_OS_WINDOW
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline double
|
static inline double
|
||||||
dpi_for_os_window_id(id_type os_window_id) {
|
dpi_for_os_window_id(id_type os_window_id) {
|
||||||
double dpi = 0;
|
double dpi = 0;
|
||||||
@@ -1080,6 +1142,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(add_borders_rect, METH_VARARGS),
|
MW(add_borders_rect, METH_VARARGS),
|
||||||
MW(set_tab_bar_render_data, METH_VARARGS),
|
MW(set_tab_bar_render_data, METH_VARARGS),
|
||||||
MW(set_window_render_data, METH_VARARGS),
|
MW(set_window_render_data, METH_VARARGS),
|
||||||
|
MW(set_window_padding, METH_VARARGS),
|
||||||
MW(viewport_for_window, METH_VARARGS),
|
MW(viewport_for_window, METH_VARARGS),
|
||||||
MW(cell_size_for_window, METH_VARARGS),
|
MW(cell_size_for_window, METH_VARARGS),
|
||||||
MW(os_window_has_background_image, METH_VARARGS),
|
MW(os_window_has_background_image, METH_VARARGS),
|
||||||
@@ -1090,6 +1153,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(change_background_opacity, METH_VARARGS),
|
MW(change_background_opacity, METH_VARARGS),
|
||||||
MW(background_opacity_of, METH_O),
|
MW(background_opacity_of, METH_O),
|
||||||
MW(update_window_visibility, METH_VARARGS),
|
MW(update_window_visibility, METH_VARARGS),
|
||||||
|
MW(sync_os_window_title, METH_VARARGS),
|
||||||
MW(global_font_size, METH_VARARGS),
|
MW(global_font_size, METH_VARARGS),
|
||||||
MW(set_background_image, METH_VARARGS),
|
MW(set_background_image, METH_VARARGS),
|
||||||
MW(os_window_font_size, METH_VARARGS),
|
MW(os_window_font_size, METH_VARARGS),
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ typedef struct {
|
|||||||
|
|
||||||
bool dynamic_background_opacity;
|
bool dynamic_background_opacity;
|
||||||
float inactive_text_alpha;
|
float inactive_text_alpha;
|
||||||
float window_padding_width;
|
|
||||||
Edge tab_bar_edge;
|
Edge tab_bar_edge;
|
||||||
unsigned long tab_bar_min_tabs;
|
unsigned long tab_bar_min_tabs;
|
||||||
DisableLigature disable_ligatures;
|
DisableLigature disable_ligatures;
|
||||||
@@ -106,6 +105,9 @@ typedef struct {
|
|||||||
double x, y;
|
double x, y;
|
||||||
bool in_left_half_of_cell;
|
bool in_left_half_of_cell;
|
||||||
} mouse_pos;
|
} mouse_pos;
|
||||||
|
struct {
|
||||||
|
unsigned int left, top, right, bottom;
|
||||||
|
} padding;
|
||||||
WindowGeometry geometry;
|
WindowGeometry geometry;
|
||||||
ClickQueue click_queue;
|
ClickQueue click_queue;
|
||||||
monotonic_t last_drag_scroll_at;
|
monotonic_t last_drag_scroll_at;
|
||||||
@@ -137,6 +139,7 @@ typedef struct {
|
|||||||
} OSWindowGeometry;
|
} OSWindowGeometry;
|
||||||
|
|
||||||
enum RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY };
|
enum RENDER_STATE { RENDER_FRAME_NOT_REQUESTED, RENDER_FRAME_REQUESTED, RENDER_FRAME_READY };
|
||||||
|
typedef enum { NO_CLOSE_REQUESTED, CONFIRMABLE_CLOSE_REQUESTED, IMPERATIVE_CLOSE_REQUESTED } CloseRequest;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
monotonic_t last_resize_event_at;
|
monotonic_t last_resize_event_at;
|
||||||
@@ -181,6 +184,7 @@ typedef struct {
|
|||||||
uint64_t render_calls;
|
uint64_t render_calls;
|
||||||
id_type last_focused_counter;
|
id_type last_focused_counter;
|
||||||
ssize_t gvao_idx;
|
ssize_t gvao_idx;
|
||||||
|
CloseRequest close_request;
|
||||||
} OSWindow;
|
} OSWindow;
|
||||||
|
|
||||||
|
|
||||||
@@ -196,7 +200,7 @@ typedef struct {
|
|||||||
bool terminate;
|
bool terminate;
|
||||||
bool is_wayland;
|
bool is_wayland;
|
||||||
bool has_render_frames;
|
bool has_render_frames;
|
||||||
bool debug_gl, debug_font_fallback;
|
bool debug_rendering, debug_font_fallback;
|
||||||
bool has_pending_resizes, has_pending_closes;
|
bool has_pending_resizes, has_pending_closes;
|
||||||
bool in_sequence_mode;
|
bool in_sequence_mode;
|
||||||
bool tab_bar_hidden;
|
bool tab_bar_hidden;
|
||||||
@@ -218,9 +222,8 @@ void remove_vao(ssize_t vao_idx);
|
|||||||
bool remove_os_window(id_type os_window_id);
|
bool remove_os_window(id_type os_window_id);
|
||||||
void make_os_window_context_current(OSWindow *w);
|
void make_os_window_context_current(OSWindow *w);
|
||||||
void update_os_window_references(void);
|
void update_os_window_references(void);
|
||||||
void mark_os_window_for_close(OSWindow* w, bool yes);
|
void mark_os_window_for_close(OSWindow* w, CloseRequest cr);
|
||||||
void update_os_window_viewport(OSWindow *window, bool);
|
void update_os_window_viewport(OSWindow *window, bool);
|
||||||
bool should_os_window_close(OSWindow* w);
|
|
||||||
bool should_os_window_be_rendered(OSWindow* w);
|
bool should_os_window_be_rendered(OSWindow* w);
|
||||||
void wakeup_main_loop(void);
|
void wakeup_main_loop(void);
|
||||||
void swap_window_buffers(OSWindow *w);
|
void swap_window_buffers(OSWindow *w);
|
||||||
@@ -274,3 +277,5 @@ void update_main_loop_timer(id_type timer_id, monotonic_t interval, bool enabled
|
|||||||
void run_main_loop(tick_callback_fun, void*);
|
void run_main_loop(tick_callback_fun, void*);
|
||||||
void stop_main_loop(void);
|
void stop_main_loop(void);
|
||||||
void os_window_update_size_increments(OSWindow *window);
|
void os_window_update_size_increments(OSWindow *window);
|
||||||
|
void set_os_window_title_from_window(Window *w, OSWindow *os_window);
|
||||||
|
void update_os_window_title(OSWindow *os_window);
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ class TabBarData(NamedTuple):
|
|||||||
title: str
|
title: str
|
||||||
is_active: bool
|
is_active: bool
|
||||||
needs_attention: bool
|
needs_attention: bool
|
||||||
|
num_windows: int
|
||||||
|
layout_name: str
|
||||||
|
|
||||||
|
|
||||||
class DrawData(NamedTuple):
|
class DrawData(NamedTuple):
|
||||||
@@ -56,7 +58,7 @@ def draw_title(draw_data: DrawData, screen: Screen, tab: TabBarData, index: int)
|
|||||||
if tab.is_active and draw_data.active_title_template is not None:
|
if tab.is_active and draw_data.active_title_template is not None:
|
||||||
template = draw_data.active_title_template
|
template = draw_data.active_title_template
|
||||||
try:
|
try:
|
||||||
title = template.format(title=tab.title, index=index)
|
title = template.format(title=tab.title, index=index, layout_name=tab.layout_name, num_windows=tab.num_windows)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if template not in template_failures:
|
if template not in template_failures:
|
||||||
template_failures.add(template)
|
template_failures.add(template)
|
||||||
@@ -84,7 +86,7 @@ def draw_tab_with_separator(draw_data: DrawData, screen: Screen, tab: TabBarData
|
|||||||
screen.cursor.fg = 0
|
screen.cursor.fg = 0
|
||||||
if not is_last:
|
if not is_last:
|
||||||
screen.cursor.bg = as_rgb(color_as_int(draw_data.inactive_bg))
|
screen.cursor.bg = as_rgb(color_as_int(draw_data.inactive_bg))
|
||||||
screen.draw(draw_data.sep)
|
screen.draw(draw_data.sep)
|
||||||
screen.cursor.bg = 0
|
screen.cursor.bg = 0
|
||||||
return end
|
return end
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ from collections import deque
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import (
|
from typing import (
|
||||||
Deque, Dict, Generator, Iterator, List, NamedTuple,
|
Any, Deque, Dict, Generator, Iterator, List, NamedTuple, Optional, Pattern,
|
||||||
Optional, Pattern, Sequence, Tuple, cast
|
Sequence, Tuple, cast
|
||||||
)
|
)
|
||||||
|
|
||||||
from .borders import Borders
|
from .borders import Borders
|
||||||
@@ -17,17 +17,17 @@ from .cli_stub import CLIOptions
|
|||||||
from .constants import appname, is_macos, is_wayland
|
from .constants import appname, is_macos, is_wayland
|
||||||
from .fast_data_types import (
|
from .fast_data_types import (
|
||||||
add_tab, attach_window, detach_window, get_boss, mark_tab_bar_dirty,
|
add_tab, attach_window, detach_window, get_boss, mark_tab_bar_dirty,
|
||||||
next_window_id, pt_to_px, remove_tab, remove_window, ring_bell,
|
next_window_id, remove_tab, remove_window, ring_bell, set_active_tab,
|
||||||
set_active_tab, swap_tabs, x11_window_id
|
swap_tabs, sync_os_window_title, x11_window_id
|
||||||
)
|
)
|
||||||
from .layout import (
|
from .layout import (
|
||||||
Layout, Rect, create_layout_object_for, evict_cached_layouts
|
Layout, Rect, create_layout_object_for, evict_cached_layouts
|
||||||
)
|
)
|
||||||
from .options_stub import Options
|
from .options_stub import Options
|
||||||
from .tab_bar import TabBar, TabBarData
|
from .tab_bar import TabBar, TabBarData
|
||||||
|
from .typing import SessionTab, SessionType, TypedDict
|
||||||
from .utils import log_error, resolved_shell
|
from .utils import log_error, resolved_shell
|
||||||
from .window import Window, WindowDict, Watchers
|
from .window import Watchers, Window, WindowDict
|
||||||
from .typing import TypedDict, SessionTab, SessionType
|
|
||||||
|
|
||||||
|
|
||||||
class TabDict(TypedDict):
|
class TabDict(TypedDict):
|
||||||
@@ -87,11 +87,10 @@ class Tab: # {{{
|
|||||||
if not self.id:
|
if not self.id:
|
||||||
raise Exception('No OS window with id {} found, or tab counter has wrapped'.format(self.os_window_id))
|
raise Exception('No OS window with id {} found, or tab counter has wrapped'.format(self.os_window_id))
|
||||||
self.opts, self.args = tab_manager.opts, tab_manager.args
|
self.opts, self.args = tab_manager.opts, tab_manager.args
|
||||||
self.recalculate_sizes(update_layout=False)
|
|
||||||
self.name = getattr(session_tab, 'name', '')
|
self.name = getattr(session_tab, 'name', '')
|
||||||
self.enabled_layouts = [x.lower() for x in getattr(session_tab, 'enabled_layouts', None) or self.opts.enabled_layouts]
|
self.enabled_layouts = [x.lower() for x in getattr(session_tab, 'enabled_layouts', None) or self.opts.enabled_layouts]
|
||||||
self.borders = Borders(self.os_window_id, self.id, self.opts)
|
self.borders = Borders(self.os_window_id, self.id, self.opts)
|
||||||
self.windows: Deque[Window] = deque()
|
self.windows: List[Window] = []
|
||||||
for i, which in enumerate('first second third fourth fifth sixth seventh eighth ninth tenth'.split()):
|
for i, which in enumerate('first second third fourth fifth sixth seventh eighth ninth tenth'.split()):
|
||||||
setattr(self, which + '_window', partial(self.nth_window, num=i))
|
setattr(self, which + '_window', partial(self.nth_window, num=i))
|
||||||
self._last_used_layout: Optional[str] = None
|
self._last_used_layout: Optional[str] = None
|
||||||
@@ -113,15 +112,6 @@ class Tab: # {{{
|
|||||||
self._set_current_layout(l0)
|
self._set_current_layout(l0)
|
||||||
self.startup(session_tab)
|
self.startup(session_tab)
|
||||||
|
|
||||||
def recalculate_sizes(self, update_layout: bool = True) -> None:
|
|
||||||
self.margin_width, self.padding_width, self.single_window_margin_width = map(
|
|
||||||
lambda x: pt_to_px(getattr(self.opts, x), self.os_window_id), (
|
|
||||||
'window_margin_width', 'window_padding_width', 'single_window_margin_width'))
|
|
||||||
self.border_width = pt_to_px(self.opts.window_border_width, self.os_window_id)
|
|
||||||
if update_layout and self.current_layout:
|
|
||||||
self.current_layout.update_sizes(
|
|
||||||
self.margin_width, self.single_window_margin_width, self.padding_width, self.border_width)
|
|
||||||
|
|
||||||
def take_over_from(self, other_tab: 'Tab') -> None:
|
def take_over_from(self, other_tab: 'Tab') -> None:
|
||||||
self.name, self.cwd = other_tab.name, other_tab.cwd
|
self.name, self.cwd = other_tab.name, other_tab.cwd
|
||||||
self.enabled_layouts = list(other_tab.enabled_layouts)
|
self.enabled_layouts = list(other_tab.enabled_layouts)
|
||||||
@@ -129,12 +119,12 @@ class Tab: # {{{
|
|||||||
self._set_current_layout(other_tab._current_layout_name)
|
self._set_current_layout(other_tab._current_layout_name)
|
||||||
self._last_used_layout = other_tab._last_used_layout
|
self._last_used_layout = other_tab._last_used_layout
|
||||||
|
|
||||||
orig_windows = deque(other_tab.windows)
|
orig_windows = list(other_tab.windows)
|
||||||
orig_history = deque(other_tab.active_window_history)
|
orig_history = deque(other_tab.active_window_history)
|
||||||
orig_active = other_tab._active_window_idx
|
orig_active = other_tab._active_window_idx
|
||||||
for window in other_tab.windows:
|
for window in other_tab.windows:
|
||||||
detach_window(other_tab.os_window_id, other_tab.id, window.id)
|
detach_window(other_tab.os_window_id, other_tab.id, window.id)
|
||||||
other_tab.windows = deque()
|
other_tab.windows = []
|
||||||
other_tab._active_window_idx = 0
|
other_tab._active_window_idx = 0
|
||||||
self.active_window_history = orig_history
|
self.active_window_history = orig_history
|
||||||
self.windows = orig_windows
|
self.windows = orig_windows
|
||||||
@@ -148,6 +138,7 @@ class Tab: # {{{
|
|||||||
self._last_used_layout = self._current_layout_name
|
self._last_used_layout = self._current_layout_name
|
||||||
self.current_layout = self.create_layout_object(layout_name)
|
self.current_layout = self.create_layout_object(layout_name)
|
||||||
self._current_layout_name = layout_name
|
self._current_layout_name = layout_name
|
||||||
|
self.mark_tab_bar_dirty()
|
||||||
|
|
||||||
def startup(self, session_tab: 'SessionTab') -> None:
|
def startup(self, session_tab: 'SessionTab') -> None:
|
||||||
for cmd in session_tab.windows:
|
for cmd in session_tab.windows:
|
||||||
@@ -157,6 +148,18 @@ class Tab: # {{{
|
|||||||
self.new_window(cmd=cmd)
|
self.new_window(cmd=cmd)
|
||||||
self.set_active_window_idx(session_tab.active_window_idx)
|
self.set_active_window_idx(session_tab.active_window_idx)
|
||||||
|
|
||||||
|
def serialize_state(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
'version': 1,
|
||||||
|
'id': self.id,
|
||||||
|
'active_window_idx': self.active_window_idx,
|
||||||
|
'windows': [w.serialize_state() for w in self],
|
||||||
|
'current_layout': self._current_layout_name,
|
||||||
|
'last_used_layout': self._last_used_layout,
|
||||||
|
'active_window_history': list(self.active_window_history),
|
||||||
|
'name': self.name,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_window_idx(self) -> int:
|
def active_window_idx(self) -> int:
|
||||||
return self._active_window_idx
|
return self._active_window_idx
|
||||||
@@ -181,10 +184,13 @@ class Tab: # {{{
|
|||||||
old_active_window.focus_changed(False)
|
old_active_window.focus_changed(False)
|
||||||
if new_active_window is not None:
|
if new_active_window is not None:
|
||||||
new_active_window.focus_changed(True)
|
new_active_window.focus_changed(True)
|
||||||
tm = self.tab_manager_ref()
|
self.relayout_borders()
|
||||||
if tm is not None:
|
self.mark_tab_bar_dirty()
|
||||||
self.relayout_borders()
|
|
||||||
tm.mark_tab_bar_dirty()
|
def mark_tab_bar_dirty(self) -> None:
|
||||||
|
tm = self.tab_manager_ref()
|
||||||
|
if tm is not None:
|
||||||
|
tm.mark_tab_bar_dirty()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_window(self) -> Optional[Window]:
|
def active_window(self) -> Optional[Window]:
|
||||||
@@ -204,7 +210,7 @@ class Tab: # {{{
|
|||||||
if window is self.active_window:
|
if window is self.active_window:
|
||||||
tm = self.tab_manager_ref()
|
tm = self.tab_manager_ref()
|
||||||
if tm is not None:
|
if tm is not None:
|
||||||
tm.mark_tab_bar_dirty()
|
tm.title_changed(self)
|
||||||
|
|
||||||
def on_bell(self, window: Window) -> None:
|
def on_bell(self, window: Window) -> None:
|
||||||
tm = self.tab_manager_ref()
|
tm = self.tab_manager_ref()
|
||||||
@@ -227,20 +233,17 @@ class Tab: # {{{
|
|||||||
if tm is not None:
|
if tm is not None:
|
||||||
visible_windows = [w for w in self.windows if w.is_visible_in_layout]
|
visible_windows = [w for w in self.windows if w.is_visible_in_layout]
|
||||||
w = self.active_window
|
w = self.active_window
|
||||||
|
ly = self.current_layout
|
||||||
self.borders(
|
self.borders(
|
||||||
windows=visible_windows, active_window=w,
|
windows=visible_windows, active_window=w,
|
||||||
current_layout=self.current_layout, extra_blank_rects=tm.blank_rects,
|
current_layout=ly, extra_blank_rects=tm.blank_rects,
|
||||||
padding_width=self.padding_width, border_width=self.border_width,
|
draw_window_borders=(ly.needs_window_borders and len(visible_windows) > 1) or ly.must_draw_borders
|
||||||
draw_window_borders=self.current_layout.needs_window_borders and len(visible_windows) > 1
|
|
||||||
)
|
)
|
||||||
if w is not None:
|
if w is not None:
|
||||||
w.change_titlebar_color()
|
w.change_titlebar_color()
|
||||||
|
|
||||||
def create_layout_object(self, name: str) -> Layout:
|
def create_layout_object(self, name: str) -> Layout:
|
||||||
return create_layout_object_for(
|
return create_layout_object_for(name, self.os_window_id, self.id)
|
||||||
name, self.os_window_id, self.id, self.margin_width,
|
|
||||||
self.single_window_margin_width, self.padding_width,
|
|
||||||
self.border_width)
|
|
||||||
|
|
||||||
def next_layout(self) -> None:
|
def next_layout(self) -> None:
|
||||||
if len(self.enabled_layouts) > 1:
|
if len(self.enabled_layouts) > 1:
|
||||||
@@ -331,6 +334,7 @@ class Tab: # {{{
|
|||||||
def _add_window(self, window: Window, location: Optional[str] = None) -> None:
|
def _add_window(self, window: Window, location: Optional[str] = None) -> None:
|
||||||
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location)
|
self.active_window_idx = self.current_layout.add_window(self.windows, window, self.active_window_idx, location)
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
|
self.mark_tab_bar_dirty()
|
||||||
|
|
||||||
def new_window(
|
def new_window(
|
||||||
self,
|
self,
|
||||||
@@ -432,6 +436,7 @@ class Tab: # {{{
|
|||||||
else:
|
else:
|
||||||
self.active_window_idx = active_window_idx
|
self.active_window_idx = active_window_idx
|
||||||
self.relayout_borders()
|
self.relayout_borders()
|
||||||
|
self.mark_tab_bar_dirty()
|
||||||
active_window = self.active_window
|
active_window = self.active_window
|
||||||
if active_window:
|
if active_window:
|
||||||
self.title_changed(active_window)
|
self.title_changed(active_window)
|
||||||
@@ -546,7 +551,7 @@ class Tab: # {{{
|
|||||||
evict_cached_layouts(self.id)
|
evict_cached_layouts(self.id)
|
||||||
for w in self.windows:
|
for w in self.windows:
|
||||||
w.destroy()
|
w.destroy()
|
||||||
self.windows = deque()
|
self.windows = []
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return 'Tab(title={}, id={})'.format(self.name or self.title, hex(id(self)))
|
return 'Tab(title={}, id={})'.format(self.name or self.title, hex(id(self)))
|
||||||
@@ -640,9 +645,10 @@ class TabManager: # {{{
|
|||||||
def update_tab_bar_data(self) -> None:
|
def update_tab_bar_data(self) -> None:
|
||||||
self.tab_bar.update(self.tab_bar_data)
|
self.tab_bar.update(self.tab_bar_data)
|
||||||
|
|
||||||
def update_dpi_based_sizes(self) -> None:
|
def title_changed(self, tab: Tab) -> None:
|
||||||
for tab in self.tabs:
|
self.mark_tab_bar_dirty()
|
||||||
tab.recalculate_sizes()
|
if tab is self.active_tab:
|
||||||
|
sync_os_window_title(self.os_window_id)
|
||||||
|
|
||||||
def resize(self, only_tabs: bool = False) -> None:
|
def resize(self, only_tabs: bool = False) -> None:
|
||||||
if not only_tabs:
|
if not only_tabs:
|
||||||
@@ -703,6 +709,14 @@ class TabManager: # {{{
|
|||||||
'active_window_history': list(tab.active_window_history),
|
'active_window_history': list(tab.active_window_history),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def serialize_state(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
'version': 1,
|
||||||
|
'id': self.os_window_id,
|
||||||
|
'tabs': [tab.serialize_state() for tab in self],
|
||||||
|
'active_tab_idx': self.active_tab_idx,
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active_tab(self) -> Optional[Tab]:
|
def active_tab(self) -> Optional[Tab]:
|
||||||
return self.tabs[self.active_tab_idx] if self.tabs else None
|
return self.tabs[self.active_tab_idx] if self.tabs else None
|
||||||
@@ -796,7 +810,10 @@ class TabManager: # {{{
|
|||||||
if w.needs_attention:
|
if w.needs_attention:
|
||||||
needs_attention = True
|
needs_attention = True
|
||||||
break
|
break
|
||||||
ans.append(TabBarData(title, t is at, needs_attention))
|
ans.append(TabBarData(
|
||||||
|
title, t is at, needs_attention,
|
||||||
|
len(t), t.current_layout.name or ''
|
||||||
|
))
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
def activate_tab_at(self, x: int) -> None:
|
def activate_tab_at(self, x: int) -> None:
|
||||||
|
|||||||
@@ -198,6 +198,8 @@ string_capabilities = {
|
|||||||
'rmso': r'\E[27m',
|
'rmso': r'\E[27m',
|
||||||
# Exit underline mode
|
# Exit underline mode
|
||||||
'rmul': r'\E[24m',
|
'rmul': r'\E[24m',
|
||||||
|
# Exit strikethrough mode
|
||||||
|
'rmxx': r'\E[29m',
|
||||||
# Reset string1 (empty OSC sequence to exit OSC/OTH modes, and regular reset)
|
# Reset string1 (empty OSC sequence to exit OSC/OTH modes, and regular reset)
|
||||||
'rs1': r'\E]\E\\\Ec',
|
'rs1': r'\E]\E\\\Ec',
|
||||||
# Save cursor
|
# Save cursor
|
||||||
@@ -224,6 +226,8 @@ string_capabilities = {
|
|||||||
'smso': r'\E[7m',
|
'smso': r'\E[7m',
|
||||||
# Enter underline mode
|
# Enter underline mode
|
||||||
'smul': r'\E[4m',
|
'smul': r'\E[4m',
|
||||||
|
# Enter strikethrough mode
|
||||||
|
'smxx': r'\E[9m',
|
||||||
# Clear all tab stops
|
# Clear all tab stops
|
||||||
'tbc': r'\E[3g',
|
'tbc': r'\E[3g',
|
||||||
# To status line (used to set window titles)
|
# To status line (used to set window titles)
|
||||||
@@ -351,6 +355,7 @@ termcap_aliases.update({
|
|||||||
'ei': 'rmir',
|
'ei': 'rmir',
|
||||||
'se': 'rmso',
|
'se': 'rmso',
|
||||||
'ue': 'rmul',
|
'ue': 'rmul',
|
||||||
|
'Te': 'rmxx',
|
||||||
'r1': 'rs1',
|
'r1': 'rs1',
|
||||||
'sc': 'sc',
|
'sc': 'sc',
|
||||||
'AB': 'setab',
|
'AB': 'setab',
|
||||||
@@ -363,6 +368,7 @@ termcap_aliases.update({
|
|||||||
'im': 'smir',
|
'im': 'smir',
|
||||||
'so': 'smso',
|
'so': 'smso',
|
||||||
'us': 'smul',
|
'us': 'smul',
|
||||||
|
'Ts': 'smxx',
|
||||||
'ct': 'tbc',
|
'ct': 'tbc',
|
||||||
'cv': 'vpa',
|
'cv': 'vpa',
|
||||||
'ZH': 'sitm',
|
'ZH': 'sitm',
|
||||||
|
|||||||
557
kitty/unicode-data.c
generated
557
kitty/unicode-data.c
generated
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
#define VS15 1280
|
#define VS15 1285
|
||||||
#define VS16 1281
|
#define VS16 1286
|
||||||
|
|
||||||
bool is_combining_char(char_type ch);
|
bool is_combining_char(char_type ch);
|
||||||
bool is_ignored_char(char_type ch);
|
bool is_ignored_char(char_type ch);
|
||||||
@@ -29,3 +29,9 @@ static inline bool
|
|||||||
is_private_use(char_type ch) {
|
is_private_use(char_type ch) {
|
||||||
return (0xe000 <= ch && ch <= 0xf8ff) || (0xF0000 <= ch && ch <= 0xFFFFF) || (0x100000 <= ch && ch <= 0x10FFFF);
|
return (0xe000 <= ch && ch <= 0xf8ff) || (0xF0000 <= ch && ch <= 0xFFFFF) || (0x100000 <= ch && ch <= 0x10FFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_flag_codepoint(char_type ch) {
|
||||||
|
return 0x1F1E6 <= ch && ch <= 0x1F1FF;
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ from contextlib import suppress
|
|||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Callable, Dict, Generator, Iterable, List, NamedTuple, Optional,
|
Any, Callable, Dict, Generator, Iterable, List, Match, NamedTuple,
|
||||||
Tuple, Union, cast
|
Optional, Tuple, Union, cast
|
||||||
)
|
)
|
||||||
|
|
||||||
from .constants import (
|
from .constants import (
|
||||||
@@ -28,6 +28,20 @@ from .typing import AddressFamily, PopenType, Socket, StartupCtx
|
|||||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
def expandvars(val: str, env: Dict[str, str] = {}) -> str:
|
||||||
|
|
||||||
|
def sub(m: Match) -> str:
|
||||||
|
key = m.group(1)
|
||||||
|
result = env.get(key)
|
||||||
|
if result is None:
|
||||||
|
result = os.environ.get(key)
|
||||||
|
if result is None:
|
||||||
|
result = m.group()
|
||||||
|
return result
|
||||||
|
|
||||||
|
return re.sub(r'\$\{(\S+?)\}', sub, val)
|
||||||
|
|
||||||
|
|
||||||
def load_shaders(name: str) -> Tuple[str, str]:
|
def load_shaders(name: str) -> Tuple[str, str]:
|
||||||
from .fast_data_types import GLSL_VERSION
|
from .fast_data_types import GLSL_VERSION
|
||||||
with open(os.path.join(BASE, '{}_vertex.glsl'.format(name))) as f:
|
with open(os.path.join(BASE, '{}_vertex.glsl'.format(name))) as f:
|
||||||
|
|||||||
395
kitty/wcwidth-std.h
generated
395
kitty/wcwidth-std.h
generated
@@ -1,4 +1,4 @@
|
|||||||
// unicode data, built from the unicode standard on: 2019-10-01
|
// unicode data, built from the unicode standard on: 2020-04-06
|
||||||
// see gen-wcwidth.py
|
// see gen-wcwidth.py
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "data-types.h"
|
#include "data-types.h"
|
||||||
@@ -8,7 +8,12 @@ START_ALLOW_CASE_RANGE
|
|||||||
static int
|
static int
|
||||||
wcwidth_std(int32_t code) {
|
wcwidth_std(int32_t code) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
// Marks (2275 codepoints) {{{
|
// Flags (26 codepoints) {{{
|
||||||
|
case 0x1f1e6 ... 0x1f1ff:
|
||||||
|
return 2;
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
// Marks (2302 codepoints) {{{
|
||||||
case 0x0:
|
case 0x0:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x300 ... 0x36f:
|
case 0x300 ... 0x36f:
|
||||||
@@ -127,7 +132,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0xb4b ... 0xb4d:
|
case 0xb4b ... 0xb4d:
|
||||||
return 0;
|
return 0;
|
||||||
case 0xb56 ... 0xb57:
|
case 0xb55 ... 0xb57:
|
||||||
return 0;
|
return 0;
|
||||||
case 0xb62 ... 0xb63:
|
case 0xb62 ... 0xb63:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -181,7 +186,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0xd62 ... 0xd63:
|
case 0xd62 ... 0xd63:
|
||||||
return 0;
|
return 0;
|
||||||
case 0xd82 ... 0xd83:
|
case 0xd81 ... 0xd83:
|
||||||
return 0;
|
return 0;
|
||||||
case 0xdca:
|
case 0xdca:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -275,7 +280,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x1a7f:
|
case 0x1a7f:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x1ab0 ... 0x1abe:
|
case 0x1ab0 ... 0x1ac0:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x1b00 ... 0x1b04:
|
case 0x1b00 ... 0x1b04:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -335,6 +340,8 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0xa823 ... 0xa827:
|
case 0xa823 ... 0xa827:
|
||||||
return 0;
|
return 0;
|
||||||
|
case 0xa82c:
|
||||||
|
return 0;
|
||||||
case 0xa880 ... 0xa881:
|
case 0xa880 ... 0xa881:
|
||||||
return 0;
|
return 0;
|
||||||
case 0xa8b4 ... 0xa8c5:
|
case 0xa8b4 ... 0xa8c5:
|
||||||
@@ -405,6 +412,8 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x10d24 ... 0x10d27:
|
case 0x10d24 ... 0x10d27:
|
||||||
return 0;
|
return 0;
|
||||||
|
case 0x10eab ... 0x10eac:
|
||||||
|
return 0;
|
||||||
case 0x10f46 ... 0x10f50:
|
case 0x10f46 ... 0x10f50:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x11000 ... 0x11002:
|
case 0x11000 ... 0x11002:
|
||||||
@@ -429,6 +438,8 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x111c9 ... 0x111cc:
|
case 0x111c9 ... 0x111cc:
|
||||||
return 0;
|
return 0;
|
||||||
|
case 0x111ce ... 0x111cf:
|
||||||
|
return 0;
|
||||||
case 0x1122c ... 0x11237:
|
case 0x1122c ... 0x11237:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x1123e:
|
case 0x1123e:
|
||||||
@@ -473,6 +484,16 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x1182c ... 0x1183a:
|
case 0x1182c ... 0x1183a:
|
||||||
return 0;
|
return 0;
|
||||||
|
case 0x11930 ... 0x11935:
|
||||||
|
return 0;
|
||||||
|
case 0x11937 ... 0x11938:
|
||||||
|
return 0;
|
||||||
|
case 0x1193b ... 0x1193e:
|
||||||
|
return 0;
|
||||||
|
case 0x11940:
|
||||||
|
return 0;
|
||||||
|
case 0x11942 ... 0x11943:
|
||||||
|
return 0;
|
||||||
case 0x119d1 ... 0x119d7:
|
case 0x119d1 ... 0x119d7:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x119da ... 0x119e0:
|
case 0x119da ... 0x119e0:
|
||||||
@@ -527,6 +548,10 @@ wcwidth_std(int32_t code) {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x16f8f ... 0x16f92:
|
case 0x16f8f ... 0x16f92:
|
||||||
return 0;
|
return 0;
|
||||||
|
case 0x16fe4:
|
||||||
|
return 0;
|
||||||
|
case 0x16ff0 ... 0x16ff1:
|
||||||
|
return 0;
|
||||||
case 0x1bc9d ... 0x1bc9e:
|
case 0x1bc9d ... 0x1bc9e:
|
||||||
return 0;
|
return 0;
|
||||||
case 0x1d165 ... 0x1d169:
|
case 0x1d165 ... 0x1d169:
|
||||||
@@ -637,7 +662,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -3;
|
return -3;
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Text Presentation (218 codepoints) {{{
|
// Text Presentation (219 codepoints) {{{
|
||||||
case 0x23:
|
case 0x23:
|
||||||
return 1;
|
return 1;
|
||||||
case 0x2a:
|
case 0x2a:
|
||||||
@@ -728,6 +753,8 @@ wcwidth_std(int32_t code) {
|
|||||||
return 1;
|
return 1;
|
||||||
case 0x26a0:
|
case 0x26a0:
|
||||||
return 1;
|
return 1;
|
||||||
|
case 0x26a7:
|
||||||
|
return 1;
|
||||||
case 0x26b0 ... 0x26b1:
|
case 0x26b0 ... 0x26b1:
|
||||||
return 1;
|
return 1;
|
||||||
case 0x26c8:
|
case 0x26c8:
|
||||||
@@ -1227,7 +1254,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -2;
|
return -2;
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// East Asian double width (181868 codepoints) {{{
|
// East Asian double width (182418 codepoints) {{{
|
||||||
case 0x1100 ... 0x115f:
|
case 0x1100 ... 0x115f:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x231a ... 0x231b:
|
case 0x231a ... 0x231b:
|
||||||
@@ -1320,9 +1347,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return 2;
|
return 2;
|
||||||
case 0x3131 ... 0x318e:
|
case 0x3131 ... 0x318e:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x3190 ... 0x31ba:
|
case 0x3190 ... 0x31e3:
|
||||||
return 2;
|
|
||||||
case 0x31c0 ... 0x31e3:
|
|
||||||
return 2;
|
return 2;
|
||||||
case 0x31f0 ... 0x321e:
|
case 0x31f0 ... 0x321e:
|
||||||
return 2;
|
return 2;
|
||||||
@@ -1360,7 +1385,9 @@ wcwidth_std(int32_t code) {
|
|||||||
return 2;
|
return 2;
|
||||||
case 0x17000 ... 0x187f7:
|
case 0x17000 ... 0x187f7:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x18800 ... 0x18af2:
|
case 0x18800 ... 0x18cd5:
|
||||||
|
return 2;
|
||||||
|
case 0x18d00 ... 0x18d08:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1b000 ... 0x1b11e:
|
case 0x1b000 ... 0x1b11e:
|
||||||
return 2;
|
return 2;
|
||||||
@@ -1434,33 +1461,37 @@ wcwidth_std(int32_t code) {
|
|||||||
return 2;
|
return 2;
|
||||||
case 0x1f6d0 ... 0x1f6d2:
|
case 0x1f6d0 ... 0x1f6d2:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f6d5:
|
case 0x1f6d5 ... 0x1f6d7:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f6eb ... 0x1f6ec:
|
case 0x1f6eb ... 0x1f6ec:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f6f4 ... 0x1f6fa:
|
case 0x1f6f4 ... 0x1f6fc:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f7e0 ... 0x1f7eb:
|
case 0x1f7e0 ... 0x1f7eb:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f90d ... 0x1f971:
|
case 0x1f90c ... 0x1f93a:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f973 ... 0x1f976:
|
case 0x1f93c ... 0x1f945:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f97a ... 0x1f9a2:
|
case 0x1f947 ... 0x1f978:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f9a5 ... 0x1f9aa:
|
case 0x1f97a ... 0x1f9cb:
|
||||||
return 2;
|
|
||||||
case 0x1f9ae ... 0x1f9ca:
|
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1f9cd ... 0x1f9ff:
|
case 0x1f9cd ... 0x1f9ff:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1fa70 ... 0x1fa73:
|
case 0x1fa70 ... 0x1fa74:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1fa78 ... 0x1fa7a:
|
case 0x1fa78 ... 0x1fa7a:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1fa80 ... 0x1fa82:
|
case 0x1fa80 ... 0x1fa86:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x1fa90 ... 0x1fa95:
|
case 0x1fa90 ... 0x1faa8:
|
||||||
|
return 2;
|
||||||
|
case 0x1fab0 ... 0x1fab6:
|
||||||
|
return 2;
|
||||||
|
case 0x1fac0 ... 0x1fac2:
|
||||||
|
return 2;
|
||||||
|
case 0x1fad0 ... 0x1fad6:
|
||||||
return 2;
|
return 2;
|
||||||
case 0x20000 ... 0x2fffd:
|
case 0x20000 ... 0x2fffd:
|
||||||
return 2;
|
return 2;
|
||||||
@@ -1468,12 +1499,10 @@ wcwidth_std(int32_t code) {
|
|||||||
return 2;
|
return 2;
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Emoji Presentation (26 codepoints) {{{
|
// Emoji Presentation (0 codepoints) {{{
|
||||||
case 0x1f1e6 ... 0x1f1ff:
|
|
||||||
return 2;
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// Not assigned in the unicode character database (766326 codepoints) {{{
|
// Not assigned in the unicode character database (765365 codepoints) {{{
|
||||||
case 0x378 ... 0x379:
|
case 0x378 ... 0x379:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x380 ... 0x383:
|
case 0x380 ... 0x383:
|
||||||
@@ -1520,7 +1549,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x8b5:
|
case 0x8b5:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x8be ... 0x8d2:
|
case 0x8c8 ... 0x8d2:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x984:
|
case 0x984:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -1628,7 +1657,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0xb49 ... 0xb4a:
|
case 0xb49 ... 0xb4a:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xb4e ... 0xb55:
|
case 0xb4e ... 0xb54:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xb58 ... 0xb5b:
|
case 0xb58 ... 0xb5b:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -1718,8 +1747,6 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0xcf3 ... 0xcff:
|
case 0xcf3 ... 0xcff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xd04:
|
|
||||||
return -4;
|
|
||||||
case 0xd0d:
|
case 0xd0d:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xd11:
|
case 0xd11:
|
||||||
@@ -1732,7 +1759,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0xd64 ... 0xd65:
|
case 0xd64 ... 0xd65:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xd80 ... 0xd81:
|
case 0xd80:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xd84:
|
case 0xd84:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -1906,7 +1933,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x1aae ... 0x1aaf:
|
case 0x1aae ... 0x1aaf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1abf ... 0x1aff:
|
case 0x1ac1 ... 0x1aff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1b4c ... 0x1b4f:
|
case 0x1b4c ... 0x1b4f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -1980,7 +2007,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x2b74 ... 0x2b75:
|
case 0x2b74 ... 0x2b75:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x2b96 ... 0x2b97:
|
case 0x2b96:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x2c2f:
|
case 0x2c2f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2016,7 +2043,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x2ddf:
|
case 0x2ddf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x2e50 ... 0x2e7f:
|
case 0x2e53 ... 0x2e7f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x2e9a:
|
case 0x2e9a:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2036,8 +2063,6 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x318f:
|
case 0x318f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x31bb ... 0x31bf:
|
|
||||||
return -4;
|
|
||||||
case 0x31e4 ... 0x31ef:
|
case 0x31e4 ... 0x31ef:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x321f:
|
case 0x321f:
|
||||||
@@ -2052,9 +2077,9 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0xa7c0 ... 0xa7c1:
|
case 0xa7c0 ... 0xa7c1:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xa7c7 ... 0xa7f6:
|
case 0xa7cb ... 0xa7f4:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xa82c ... 0xa82f:
|
case 0xa82d ... 0xa82f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xa83a ... 0xa83f:
|
case 0xa83a ... 0xa83f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2094,7 +2119,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0xab2f:
|
case 0xab2f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xab68 ... 0xab6f:
|
case 0xab6c ... 0xab6f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0xabee ... 0xabef:
|
case 0xabee ... 0xabef:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2180,7 +2205,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x1018f:
|
case 0x1018f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1019c ... 0x1019f:
|
case 0x1019d ... 0x1019f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x101a1 ... 0x101cf:
|
case 0x101a1 ... 0x101cf:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2298,11 +2323,19 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x10d3a ... 0x10e5f:
|
case 0x10d3a ... 0x10e5f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x10e7f ... 0x10eff:
|
case 0x10e7f:
|
||||||
|
return -4;
|
||||||
|
case 0x10eaa:
|
||||||
|
return -4;
|
||||||
|
case 0x10eae ... 0x10eaf:
|
||||||
|
return -4;
|
||||||
|
case 0x10eb2 ... 0x10eff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x10f28 ... 0x10f2f:
|
case 0x10f28 ... 0x10f2f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x10f5a ... 0x10fdf:
|
case 0x10f5a ... 0x10faf:
|
||||||
|
return -4;
|
||||||
|
case 0x10fcc ... 0x10fdf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x10ff7 ... 0x10fff:
|
case 0x10ff7 ... 0x10fff:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2320,12 +2353,10 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x11135:
|
case 0x11135:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11147 ... 0x1114f:
|
case 0x11148 ... 0x1114f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11177 ... 0x1117f:
|
case 0x11177 ... 0x1117f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x111ce ... 0x111cf:
|
|
||||||
return -4;
|
|
||||||
case 0x111e0:
|
case 0x111e0:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x111f5 ... 0x111ff:
|
case 0x111f5 ... 0x111ff:
|
||||||
@@ -2378,11 +2409,9 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x11375 ... 0x113ff:
|
case 0x11375 ... 0x113ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1145a:
|
|
||||||
return -4;
|
|
||||||
case 0x1145c:
|
case 0x1145c:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11460 ... 0x1147f:
|
case 0x11462 ... 0x1147f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x114c8 ... 0x114cf:
|
case 0x114c8 ... 0x114cf:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2412,7 +2441,21 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x118f3 ... 0x118fe:
|
case 0x118f3 ... 0x118fe:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11900 ... 0x1199f:
|
case 0x11907 ... 0x11908:
|
||||||
|
return -4;
|
||||||
|
case 0x1190a ... 0x1190b:
|
||||||
|
return -4;
|
||||||
|
case 0x11914:
|
||||||
|
return -4;
|
||||||
|
case 0x11917:
|
||||||
|
return -4;
|
||||||
|
case 0x11936:
|
||||||
|
return -4;
|
||||||
|
case 0x11939 ... 0x1193a:
|
||||||
|
return -4;
|
||||||
|
case 0x11947 ... 0x1194f:
|
||||||
|
return -4;
|
||||||
|
case 0x1195a ... 0x1199f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x119a8 ... 0x119a9:
|
case 0x119a8 ... 0x119a9:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2466,7 +2509,9 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x11daa ... 0x11edf:
|
case 0x11daa ... 0x11edf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11ef9 ... 0x11fbf:
|
case 0x11ef9 ... 0x11faf:
|
||||||
|
return -4;
|
||||||
|
case 0x11fb1 ... 0x11fbf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x11ff2 ... 0x11ffe:
|
case 0x11ff2 ... 0x11ffe:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2514,11 +2559,15 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x16fa0 ... 0x16fdf:
|
case 0x16fa0 ... 0x16fdf:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x16fe4 ... 0x16fff:
|
case 0x16fe5 ... 0x16fef:
|
||||||
|
return -4;
|
||||||
|
case 0x16ff2 ... 0x16fff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x187f8 ... 0x187ff:
|
case 0x187f8 ... 0x187ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x18af3 ... 0x1afff:
|
case 0x18cd6 ... 0x18cff:
|
||||||
|
return -4;
|
||||||
|
case 0x18d09 ... 0x1afff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1b11f ... 0x1b14f:
|
case 0x1b11f ... 0x1b14f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2714,11 +2763,7 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x1f0f6 ... 0x1f0ff:
|
case 0x1f0f6 ... 0x1f0ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f10d ... 0x1f10f:
|
case 0x1f1ae ... 0x1f1e5:
|
||||||
return -4;
|
|
||||||
case 0x1f16d ... 0x1f16f:
|
|
||||||
return -4;
|
|
||||||
case 0x1f1ad ... 0x1f1e5:
|
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f203 ... 0x1f20f:
|
case 0x1f203 ... 0x1f20f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2730,11 +2775,11 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x1f266 ... 0x1f2ff:
|
case 0x1f266 ... 0x1f2ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f6d6 ... 0x1f6df:
|
case 0x1f6d8 ... 0x1f6df:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f6ed ... 0x1f6ef:
|
case 0x1f6ed ... 0x1f6ef:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f6fb ... 0x1f6ff:
|
case 0x1f6fd ... 0x1f6ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f774 ... 0x1f77f:
|
case 0x1f774 ... 0x1f77f:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2750,31 +2795,37 @@ wcwidth_std(int32_t code) {
|
|||||||
return -4;
|
return -4;
|
||||||
case 0x1f888 ... 0x1f88f:
|
case 0x1f888 ... 0x1f88f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f8ae ... 0x1f8ff:
|
case 0x1f8ae ... 0x1f8af:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f90c:
|
case 0x1f8b2 ... 0x1f8ff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f972:
|
case 0x1f979:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1f977 ... 0x1f979:
|
case 0x1f9cc:
|
||||||
return -4;
|
|
||||||
case 0x1f9a3 ... 0x1f9a4:
|
|
||||||
return -4;
|
|
||||||
case 0x1f9ab ... 0x1f9ad:
|
|
||||||
return -4;
|
|
||||||
case 0x1f9cb ... 0x1f9cc:
|
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa54 ... 0x1fa5f:
|
case 0x1fa54 ... 0x1fa5f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa6e ... 0x1fa6f:
|
case 0x1fa6e ... 0x1fa6f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa74 ... 0x1fa77:
|
case 0x1fa75 ... 0x1fa77:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa7b ... 0x1fa7f:
|
case 0x1fa7b ... 0x1fa7f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa83 ... 0x1fa8f:
|
case 0x1fa87 ... 0x1fa8f:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x1fa96 ... 0x1ffff:
|
case 0x1faa9 ... 0x1faaf:
|
||||||
|
return -4;
|
||||||
|
case 0x1fab7 ... 0x1fabf:
|
||||||
|
return -4;
|
||||||
|
case 0x1fac3 ... 0x1facf:
|
||||||
|
return -4;
|
||||||
|
case 0x1fad7 ... 0x1faff:
|
||||||
|
return -4;
|
||||||
|
case 0x1fb93:
|
||||||
|
return -4;
|
||||||
|
case 0x1fbcb ... 0x1fbef:
|
||||||
|
return -4;
|
||||||
|
case 0x1fbfa ... 0x1ffff:
|
||||||
return -4;
|
return -4;
|
||||||
case 0x2fffe ... 0x2ffff:
|
case 0x2fffe ... 0x2ffff:
|
||||||
return -4;
|
return -4;
|
||||||
@@ -2827,11 +2878,7 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x23cf:
|
case 0x23cf:
|
||||||
return true;
|
return true;
|
||||||
case 0x23e9 ... 0x23ea:
|
case 0x23e9 ... 0x23f3:
|
||||||
return true;
|
|
||||||
case 0x23ed ... 0x23ef:
|
|
||||||
return true;
|
|
||||||
case 0x23f1 ... 0x23f3:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x23f8 ... 0x23fa:
|
case 0x23f8 ... 0x23fa:
|
||||||
return true;
|
return true;
|
||||||
@@ -2895,6 +2942,8 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x26a0 ... 0x26a1:
|
case 0x26a0 ... 0x26a1:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x26a7:
|
||||||
|
return true;
|
||||||
case 0x26aa ... 0x26ab:
|
case 0x26aa ... 0x26ab:
|
||||||
return true;
|
return true;
|
||||||
case 0x26b0 ... 0x26b1:
|
case 0x26b0 ... 0x26b1:
|
||||||
@@ -2905,7 +2954,7 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x26c8:
|
case 0x26c8:
|
||||||
return true;
|
return true;
|
||||||
case 0x26cf:
|
case 0x26ce ... 0x26cf:
|
||||||
return true;
|
return true;
|
||||||
case 0x26d1:
|
case 0x26d1:
|
||||||
return true;
|
return true;
|
||||||
@@ -2921,9 +2970,9 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x2702:
|
case 0x2702:
|
||||||
return true;
|
return true;
|
||||||
case 0x2708 ... 0x2709:
|
case 0x2705:
|
||||||
return true;
|
return true;
|
||||||
case 0x270c ... 0x270d:
|
case 0x2708 ... 0x270d:
|
||||||
return true;
|
return true;
|
||||||
case 0x270f:
|
case 0x270f:
|
||||||
return true;
|
return true;
|
||||||
@@ -2937,20 +2986,32 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x2721:
|
case 0x2721:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x2728:
|
||||||
|
return true;
|
||||||
case 0x2733 ... 0x2734:
|
case 0x2733 ... 0x2734:
|
||||||
return true;
|
return true;
|
||||||
case 0x2744:
|
case 0x2744:
|
||||||
return true;
|
return true;
|
||||||
case 0x2747:
|
case 0x2747:
|
||||||
return true;
|
return true;
|
||||||
case 0x2753:
|
case 0x274c:
|
||||||
|
return true;
|
||||||
|
case 0x274e:
|
||||||
|
return true;
|
||||||
|
case 0x2753 ... 0x2755:
|
||||||
return true;
|
return true;
|
||||||
case 0x2757:
|
case 0x2757:
|
||||||
return true;
|
return true;
|
||||||
case 0x2763 ... 0x2764:
|
case 0x2763 ... 0x2764:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x2795 ... 0x2797:
|
||||||
|
return true;
|
||||||
case 0x27a1:
|
case 0x27a1:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x27b0:
|
||||||
|
return true;
|
||||||
|
case 0x27bf:
|
||||||
|
return true;
|
||||||
case 0x2934 ... 0x2935:
|
case 0x2934 ... 0x2935:
|
||||||
return true;
|
return true;
|
||||||
case 0x2b05 ... 0x2b07:
|
case 0x2b05 ... 0x2b07:
|
||||||
@@ -2971,125 +3032,51 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f004:
|
case 0x1f004:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x1f0cf:
|
||||||
|
return true;
|
||||||
case 0x1f170 ... 0x1f171:
|
case 0x1f170 ... 0x1f171:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f17e ... 0x1f17f:
|
case 0x1f17e ... 0x1f17f:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f202:
|
case 0x1f18e:
|
||||||
|
return true;
|
||||||
|
case 0x1f191 ... 0x1f19a:
|
||||||
|
return true;
|
||||||
|
case 0x1f1e6 ... 0x1f1ff:
|
||||||
|
return true;
|
||||||
|
case 0x1f201 ... 0x1f202:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f21a:
|
case 0x1f21a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f22f:
|
case 0x1f22f:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f237:
|
case 0x1f232 ... 0x1f23a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f30d ... 0x1f30f:
|
case 0x1f250 ... 0x1f251:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f315:
|
case 0x1f300 ... 0x1f321:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f31c:
|
case 0x1f324 ... 0x1f393:
|
||||||
return true;
|
|
||||||
case 0x1f321:
|
|
||||||
return true;
|
|
||||||
case 0x1f324 ... 0x1f32c:
|
|
||||||
return true;
|
|
||||||
case 0x1f336:
|
|
||||||
return true;
|
|
||||||
case 0x1f378:
|
|
||||||
return true;
|
|
||||||
case 0x1f37d:
|
|
||||||
return true;
|
|
||||||
case 0x1f393:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f396 ... 0x1f397:
|
case 0x1f396 ... 0x1f397:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f399 ... 0x1f39b:
|
case 0x1f399 ... 0x1f39b:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f39e ... 0x1f39f:
|
case 0x1f39e ... 0x1f3f0:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f3a7:
|
case 0x1f3f3 ... 0x1f3f5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f3ac ... 0x1f3ae:
|
case 0x1f3f7 ... 0x1f4fd:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f3c2:
|
case 0x1f4ff ... 0x1f53d:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f3c4:
|
case 0x1f549 ... 0x1f54e:
|
||||||
return true;
|
|
||||||
case 0x1f3c6:
|
|
||||||
return true;
|
|
||||||
case 0x1f3ca ... 0x1f3ce:
|
|
||||||
return true;
|
|
||||||
case 0x1f3d4 ... 0x1f3e0:
|
|
||||||
return true;
|
|
||||||
case 0x1f3ed:
|
|
||||||
return true;
|
|
||||||
case 0x1f3f3:
|
|
||||||
return true;
|
|
||||||
case 0x1f3f5:
|
|
||||||
return true;
|
|
||||||
case 0x1f3f7:
|
|
||||||
return true;
|
|
||||||
case 0x1f408:
|
|
||||||
return true;
|
|
||||||
case 0x1f415:
|
|
||||||
return true;
|
|
||||||
case 0x1f41f:
|
|
||||||
return true;
|
|
||||||
case 0x1f426:
|
|
||||||
return true;
|
|
||||||
case 0x1f43f:
|
|
||||||
return true;
|
|
||||||
case 0x1f441 ... 0x1f442:
|
|
||||||
return true;
|
|
||||||
case 0x1f446 ... 0x1f449:
|
|
||||||
return true;
|
|
||||||
case 0x1f44d ... 0x1f44e:
|
|
||||||
return true;
|
|
||||||
case 0x1f453:
|
|
||||||
return true;
|
|
||||||
case 0x1f46a:
|
|
||||||
return true;
|
|
||||||
case 0x1f47d:
|
|
||||||
return true;
|
|
||||||
case 0x1f4a3:
|
|
||||||
return true;
|
|
||||||
case 0x1f4b0:
|
|
||||||
return true;
|
|
||||||
case 0x1f4b3:
|
|
||||||
return true;
|
|
||||||
case 0x1f4bb:
|
|
||||||
return true;
|
|
||||||
case 0x1f4bf:
|
|
||||||
return true;
|
|
||||||
case 0x1f4cb:
|
|
||||||
return true;
|
|
||||||
case 0x1f4da:
|
|
||||||
return true;
|
|
||||||
case 0x1f4df:
|
|
||||||
return true;
|
|
||||||
case 0x1f4e4 ... 0x1f4e6:
|
|
||||||
return true;
|
|
||||||
case 0x1f4ea ... 0x1f4ed:
|
|
||||||
return true;
|
|
||||||
case 0x1f4f7:
|
|
||||||
return true;
|
|
||||||
case 0x1f4f9 ... 0x1f4fb:
|
|
||||||
return true;
|
|
||||||
case 0x1f4fd:
|
|
||||||
return true;
|
|
||||||
case 0x1f508:
|
|
||||||
return true;
|
|
||||||
case 0x1f50d:
|
|
||||||
return true;
|
|
||||||
case 0x1f512 ... 0x1f513:
|
|
||||||
return true;
|
|
||||||
case 0x1f549 ... 0x1f54a:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f550 ... 0x1f567:
|
case 0x1f550 ... 0x1f567:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f56f ... 0x1f570:
|
case 0x1f56f ... 0x1f570:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f573 ... 0x1f579:
|
case 0x1f573 ... 0x1f57a:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f587:
|
case 0x1f587:
|
||||||
return true;
|
return true;
|
||||||
@@ -3097,7 +3084,9 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f590:
|
case 0x1f590:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f5a5:
|
case 0x1f595 ... 0x1f596:
|
||||||
|
return true;
|
||||||
|
case 0x1f5a4 ... 0x1f5a5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f5a8:
|
case 0x1f5a8:
|
||||||
return true;
|
return true;
|
||||||
@@ -3121,39 +3110,49 @@ is_emoji_presentation_base(uint32_t code) {
|
|||||||
return true;
|
return true;
|
||||||
case 0x1f5f3:
|
case 0x1f5f3:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f5fa:
|
case 0x1f5fa ... 0x1f64f:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f610:
|
case 0x1f680 ... 0x1f6c5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f687:
|
case 0x1f6cb ... 0x1f6d2:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f68d:
|
case 0x1f6d5 ... 0x1f6d7:
|
||||||
return true;
|
|
||||||
case 0x1f691:
|
|
||||||
return true;
|
|
||||||
case 0x1f694:
|
|
||||||
return true;
|
|
||||||
case 0x1f698:
|
|
||||||
return true;
|
|
||||||
case 0x1f6ad:
|
|
||||||
return true;
|
|
||||||
case 0x1f6b2:
|
|
||||||
return true;
|
|
||||||
case 0x1f6b9 ... 0x1f6ba:
|
|
||||||
return true;
|
|
||||||
case 0x1f6bc:
|
|
||||||
return true;
|
|
||||||
case 0x1f6cb:
|
|
||||||
return true;
|
|
||||||
case 0x1f6cd ... 0x1f6cf:
|
|
||||||
return true;
|
return true;
|
||||||
case 0x1f6e0 ... 0x1f6e5:
|
case 0x1f6e0 ... 0x1f6e5:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f6e9:
|
case 0x1f6e9:
|
||||||
return true;
|
return true;
|
||||||
|
case 0x1f6eb ... 0x1f6ec:
|
||||||
|
return true;
|
||||||
case 0x1f6f0:
|
case 0x1f6f0:
|
||||||
return true;
|
return true;
|
||||||
case 0x1f6f3:
|
case 0x1f6f3 ... 0x1f6fc:
|
||||||
|
return true;
|
||||||
|
case 0x1f7e0 ... 0x1f7eb:
|
||||||
|
return true;
|
||||||
|
case 0x1f90c ... 0x1f93a:
|
||||||
|
return true;
|
||||||
|
case 0x1f93c ... 0x1f945:
|
||||||
|
return true;
|
||||||
|
case 0x1f947 ... 0x1f978:
|
||||||
|
return true;
|
||||||
|
case 0x1f97a ... 0x1f9cb:
|
||||||
|
return true;
|
||||||
|
case 0x1f9cd ... 0x1f9ff:
|
||||||
|
return true;
|
||||||
|
case 0x1fa70 ... 0x1fa74:
|
||||||
|
return true;
|
||||||
|
case 0x1fa78 ... 0x1fa7a:
|
||||||
|
return true;
|
||||||
|
case 0x1fa80 ... 0x1fa86:
|
||||||
|
return true;
|
||||||
|
case 0x1fa90 ... 0x1faa8:
|
||||||
|
return true;
|
||||||
|
case 0x1fab0 ... 0x1fab6:
|
||||||
|
return true;
|
||||||
|
case 0x1fac0 ... 0x1fac2:
|
||||||
|
return true;
|
||||||
|
case 0x1fad0 ... 0x1fad6:
|
||||||
return true;
|
return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,14 +25,15 @@ from .fast_data_types import (
|
|||||||
MARK, MARK_MASK, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE,
|
MARK, MARK_MASK, OSC, REVERSE, SCROLL_FULL, SCROLL_LINE, SCROLL_PAGE,
|
||||||
STRIKETHROUGH, TINT_PROGRAM, Screen, add_window, cell_size_for_window,
|
STRIKETHROUGH, TINT_PROGRAM, Screen, add_window, cell_size_for_window,
|
||||||
compile_program, get_boss, get_clipboard_string, init_cell_program,
|
compile_program, get_boss, get_clipboard_string, init_cell_program,
|
||||||
set_clipboard_string, set_titlebar_color, set_window_render_data,
|
pt_to_px, set_clipboard_string, set_titlebar_color, set_window_padding,
|
||||||
update_window_title, update_window_visibility, viewport_for_window
|
set_window_render_data, update_window_title, update_window_visibility,
|
||||||
|
viewport_for_window
|
||||||
)
|
)
|
||||||
from .keys import defines, extended_key_event, keyboard_mode_name
|
from .keys import defines, extended_key_event, keyboard_mode_name
|
||||||
from .options_stub import Options
|
from .options_stub import Options
|
||||||
from .rgb import to_color
|
from .rgb import to_color
|
||||||
from .terminfo import get_capabilities
|
from .terminfo import get_capabilities
|
||||||
from .typing import BossType, ChildType, TabType, TypedDict
|
from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict
|
||||||
from .utils import (
|
from .utils import (
|
||||||
color_as_int, get_primary_selection, load_shaders, open_cmd, open_url,
|
color_as_int, get_primary_selection, load_shaders, open_cmd, open_url,
|
||||||
parse_color_set, read_shell_environment, sanitize_title,
|
parse_color_set, read_shell_environment, sanitize_title,
|
||||||
@@ -185,6 +186,25 @@ def text_sanitizer(as_ansi: bool, add_wrap_markers: bool) -> Callable[[str], str
|
|||||||
return remove_wrap_markers
|
return remove_wrap_markers
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeWidths:
|
||||||
|
left: Optional[float]
|
||||||
|
top: Optional[float]
|
||||||
|
right: Optional[float]
|
||||||
|
bottom: Optional[float]
|
||||||
|
|
||||||
|
def __init__(self, serialized: Optional[Dict[str, Optional[float]]] = None):
|
||||||
|
if serialized is not None:
|
||||||
|
self.left = serialized['left']
|
||||||
|
self.right = serialized['right']
|
||||||
|
self.top = serialized['top']
|
||||||
|
self.bottom = serialized['bottom']
|
||||||
|
else:
|
||||||
|
self.left = self.top = self.right = self.bottom = None
|
||||||
|
|
||||||
|
def serialize(self) -> Dict[str, Optional[float]]:
|
||||||
|
return {'left': self.left, 'right': self.right, 'top': self.top, 'bottom': self.bottom}
|
||||||
|
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -211,6 +231,8 @@ class Window:
|
|||||||
self.title_stack: Deque[str] = deque(maxlen=10)
|
self.title_stack: Deque[str] = deque(maxlen=10)
|
||||||
self.allow_remote_control = child.allow_remote_control
|
self.allow_remote_control = child.allow_remote_control
|
||||||
self.id = add_window(tab.os_window_id, tab.id, self.title)
|
self.id = add_window(tab.os_window_id, tab.id, self.title)
|
||||||
|
self.margin = EdgeWidths()
|
||||||
|
self.padding = EdgeWidths()
|
||||||
if not self.id:
|
if not self.id:
|
||||||
raise Exception('No tab with id: {} in OS Window: {} was found, or the window counter wrapped'.format(tab.id, tab.os_window_id))
|
raise Exception('No tab with id: {} in OS Window: {} was found, or the window counter wrapped'.format(tab.id, tab.os_window_id))
|
||||||
self.tab_id = tab.id
|
self.tab_id = tab.id
|
||||||
@@ -229,11 +251,47 @@ class Window:
|
|||||||
else:
|
else:
|
||||||
setup_colors(self.screen, opts)
|
setup_colors(self.screen, opts)
|
||||||
|
|
||||||
|
def on_dpi_change(self, font_sz: float) -> None:
|
||||||
|
self.update_effective_padding()
|
||||||
|
|
||||||
def change_tab(self, tab: TabType) -> None:
|
def change_tab(self, tab: TabType) -> None:
|
||||||
self.tab_id = tab.id
|
self.tab_id = tab.id
|
||||||
self.os_window_id = tab.os_window_id
|
self.os_window_id = tab.os_window_id
|
||||||
self.tabref = weakref.ref(tab)
|
self.tabref = weakref.ref(tab)
|
||||||
|
|
||||||
|
def effective_margin(self, edge: EdgeLiteral, is_single_window: bool = False) -> int:
|
||||||
|
q = getattr(self.margin, edge)
|
||||||
|
if q is not None:
|
||||||
|
return pt_to_px(q, self.os_window_id)
|
||||||
|
if is_single_window:
|
||||||
|
q = getattr(self.opts.single_window_margin_width, edge)
|
||||||
|
if q > -0.1:
|
||||||
|
return pt_to_px(q, self.os_window_id)
|
||||||
|
q = getattr(self.opts.window_margin_width, edge)
|
||||||
|
return pt_to_px(q, self.os_window_id)
|
||||||
|
|
||||||
|
def effective_padding(self, edge: EdgeLiteral) -> int:
|
||||||
|
q = getattr(self.padding, edge)
|
||||||
|
if q is not None:
|
||||||
|
return pt_to_px(q, self.os_window_id)
|
||||||
|
q = getattr(self.opts.window_padding_width, edge)
|
||||||
|
return pt_to_px(q, self.os_window_id)
|
||||||
|
|
||||||
|
def update_effective_padding(self) -> None:
|
||||||
|
set_window_padding(
|
||||||
|
self.os_window_id, self.tab_id, self.id,
|
||||||
|
self.effective_padding('left'), self.effective_padding('top'),
|
||||||
|
self.effective_padding('right'), self.effective_padding('bottom'))
|
||||||
|
|
||||||
|
def patch_edge_width(self, which: str, edge: EdgeLiteral, val: Optional[float]) -> None:
|
||||||
|
q = self.padding if which == 'padding' else self.margin
|
||||||
|
setattr(q, edge, val)
|
||||||
|
if q is self.padding:
|
||||||
|
self.update_effective_padding()
|
||||||
|
|
||||||
|
def effective_border(self) -> int:
|
||||||
|
return pt_to_px(self.opts.window_border_width, self.os_window_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self) -> str:
|
def title(self) -> str:
|
||||||
return self.override_title or self.child_title
|
return self.override_title or self.child_title
|
||||||
@@ -254,6 +312,24 @@ class Window:
|
|||||||
foreground_processes=self.child.foreground_processes
|
foreground_processes=self.child.foreground_processes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def serialize_state(self) -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
'version': 1,
|
||||||
|
'id': self.id,
|
||||||
|
'child_title': self.child_title,
|
||||||
|
'override_title': self.override_title,
|
||||||
|
'default_title': self.default_title,
|
||||||
|
'title_stack': list(self.title_stack),
|
||||||
|
'allow_remote_control': self.allow_remote_control,
|
||||||
|
'overlay_window_id': self.overlay_window_id,
|
||||||
|
'overlay_for': self.overlay_for,
|
||||||
|
'cwd': self.child.current_cwd or self.child.cwd,
|
||||||
|
'env': self.child.environ,
|
||||||
|
'cmdline': self.child.cmdline,
|
||||||
|
'margin': self.margin.serialize(),
|
||||||
|
'padding': self.padding.serialize(),
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_colors(self) -> Dict:
|
def current_colors(self) -> Dict:
|
||||||
return self.screen.color_profile.as_dict()
|
return self.screen.color_profile.as_dict()
|
||||||
@@ -323,6 +399,7 @@ class Window:
|
|||||||
sg = self.update_position(new_geometry)
|
sg = self.update_position(new_geometry)
|
||||||
self.geometry = g = new_geometry
|
self.geometry = g = new_geometry
|
||||||
set_window_render_data(self.os_window_id, self.tab_id, self.id, window_idx, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen, *g[:4])
|
set_window_render_data(self.os_window_id, self.tab_id, self.id, window_idx, sg.xstart, sg.ystart, sg.dx, sg.dy, self.screen, *g[:4])
|
||||||
|
self.update_effective_padding()
|
||||||
|
|
||||||
def contains(self, x: int, y: int) -> bool:
|
def contains(self, x: int, y: int) -> bool:
|
||||||
g = self.geometry
|
g = self.geometry
|
||||||
|
|||||||
@@ -359,6 +359,10 @@ class TestDataTypes(BaseTest):
|
|||||||
self.ae(wcswidth('\033a\033[2mb'), 2)
|
self.ae(wcswidth('\033a\033[2mb'), 2)
|
||||||
self.ae(wcswidth('\u25b6\ufe0f'), 2)
|
self.ae(wcswidth('\u25b6\ufe0f'), 2)
|
||||||
self.ae(wcswidth('\U0001f610\ufe0e'), 1)
|
self.ae(wcswidth('\U0001f610\ufe0e'), 1)
|
||||||
|
self.ae(wcswidth('\U0001f1e6a'), 3)
|
||||||
|
self.ae(wcswidth('\U0001F1E6a\U0001F1E8a'), 6)
|
||||||
|
self.ae(wcswidth('\U0001F1E6\U0001F1E8a'), 3)
|
||||||
|
self.ae(wcswidth('\U0001F1E6\U0001F1E8\U0001F1E6'), 4)
|
||||||
# Regional indicator symbols (unicode flags) are defined as having
|
# Regional indicator symbols (unicode flags) are defined as having
|
||||||
# Emoji_Presentation so must have width 2
|
# Emoji_Presentation so must have width 2
|
||||||
self.ae(tuple(map(w, '\U0001f1ee\U0001f1f3')), (2, 2))
|
self.ae(tuple(map(w, '\U0001f1ee\U0001f1f3')), (2, 2))
|
||||||
|
|||||||
@@ -80,26 +80,25 @@ class TestParser(BaseTest):
|
|||||||
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
km(modify_key_bytes(base_key, num).decode('ascii')[1:], key)
|
||||||
|
|
||||||
def test_encode_mouse_event(self):
|
def test_encode_mouse_event(self):
|
||||||
PRESS, RELEASE, DRAG, MOVE = range(4)
|
|
||||||
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
|
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
|
||||||
L, M, R = defines.GLFW_MOUSE_BUTTON_LEFT, defines.GLFW_MOUSE_BUTTON_MIDDLE, defines.GLFW_MOUSE_BUTTON_RIGHT
|
L, M, R = defines.GLFW_MOUSE_BUTTON_LEFT, defines.GLFW_MOUSE_BUTTON_MIDDLE, defines.GLFW_MOUSE_BUTTON_RIGHT
|
||||||
protocol = SGR_PROTOCOL
|
protocol = SGR_PROTOCOL
|
||||||
|
|
||||||
def enc(button=L, action=PRESS, mods=0, x=1, y=1):
|
def enc(button=L, action=defines.PRESS, mods=0, x=1, y=1):
|
||||||
return defines.test_encode_mouse(x, y, protocol, button, action, mods)
|
return defines.test_encode_mouse(x, y, protocol, button, action, mods)
|
||||||
|
|
||||||
self.ae(enc(), '<0;1;1M')
|
self.ae(enc(), '<0;1;1M')
|
||||||
self.ae(enc(action=RELEASE), '<0;1;1m')
|
self.ae(enc(action=defines.RELEASE), '<0;1;1m')
|
||||||
self.ae(enc(action=MOVE), '<35;1;1M')
|
self.ae(enc(action=defines.MOVE), '<35;1;1M')
|
||||||
self.ae(enc(action=DRAG), '<32;1;1M')
|
self.ae(enc(action=defines.DRAG), '<32;1;1M')
|
||||||
|
|
||||||
self.ae(enc(R), '<2;1;1M')
|
self.ae(enc(R), '<2;1;1M')
|
||||||
self.ae(enc(R, action=RELEASE), '<2;1;1m')
|
self.ae(enc(R, action=defines.RELEASE), '<2;1;1m')
|
||||||
self.ae(enc(R, action=DRAG), '<34;1;1M')
|
self.ae(enc(R, action=defines.DRAG), '<34;1;1M')
|
||||||
|
|
||||||
self.ae(enc(M), '<1;1;1M')
|
self.ae(enc(M), '<1;1;1M')
|
||||||
self.ae(enc(M, action=RELEASE), '<1;1;1m')
|
self.ae(enc(M, action=defines.RELEASE), '<1;1;1m')
|
||||||
self.ae(enc(M, action=DRAG), '<33;1;1M')
|
self.ae(enc(M, action=defines.DRAG), '<33;1;1M')
|
||||||
|
|
||||||
self.ae(enc(x=1234, y=5678), '<0;1234;5678M')
|
self.ae(enc(x=1234, y=5678), '<0;1234;5678M')
|
||||||
self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
|
self.ae(enc(mods=defines.GLFW_MOD_SHIFT), '<4;1;1M')
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
from kitty.config import defaults
|
from kitty.config import defaults
|
||||||
from kitty.fast_data_types import pt_to_px
|
|
||||||
from kitty.layout import Horizontal, Stack, Tall, Grid, idx_for_id, Splits
|
|
||||||
from kitty.constants import WindowGeometry
|
from kitty.constants import WindowGeometry
|
||||||
|
from kitty.layout import Grid, Horizontal, Splits, Stack, Tall, idx_for_id
|
||||||
|
from kitty.window import EdgeWidths
|
||||||
|
|
||||||
from . import BaseTest
|
from . import BaseTest
|
||||||
|
|
||||||
@@ -18,6 +18,17 @@ class Window:
|
|||||||
self.overlay_window_id = overlay_window_id
|
self.overlay_window_id = overlay_window_id
|
||||||
self.is_visible_in_layout = True
|
self.is_visible_in_layout = True
|
||||||
self.geometry = WindowGeometry(0, 0, 0, 0, 0, 0)
|
self.geometry = WindowGeometry(0, 0, 0, 0, 0, 0)
|
||||||
|
self.padding = EdgeWidths()
|
||||||
|
self.margin = EdgeWidths()
|
||||||
|
|
||||||
|
def effective_border(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def effective_padding(self, edge):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def effective_margin(self, edge, is_single_window=False):
|
||||||
|
return 0 if is_single_window else 1
|
||||||
|
|
||||||
def set_visible_in_layout(self, idx, val):
|
def set_visible_in_layout(self, idx, val):
|
||||||
self.is_visible_in_layout = bool(val)
|
self.is_visible_in_layout = bool(val)
|
||||||
@@ -29,8 +40,7 @@ class Window:
|
|||||||
def create_layout(cls, opts=None, border_width=2):
|
def create_layout(cls, opts=None, border_width=2):
|
||||||
if opts is None:
|
if opts is None:
|
||||||
opts = defaults
|
opts = defaults
|
||||||
mw, pw = map(pt_to_px, (opts.window_margin_width, opts.window_padding_width))
|
ans = cls(1, 1)
|
||||||
ans = cls(1, 1, mw, mw, pw, border_width)
|
|
||||||
ans.set_active_window_in_os_window = lambda idx: None
|
ans.set_active_window_in_os_window = lambda idx: None
|
||||||
ans.swap_windows_in_os_window = lambda a, b: None
|
ans.swap_windows_in_os_window = lambda a, b: None
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
@@ -456,12 +456,16 @@ class TestScreen(BaseTest):
|
|||||||
self.ae(as_text(True), '\x1b[mababa\x1b[mbabab\n\x1b[mc\n\n')
|
self.ae(as_text(True), '\x1b[mababa\x1b[mbabab\n\x1b[mc\n\n')
|
||||||
|
|
||||||
def test_user_marking(self):
|
def test_user_marking(self):
|
||||||
|
|
||||||
|
def cells(*a, y=0, mark=3):
|
||||||
|
return [(x, y, mark) for x in a]
|
||||||
|
|
||||||
s = self.create_screen()
|
s = self.create_screen()
|
||||||
s.draw('abaa')
|
s.draw('abaa')
|
||||||
s.carriage_return(), s.linefeed()
|
s.carriage_return(), s.linefeed()
|
||||||
s.draw('xyxyx')
|
s.draw('xyxyx')
|
||||||
s.set_marker(marker_from_regex('a', 3))
|
s.set_marker(marker_from_regex('a', 3))
|
||||||
self.ae(s.marked_cells(), [(0, 0, 3), (2, 0, 3), (3, 0, 3)])
|
self.ae(s.marked_cells(), cells(0, 2, 3))
|
||||||
s.set_marker()
|
s.set_marker()
|
||||||
self.ae(s.marked_cells(), [])
|
self.ae(s.marked_cells(), [])
|
||||||
|
|
||||||
@@ -488,3 +492,19 @@ class TestScreen(BaseTest):
|
|||||||
self.assertTrue(s.scroll_to_next_mark(0, False))
|
self.assertTrue(s.scroll_to_next_mark(0, False))
|
||||||
self.ae(s.scrolled_by, 10 - i - 1)
|
self.ae(s.scrolled_by, 10 - i - 1)
|
||||||
self.ae(s.scrolled_by, 0)
|
self.ae(s.scrolled_by, 0)
|
||||||
|
|
||||||
|
s = self.create_screen()
|
||||||
|
s.draw('🐈ab')
|
||||||
|
s.set_marker(marker_from_regex('🐈', 3))
|
||||||
|
self.ae(s.marked_cells(), cells(0, 1))
|
||||||
|
s.set_marker(marker_from_regex('🐈a', 3))
|
||||||
|
self.ae(s.marked_cells(), cells(0, 1, 2))
|
||||||
|
s.set_marker(marker_from_regex('a', 3))
|
||||||
|
self.ae(s.marked_cells(), cells(2))
|
||||||
|
s = self.create_screen(cols=20)
|
||||||
|
s.tab()
|
||||||
|
s.draw('ab')
|
||||||
|
s.set_marker(marker_from_regex('a', 3))
|
||||||
|
self.ae(s.marked_cells(), cells(8))
|
||||||
|
s.set_marker(marker_from_regex('\t', 3))
|
||||||
|
self.ae(s.marked_cells(), cells(*range(8)))
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#define KITTY_LIB_DIR_NAME "lib"
|
#define KITTY_LIB_DIR_NAME "lib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FreeBSD__
|
||||||
static inline bool
|
static inline bool
|
||||||
safe_realpath(const char* src, char *buf, size_t buf_sz) {
|
safe_realpath(const char* src, char *buf, size_t buf_sz) {
|
||||||
char* ans = realpath(src, NULL);
|
char* ans = realpath(src, NULL);
|
||||||
@@ -39,6 +40,7 @@ safe_realpath(const char* src, char *buf, size_t buf_sz) {
|
|||||||
free(ans);
|
free(ans);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_bundle_exe_dir(const wchar_t *exe_dir) {
|
set_bundle_exe_dir(const wchar_t *exe_dir) {
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
files = [x for x in sys.argv[1:] if not x.startswith('-')]
|
base = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
files = [os.path.relpath(x, base) for x in sys.argv[1:] if not x.startswith('-')]
|
||||||
if not files:
|
if not files:
|
||||||
raise SystemExit(subprocess.Popen(['mypy'] + sys.argv[1:]).wait())
|
raise SystemExit(subprocess.Popen(['mypy'] + sys.argv[1:]).wait())
|
||||||
|
|
||||||
output = subprocess.run('dmypy run -- --follow-imports=error --show-column-numbers --no-color-output'.split(), stdout=subprocess.PIPE).stdout
|
output = subprocess.run('dmypy run -- --follow-imports=error --show-column-numbers --no-color-output'.split(), stdout=subprocess.PIPE).stdout
|
||||||
q = files[0] + ':'
|
q = files[0] + ':'
|
||||||
|
rc = 0
|
||||||
for line in output.decode('utf-8').splitlines():
|
for line in output.decode('utf-8').splitlines():
|
||||||
if line.startswith(q):
|
if line.startswith(q):
|
||||||
print(line)
|
print(line)
|
||||||
|
rc = 1
|
||||||
|
raise SystemExit(rc)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ set tabstop=4
|
|||||||
set shiftwidth=4
|
set shiftwidth=4
|
||||||
set softtabstop=0
|
set softtabstop=0
|
||||||
set smarttab
|
set smarttab
|
||||||
python <<endpython
|
python3 <<endpython
|
||||||
import sys
|
import sys
|
||||||
sys.path.insert(0, os.path.abspath('.'))
|
sys.path.insert(0, os.path.abspath('.'))
|
||||||
import kitty
|
import kitty
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -349,7 +349,7 @@ def run_tool(cmd: Union[str, List[str]], desc: Optional[str] = None) -> None:
|
|||||||
raise SystemExit(ret)
|
raise SystemExit(ret)
|
||||||
|
|
||||||
|
|
||||||
def get_vcs_rev_defines() -> List[str]:
|
def get_vcs_rev_defines(env: Env) -> List[str]:
|
||||||
ans = []
|
ans = []
|
||||||
if os.path.exists('.git'):
|
if os.path.exists('.git'):
|
||||||
try:
|
try:
|
||||||
@@ -368,7 +368,7 @@ def get_vcs_rev_defines() -> List[str]:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
SPECIAL_SOURCES: Dict[str, Tuple[str, Union[List[str], Callable[[], Union[List[str], Iterator[str]]]]]] = {
|
SPECIAL_SOURCES: Dict[str, Tuple[str, Union[List[str], Callable[[Env], Union[List[str], Iterator[str]]]]]] = {
|
||||||
'kitty/parser_dump.c': ('kitty/parser.c', ['DUMP_COMMANDS']),
|
'kitty/parser_dump.c': ('kitty/parser.c', ['DUMP_COMMANDS']),
|
||||||
'kitty/data-types.c': ('kitty/data-types.c', get_vcs_rev_defines),
|
'kitty/data-types.c': ('kitty/data-types.c', get_vcs_rev_defines),
|
||||||
}
|
}
|
||||||
@@ -557,7 +557,7 @@ def compile_c_extension(
|
|||||||
if is_special:
|
if is_special:
|
||||||
src, defines_ = SPECIAL_SOURCES[src]
|
src, defines_ = SPECIAL_SOURCES[src]
|
||||||
if callable(defines_):
|
if callable(defines_):
|
||||||
defines = defines_()
|
defines = defines_(kenv)
|
||||||
cppflags.extend(map(define, defines))
|
cppflags.extend(map(define, defines))
|
||||||
else:
|
else:
|
||||||
cppflags.extend(map(define, defines_))
|
cppflags.extend(map(define, defines_))
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ xterm-kitty|KovIdTTY,
|
|||||||
rmkx=\E[?1l,
|
rmkx=\E[?1l,
|
||||||
rmso=\E[27m,
|
rmso=\E[27m,
|
||||||
rmul=\E[24m,
|
rmul=\E[24m,
|
||||||
|
rmxx=\E[29m,
|
||||||
rs1=\E]\E\\\Ec,
|
rs1=\E]\E\\\Ec,
|
||||||
sc=\E7,
|
sc=\E7,
|
||||||
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
||||||
@@ -231,6 +232,7 @@ xterm-kitty|KovIdTTY,
|
|||||||
smkx=\E[?1h,
|
smkx=\E[?1h,
|
||||||
smso=\E[7m,
|
smso=\E[7m,
|
||||||
smul=\E[4m,
|
smul=\E[4m,
|
||||||
|
smxx=\E[9m,
|
||||||
tbc=\E[3g,
|
tbc=\E[3g,
|
||||||
tsl=\E]2;,
|
tsl=\E]2;,
|
||||||
vpa=\E[%i%p1%dd,
|
vpa=\E[%i%p1%dd,
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user