@@ -13,6 +13,8 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
- Add a new mappable `select_tab` action to choose a tab to switch to even
|
||||
when the tab bar is hidden (:iss:`3115`)
|
||||
|
||||
- Allow specifying text formatting in :opt:`tab_title_template` (:iss:`3146`)
|
||||
|
||||
- Graphics protocol: Add support for giving individual image placements their
|
||||
own ids. This is a backwards compatible protocol extension, and also allow
|
||||
suppressing responses from the terminal to commands (:iss:`3133`)
|
||||
|
||||
@@ -939,6 +939,10 @@ 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.
|
||||
If you want to style the text, you can use styling directives, for example:
|
||||
:code:`{fmt.fg.red}red{fmt.fg.default}normal{fmt.bg._00FF00}green bg{fmt.bg.normal}`.
|
||||
Similarly, for bold and italic:
|
||||
:code:`{fmt.bold}bold{fmt.nobold}normal{fmt.italic}italic{fmt.noitalic}`.
|
||||
'''))
|
||||
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
|
||||
|
||||
@@ -1002,6 +1002,9 @@ class Screen:
|
||||
def draw(self, text: str) -> None:
|
||||
pass
|
||||
|
||||
def apply_sgr(self, text: str) -> None:
|
||||
pass
|
||||
|
||||
def copy_colors_from(self, other: 'Screen') -> None:
|
||||
pass
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ utf8(char_type codepoint) {
|
||||
// }}}
|
||||
|
||||
// Macros {{{
|
||||
#define MAX_PARAMS 256
|
||||
#define IS_DIGIT \
|
||||
case '0': \
|
||||
case '1': \
|
||||
@@ -465,7 +464,10 @@ repr_csi_params(unsigned int *params, unsigned int num_params) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline void
|
||||
#ifdef DUMP_COMMANDS
|
||||
static
|
||||
#endif
|
||||
void
|
||||
parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params, PyObject DUMP_UNUSED *dump_callback, const char *report_name DUMP_UNUSED, Region *region) {
|
||||
enum State { START, NORMAL, MULTIPLE, COLOR, COLOR1, COLOR3 };
|
||||
enum State state = START;
|
||||
|
||||
@@ -2137,6 +2137,20 @@ draw(Screen *self, PyObject *src) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
extern void
|
||||
parse_sgr(Screen *screen, uint32_t *buf, unsigned int num, unsigned int *params, PyObject *dump_callback, const char *report_name, Region *region);
|
||||
|
||||
static PyObject*
|
||||
apply_sgr(Screen *self, PyObject *src) {
|
||||
if (!PyUnicode_Check(src)) { PyErr_SetString(PyExc_TypeError, "A unicode string is required"); return NULL; }
|
||||
if (PyUnicode_READY(src) != 0) { return PyErr_NoMemory(); }
|
||||
Py_UCS4 *buf = PyUnicode_AsUCS4Copy(src);
|
||||
if (!buf) return NULL;
|
||||
unsigned int params[MAX_PARAMS] = {0};
|
||||
parse_sgr(self, buf, PyUnicode_GET_LENGTH(src), params, NULL, "parse_sgr", NULL);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
reset_mode(Screen *self, PyObject *args) {
|
||||
int private = false;
|
||||
@@ -2783,6 +2797,7 @@ static PyMethodDef methods[] = {
|
||||
MND(visual_line, METH_VARARGS)
|
||||
MND(current_url_text, METH_NOARGS)
|
||||
MND(draw, METH_O)
|
||||
MND(apply_sgr, METH_O)
|
||||
MND(cursor_position, METH_VARARGS)
|
||||
MND(set_mode, METH_VARARGS)
|
||||
MND(reset_mode, METH_VARARGS)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "graphics.h"
|
||||
#include "monotonic.h"
|
||||
#define MAX_PARAMS 256
|
||||
|
||||
typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } ScrollType;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ from .fast_data_types import (
|
||||
)
|
||||
from .layout.base import Rect
|
||||
from .options_stub import Options
|
||||
from .rgb import Color, alpha_blend, color_from_int
|
||||
from .rgb import Color, alpha_blend, color_as_sgr, color_from_int, to_color
|
||||
from .utils import color_as_int, log_error
|
||||
from .window import calculate_gl_geometry
|
||||
|
||||
@@ -61,6 +61,35 @@ def compile_template(template: str) -> Any:
|
||||
report_template_failure(template, str(e))
|
||||
|
||||
|
||||
class ColorFormatter:
|
||||
|
||||
def __init__(self, which: str):
|
||||
self.which = which
|
||||
|
||||
def __getattr__(self, name: str) -> str:
|
||||
q = name
|
||||
if q == 'default':
|
||||
ans = '9'
|
||||
else:
|
||||
if name.startswith('_'):
|
||||
q = '#' + name[1:]
|
||||
c = to_color(q)
|
||||
if c is None:
|
||||
raise AttributeError(f'{name} is not a valid color')
|
||||
ans = '8' + color_as_sgr(c)
|
||||
return f'\x1b[{self.which}{ans}m'
|
||||
|
||||
|
||||
class Formatter:
|
||||
reset = '\x1b[0m'
|
||||
fg = ColorFormatter('3')
|
||||
bg = ColorFormatter('4')
|
||||
bold = '\x1b[1m'
|
||||
nobold = '\x1b[22m'
|
||||
italic = '\x1b[3m'
|
||||
noitalic = '\x1b[23m'
|
||||
|
||||
|
||||
def draw_title(draw_data: DrawData, screen: Screen, tab: TabBarData, index: int) -> None:
|
||||
if tab.needs_attention and draw_data.bell_on_tab:
|
||||
fg = screen.cursor.fg
|
||||
@@ -81,13 +110,22 @@ def draw_title(draw_data: DrawData, screen: Screen, tab: TabBarData, index: int)
|
||||
'index': index,
|
||||
'layout_name': tab.layout_name,
|
||||
'num_windows': tab.num_windows,
|
||||
'title': tab.title
|
||||
'title': tab.title,
|
||||
'fmt': Formatter,
|
||||
}
|
||||
title = eval(compile_template(template), {'__builtins__': {}}, eval_locals)
|
||||
except Exception as e:
|
||||
report_template_failure(template, str(e))
|
||||
title = tab.title
|
||||
screen.draw(title)
|
||||
if '\x1b' in title:
|
||||
import re
|
||||
for x in re.split('(\x1b\\[[^m]*m)', title):
|
||||
if x.startswith('\x1b') and x.endswith('m'):
|
||||
screen.apply_sgr(x[2:-1])
|
||||
else:
|
||||
screen.draw(x)
|
||||
else:
|
||||
screen.draw(title)
|
||||
|
||||
|
||||
def draw_tab_with_separator(draw_data: DrawData, screen: Screen, tab: TabBarData, before: int, max_title_length: int, index: int, is_last: bool) -> int:
|
||||
|
||||
Reference in New Issue
Block a user