Add an option to use a modern wcwidth() instead of the system one

This commit is contained in:
Kovid Goyal 2017-01-12 19:28:51 +05:30
parent a8408a1ce4
commit cb5d6547e5
8 changed files with 1364 additions and 15 deletions

View File

@ -109,6 +109,7 @@ type_map = {
'cursor_blink_interval': float,
'cursor_stop_blinking_after': float,
'enabled_layouts': to_layout_names,
'use_system_wcwidth': to_bool,
}
for name in 'foreground background cursor active_border_color inactive_border_color selection_foreground selection_background'.split():

View File

@ -20,6 +20,17 @@ drain_read(PyObject UNUSED *self, PyObject *fd) {
Py_RETURN_NONE;
}
static PyObject*
wcwidth_wrap(PyObject UNUSED *self, PyObject *chr) {
return PyLong_FromUnsignedLong(safe_wcwidth(PyLong_AsLong(chr)));
}
static PyObject*
change_wcwidth_wrap(PyObject UNUSED *self, PyObject *use9) {
change_wcwidth(PyObject_IsTrue(use9));
Py_RETURN_NONE;
}
static PyMethodDef module_methods[] = {
GL_METHODS
{"drain_read", (PyCFunction)drain_read, METH_O, ""},
@ -27,6 +38,8 @@ static PyMethodDef module_methods[] = {
{"parse_bytes_dump", (PyCFunction)parse_bytes_dump, METH_VARARGS, ""},
{"read_bytes", (PyCFunction)read_bytes, METH_VARARGS, ""},
{"read_bytes_dump", (PyCFunction)read_bytes_dump, METH_VARARGS, ""},
{"wcwidth", (PyCFunction)wcwidth_wrap, METH_O, ""},
{"change_wcwidth", (PyCFunction)change_wcwidth_wrap, METH_O, ""},
GLFW_FUNC_WRAPPERS
{NULL, NULL, 0, NULL} /* Sentinel */
};

View File

@ -355,6 +355,8 @@ void historybuf_add_line(HistoryBuf *self, const Line *line);
void historybuf_rewrap(HistoryBuf *self, HistoryBuf *other);
void historybuf_init_line(HistoryBuf *self, index_type num, Line *l);
unsigned int safe_wcwidth(uint32_t ch);
void change_wcwidth(bool use9);
void screen_align(Screen*);
void screen_restore_cursor(Screen *);
void screen_save_cursor(Screen *);

View File

@ -73,6 +73,15 @@ open_url_modifiers ctrl+shift
# use the operating system's default URL handler.
open_url_with default
# Choose whether to use the system implementation of wcwidth() (used to
# control how many cells a character is rendered in). If you use the system
# implementation, then kitty and any programs running in it will agree. The
# problem is that system implementations often are based on outdated unicode
# standards and get the width of many characters, such as emoji, wrong. So if
# you are using kitty with programs that have their own up-to-date wcwidth()
# implementation, set this option to no.
use_system_wcwidth yes
# The value of the TERM environment variable to set
term xterm-kitty

View File

@ -21,7 +21,7 @@ from .fast_data_types import (
GLFW_CONTEXT_VERSION_MINOR, GLFW_OPENGL_PROFILE,
GLFW_OPENGL_FORWARD_COMPAT, GLFW_OPENGL_CORE_PROFILE, GLFW_SAMPLES,
glfw_set_error_callback, glfw_init, glfw_terminate, glfw_window_hint,
glfw_swap_interval, glfw_wait_events, Window
glfw_swap_interval, glfw_wait_events, Window, change_wcwidth
)
from .utils import safe_print
@ -137,6 +137,7 @@ def main():
main(args.replay_commands)
return
opts = load_config(args.config)
change_wcwidth(not opts.use_system_wcwidth)
glfw_set_error_callback(on_glfw_error)
enable_automatic_opengl_error_checking(False)
if not glfw_init():

View File

@ -10,6 +10,7 @@
#include "unicode-data.h"
#include "tracker.h"
#include "modes.h"
#include "wcwidth9.h"
static const ScreenModes empty_modes = {0, .mDECAWM=true, .mDECTCEM=true, .mDECARM=true};
@ -195,13 +196,21 @@ screen_designate_charset(Screen *self, uint32_t which, uint32_t as) {
}
}
static inline unsigned int
static int (*wcwidth_impl)(wchar_t) = wcwidth;
unsigned int
safe_wcwidth(uint32_t ch) {
int ans = wcwidth(ch);
int ans = wcwidth_impl(ch);
if (ans < 0) ans = 1;
return MIN(2, ans);
}
void
change_wcwidth(bool use9) {
wcwidth_impl = (use9) ? wcwidth9 : wcwidth;
}
void
screen_draw(Screen *self, uint32_t och) {
if (is_ignored_char(och)) return;

View File

@ -7,7 +7,6 @@ import os
import signal
import shlex
import subprocess
import ctypes
import math
from collections import namedtuple
from contextlib import contextmanager
@ -15,13 +14,7 @@ from functools import lru_cache
from time import monotonic
from .constants import isosx
from .fast_data_types import glfw_get_physical_dpi
libc = ctypes.CDLL(None)
wcwidth_native = libc.wcwidth
del libc
wcwidth_native.argtypes = [ctypes.c_wchar]
wcwidth_native.restype = ctypes.c_int
from .fast_data_types import glfw_get_physical_dpi, wcwidth as wcwidth_impl
def safe_print(*a, **k):
@ -37,10 +30,10 @@ def ceil_int(x):
@lru_cache(maxsize=2**13)
def wcwidth(c: str) -> int:
ans = min(2, wcwidth_native(c))
if ans == -1:
ans = 1
return ans
try:
return wcwidth_impl(ord(c))
except TypeError:
return wcwidth_impl(ord(c[0]))
@contextmanager

1321
kitty/wcwidth9.h Normal file

File diff suppressed because it is too large Load Diff