Utility method to truncate formatted lines to specified width
This commit is contained in:
parent
61a2360df5
commit
0be0963dc7
@ -80,7 +80,7 @@ class DiffHandler(Handler):
|
|||||||
else:
|
else:
|
||||||
text = self.diff_lines[lpos].text
|
text = self.diff_lines[lpos].text
|
||||||
self.write(text)
|
self.write(text)
|
||||||
self.write('\n\r')
|
self.write('\x1b[0m\n\r')
|
||||||
|
|
||||||
def on_key(self, key_event):
|
def on_key(self, key_event):
|
||||||
if self.state is INITIALIZING:
|
if self.state is INITIALIZING:
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
import re
|
import re
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
from kitty.fast_data_types import wcswidth
|
from kitty.fast_data_types import truncate_point_for_length
|
||||||
|
|
||||||
from .collect import data_for_path, path_name_map
|
from .collect import data_for_path, path_name_map
|
||||||
from .config import formats
|
from .config import formats
|
||||||
@ -60,13 +60,16 @@ def sanitize(text):
|
|||||||
|
|
||||||
|
|
||||||
def fit_in(text, count):
|
def fit_in(text, count):
|
||||||
w = wcswidth(text)
|
p = truncate_point_for_length(text, count)
|
||||||
if w <= count:
|
if p >= len(text):
|
||||||
return text
|
return text
|
||||||
text = text[:count-1]
|
if count > 1:
|
||||||
while wcswidth(text) > count - 1:
|
p = truncate_point_for_length(text, count - 1)
|
||||||
text = text[:-1]
|
return text[:p] + '…'
|
||||||
return text + '…'
|
|
||||||
|
|
||||||
|
def place_in(text, sz):
|
||||||
|
return fit_in(text, sz).ljust(sz)
|
||||||
|
|
||||||
|
|
||||||
def format_func(which):
|
def format_func(which):
|
||||||
@ -82,10 +85,6 @@ title_format = format_func('title')
|
|||||||
margin_format = format_func('margin')
|
margin_format = format_func('margin')
|
||||||
|
|
||||||
|
|
||||||
def place_in(text, sz):
|
|
||||||
return fit_in(text, sz).ljust(sz)
|
|
||||||
|
|
||||||
|
|
||||||
def title_lines(left_path, right_path, args, columns, margin_size):
|
def title_lines(left_path, right_path, args, columns, margin_size):
|
||||||
name = fit_in(sanitize(path_name_map[left_path]), columns - 2 * margin_size)
|
name = fit_in(sanitize(path_name_map[left_path]), columns - 2 * margin_size)
|
||||||
yield title_format((' ' + name).ljust(columns))
|
yield title_format((' ' + name).ljust(columns))
|
||||||
@ -99,13 +98,23 @@ def binary_lines(path, other_path, columns, margin_size):
|
|||||||
def fl(path):
|
def fl(path):
|
||||||
text = template.format(human_readable(len(data_for_path(path))))
|
text = template.format(human_readable(len(data_for_path(path))))
|
||||||
text = place_in(text, columns // 2 - margin_size)
|
text = place_in(text, columns // 2 - margin_size)
|
||||||
return margin_format(' ' * margin_size) + text_format(text)
|
return margin_format(' ' * margin_size) + text_format(text) + '\x1b[0m'
|
||||||
|
|
||||||
return fl(path) + fl(other_path)
|
return fl(path) + fl(other_path)
|
||||||
|
|
||||||
|
|
||||||
|
def split_to_size(line, width):
|
||||||
|
while line:
|
||||||
|
p = truncate_point_for_length(line, width)
|
||||||
|
yield line[:p]
|
||||||
|
line = line[p:]
|
||||||
|
|
||||||
|
|
||||||
def lines_for_diff(left_path, right_path, hunks, args, columns, margin_size):
|
def lines_for_diff(left_path, right_path, hunks, args, columns, margin_size):
|
||||||
return iter(())
|
available_cols = columns // 2 - margin_size
|
||||||
|
for hunk_num, hunk in enumerate(hunks):
|
||||||
|
for line_num, (left, right) in enumerate(zip(hunk.left_lines, hunk.right_lines)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def render_diff(collection, diff_map, args, columns):
|
def render_diff(collection, diff_map, args, columns):
|
||||||
|
|||||||
@ -1516,6 +1516,52 @@ screen_wcswidth(PyObject UNUSED *self, PyObject *str) {
|
|||||||
return PyLong_FromUnsignedLong(ans);
|
return PyLong_FromUnsignedLong(ans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
screen_truncate_point_for_length(PyObject UNUSED *self, PyObject *args) {
|
||||||
|
PyObject *str; unsigned int num_cells;
|
||||||
|
if (!PyArg_ParseTuple(args, "OI", &str, &num_cells)) return NULL;
|
||||||
|
if (PyUnicode_READY(str) != 0) return NULL;
|
||||||
|
int kind = PyUnicode_KIND(str);
|
||||||
|
void *data = PyUnicode_DATA(str);
|
||||||
|
Py_ssize_t len = PyUnicode_GET_LENGTH(str), i;
|
||||||
|
char_type prev_ch = 0;
|
||||||
|
int prev_width = 0;
|
||||||
|
bool in_sgr = false;
|
||||||
|
unsigned long width_so_far = 0;
|
||||||
|
for (i = 0; i < len && width_so_far < num_cells; i++) {
|
||||||
|
char_type ch = PyUnicode_READ(kind, data, i);
|
||||||
|
if (in_sgr) {
|
||||||
|
if (ch == 'm') in_sgr = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ch == 0x1b && i + 1 < len && PyUnicode_READ(kind, data, i + 1) == '[') { in_sgr = true; continue; }
|
||||||
|
if (ch == 0xfe0f) {
|
||||||
|
if (is_emoji_presentation_base(prev_ch) && prev_width == 1) {
|
||||||
|
width_so_far += 1;
|
||||||
|
prev_width = 2;
|
||||||
|
} else prev_width = 0;
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (width_so_far + prev_width > num_cells) { break; }
|
||||||
|
width_so_far += prev_width;
|
||||||
|
}
|
||||||
|
prev_ch = ch;
|
||||||
|
|
||||||
|
}
|
||||||
|
return PyLong_FromUnsignedLong(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
line(Screen *self, PyObject *val) {
|
line(Screen *self, PyObject *val) {
|
||||||
unsigned long y = PyLong_AsUnsignedLong(val);
|
unsigned long y = PyLong_AsUnsignedLong(val);
|
||||||
@ -1987,6 +2033,7 @@ PyTypeObject Screen_Type = {
|
|||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
|
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
|
||||||
{"wcswidth", (PyCFunction)screen_wcswidth, METH_O, ""},
|
{"wcswidth", (PyCFunction)screen_wcswidth, METH_O, ""},
|
||||||
|
{"truncate_point_for_length", (PyCFunction)screen_truncate_point_for_length, METH_VARARGS, ""},
|
||||||
{NULL} /* Sentinel */
|
{NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
from kitty.config import build_ansi_color_table, defaults
|
from kitty.config import build_ansi_color_table, defaults
|
||||||
from kitty.fast_data_types import (
|
from kitty.fast_data_types import (
|
||||||
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
|
REVERSE, ColorProfile, Cursor as C, HistoryBuf, LineBuf,
|
||||||
parse_input_from_terminal, wcswidth, wcwidth
|
parse_input_from_terminal, wcswidth, wcwidth, truncate_point_for_length
|
||||||
)
|
)
|
||||||
from kitty.rgb import to_color
|
from kitty.rgb import to_color
|
||||||
from kitty.utils import sanitize_title
|
from kitty.utils import sanitize_title
|
||||||
@ -338,7 +338,15 @@ class TestDataTypes(BaseTest):
|
|||||||
self.ae(tuple(map(w, 'a1\0コニチ ✔')), (1, 1, 0, 2, 2, 2, 1, 1))
|
self.ae(tuple(map(w, 'a1\0コニチ ✔')), (1, 1, 0, 2, 2, 2, 1, 1))
|
||||||
self.ae(wcswidth('\u2716\u2716\ufe0f\U0001f337'), 5)
|
self.ae(wcswidth('\u2716\u2716\ufe0f\U0001f337'), 5)
|
||||||
self.ae(wcswidth('\033a\033[2mb'), 2)
|
self.ae(wcswidth('\033a\033[2mb'), 2)
|
||||||
|
tpl = truncate_point_for_length
|
||||||
|
self.ae(tpl('abc', 4), 3)
|
||||||
|
self.ae(tpl('abc', 2), 2)
|
||||||
|
self.ae(tpl('abc', 0), 0)
|
||||||
|
self.ae(tpl('a\U0001f337', 2), 1)
|
||||||
|
self.ae(tpl('a\U0001f337', 3), 2)
|
||||||
|
self.ae(tpl('a\U0001f337b', 4), 3)
|
||||||
self.ae(sanitize_title('a\0\01 \t\n\f\rb'), 'a b')
|
self.ae(sanitize_title('a\0\01 \t\n\f\rb'), 'a b')
|
||||||
|
self.ae(tpl('a\x1b[31mbc', 2), 7)
|
||||||
|
|
||||||
def tp(*data, leftover='', text='', csi='', apc='', ibp=False):
|
def tp(*data, leftover='', text='', csi='', apc='', ibp=False):
|
||||||
text_r, csi_r, apc_r, rest = [], [], [], []
|
text_r, csi_r, apc_r, rest = [], [], [], []
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user