Add option select_by_word_characters_forward
This adds an option to select separate characters for forward and backward word extension on double click. If it is empty the old behavior is preserved. This is the default. If it is not empty, select_by_word_characters_forward will be used for extending the selection in forward direction (right) and select_by_word_characters will be used for extending in backward direction (left). Signed-off-by: Konrad Gräfe <kgraefe@paktolos.net>
This commit is contained in:
parent
d3656bf7e9
commit
8c41cc8d3e
@ -492,6 +492,18 @@ Unicode database will be matched.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
|
opt('select_by_word_characters_forward', '',
|
||||||
|
ctype='!select_by_word_characters_forward',
|
||||||
|
long_text='''
|
||||||
|
Characters considered part of a word when extending the selection forward on
|
||||||
|
double clicking. In addition to these characters any character that is marked
|
||||||
|
as an alphanumeric character in the Unicode database will be matched.
|
||||||
|
|
||||||
|
If empty (default) :opt:`select_by_word_characters` will be used for both
|
||||||
|
directions.
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
opt('click_interval', '-1.0',
|
opt('click_interval', '-1.0',
|
||||||
option_type='float', ctype='time',
|
option_type='float', ctype='time',
|
||||||
long_text='''
|
long_text='''
|
||||||
|
|||||||
3
kitty/options/parse.py
generated
3
kitty/options/parse.py
generated
@ -1163,6 +1163,9 @@ class Parser:
|
|||||||
def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def select_by_word_characters(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['select_by_word_characters'] = str(val)
|
ans['select_by_word_characters'] = str(val)
|
||||||
|
|
||||||
|
def select_by_word_characters_forward(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
|
ans['select_by_word_characters_forward'] = str(val)
|
||||||
|
|
||||||
def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def selection_background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['selection_background'] = to_color_or_none(val)
|
ans['selection_background'] = to_color_or_none(val)
|
||||||
|
|
||||||
|
|||||||
15
kitty/options/to-c-generated.h
generated
15
kitty/options/to-c-generated.h
generated
@ -304,6 +304,19 @@ convert_from_opts_select_by_word_characters(PyObject *py_opts, Options *opts) {
|
|||||||
Py_DECREF(ret);
|
Py_DECREF(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_from_python_select_by_word_characters_forward(PyObject *val, Options *opts) {
|
||||||
|
select_by_word_characters_forward(val, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_from_opts_select_by_word_characters_forward(PyObject *py_opts, Options *opts) {
|
||||||
|
PyObject *ret = PyObject_GetAttrString(py_opts, "select_by_word_characters_forward");
|
||||||
|
if (ret == NULL) return;
|
||||||
|
convert_from_python_select_by_word_characters_forward(ret, opts);
|
||||||
|
Py_DECREF(ret);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_from_python_click_interval(PyObject *val, Options *opts) {
|
convert_from_python_click_interval(PyObject *val, Options *opts) {
|
||||||
opts->click_interval = parse_s_double_to_monotonic_t(val);
|
opts->click_interval = parse_s_double_to_monotonic_t(val);
|
||||||
@ -1067,6 +1080,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
|
|||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_select_by_word_characters(py_opts, opts);
|
convert_from_opts_select_by_word_characters(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
|
convert_from_opts_select_by_word_characters_forward(py_opts, opts);
|
||||||
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_click_interval(py_opts, opts);
|
convert_from_opts_click_interval(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_focus_follows_mouse(py_opts, opts);
|
convert_from_opts_focus_follows_mouse(py_opts, opts);
|
||||||
|
|||||||
@ -187,6 +187,12 @@ select_by_word_characters(PyObject *chars, Options *opts) {
|
|||||||
opts->select_by_word_characters = list_of_chars(chars);
|
opts->select_by_word_characters = list_of_chars(chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
select_by_word_characters_forward(PyObject *chars, Options *opts) {
|
||||||
|
free(opts->select_by_word_characters_forward);
|
||||||
|
opts->select_by_word_characters_forward = list_of_chars(chars);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
tab_bar_style(PyObject *val, Options *opts) {
|
tab_bar_style(PyObject *val, Options *opts) {
|
||||||
opts->tab_bar_hidden = PyUnicode_CompareWithASCIIString(val, "hidden") == 0 ? true: false;
|
opts->tab_bar_hidden = PyUnicode_CompareWithASCIIString(val, "hidden") == 0 ? true: false;
|
||||||
|
|||||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@ -411,6 +411,7 @@ option_names = ( # {{{
|
|||||||
'scrollback_pager',
|
'scrollback_pager',
|
||||||
'scrollback_pager_history_size',
|
'scrollback_pager_history_size',
|
||||||
'select_by_word_characters',
|
'select_by_word_characters',
|
||||||
|
'select_by_word_characters_forward',
|
||||||
'selection_background',
|
'selection_background',
|
||||||
'selection_foreground',
|
'selection_foreground',
|
||||||
'shell',
|
'shell',
|
||||||
@ -561,6 +562,7 @@ class Options:
|
|||||||
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
|
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
|
||||||
scrollback_pager_history_size: int = 0
|
scrollback_pager_history_size: int = 0
|
||||||
select_by_word_characters: str = '@-./_~?&=%+#'
|
select_by_word_characters: str = '@-./_~?&=%+#'
|
||||||
|
select_by_word_characters_forward: str = ''
|
||||||
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
|
selection_background: typing.Optional[kitty.fast_data_types.Color] = Color(255, 250, 205)
|
||||||
selection_foreground: typing.Optional[kitty.fast_data_types.Color] = Color(0, 0, 0)
|
selection_foreground: typing.Optional[kitty.fast_data_types.Color] = Color(0, 0, 0)
|
||||||
shell: str = '.'
|
shell: str = '.'
|
||||||
|
|||||||
@ -3222,7 +3222,15 @@ screen_selection_range_for_line(Screen *self, index_type y, index_type *start, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_opt_word_char(char_type ch) {
|
is_opt_word_char(char_type ch, bool forward) {
|
||||||
|
if (forward && OPT(select_by_word_characters_forward)) {
|
||||||
|
for (const char_type *p = OPT(select_by_word_characters_forward); *p; p++) {
|
||||||
|
if (ch == *p) return true;
|
||||||
|
}
|
||||||
|
if (*OPT(select_by_word_characters_forward)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (OPT(select_by_word_characters)) {
|
if (OPT(select_by_word_characters)) {
|
||||||
for (const char_type *p = OPT(select_by_word_characters); *p; p++) {
|
for (const char_type *p = OPT(select_by_word_characters); *p; p++) {
|
||||||
if (ch == *p) return true;
|
if (ch == *p) return true;
|
||||||
@ -3232,9 +3240,9 @@ is_opt_word_char(char_type ch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_char_ok_for_word_extension(Line* line, index_type x) {
|
is_char_ok_for_word_extension(Line* line, index_type x, bool forward) {
|
||||||
char_type ch = line->cpu_cells[x].ch;
|
char_type ch = line->cpu_cells[x].ch;
|
||||||
if (is_word_char(ch) || is_opt_word_char(ch)) return true;
|
if (is_word_char(ch) || is_opt_word_char(ch, forward)) return true;
|
||||||
// pass : from :// so that common URLs are matched
|
// pass : from :// so that common URLs are matched
|
||||||
if (ch == ':' && x + 2 < line->xnum && line->cpu_cells[x+1].ch == '/' && line->cpu_cells[x+2].ch == '/') return true;
|
if (ch == ':' && x + 2 < line->xnum && line->cpu_cells[x+1].ch == '/' && line->cpu_cells[x+2].ch == '/') return true;
|
||||||
return false;
|
return false;
|
||||||
@ -3247,26 +3255,26 @@ screen_selection_range_for_word(Screen *self, const index_type x, const index_ty
|
|||||||
Line *line = visual_line_(self, y);
|
Line *line = visual_line_(self, y);
|
||||||
*y1 = y;
|
*y1 = y;
|
||||||
*y2 = y;
|
*y2 = y;
|
||||||
#define is_ok(x) is_char_ok_for_word_extension(line, x)
|
#define is_ok(x, forward) is_char_ok_for_word_extension(line, x, forward)
|
||||||
if (!is_ok(x)) {
|
if (!is_ok(x, false)) {
|
||||||
if (initial_selection) return false;
|
if (initial_selection) return false;
|
||||||
*s = x; *e = x;
|
*s = x; *e = x;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
start = x; end = x;
|
start = x; end = x;
|
||||||
while(true) {
|
while(true) {
|
||||||
while(start > 0 && is_ok(start - 1)) start--;
|
while(start > 0 && is_ok(start - 1, false)) start--;
|
||||||
if (start > 0 || !line->attrs.continued || *y1 == 0) break;
|
if (start > 0 || !line->attrs.continued || *y1 == 0) break;
|
||||||
line = visual_line_(self, *y1 - 1);
|
line = visual_line_(self, *y1 - 1);
|
||||||
if (!is_ok(self->columns - 1)) break;
|
if (!is_ok(self->columns - 1, false)) break;
|
||||||
(*y1)--; start = self->columns - 1;
|
(*y1)--; start = self->columns - 1;
|
||||||
}
|
}
|
||||||
line = visual_line_(self, *y2);
|
line = visual_line_(self, *y2);
|
||||||
while(true) {
|
while(true) {
|
||||||
while(end < self->columns - 1 && is_ok(end + 1)) end++;
|
while(end < self->columns - 1 && is_ok(end + 1, true)) end++;
|
||||||
if (end < self->columns - 1 || *y2 >= self->lines - 1) break;
|
if (end < self->columns - 1 || *y2 >= self->lines - 1) break;
|
||||||
line = visual_line_(self, *y2 + 1);
|
line = visual_line_(self, *y2 + 1);
|
||||||
if (!line->attrs.continued || !is_ok(0)) break;
|
if (!line->attrs.continued || !is_ok(0, true)) break;
|
||||||
(*y2)++; end = 0;
|
(*y2)++; end = 0;
|
||||||
}
|
}
|
||||||
*s = start; *e = end;
|
*s = start; *e = end;
|
||||||
|
|||||||
@ -33,6 +33,7 @@ typedef struct {
|
|||||||
unsigned int scrollback_pager_history_size;
|
unsigned int scrollback_pager_history_size;
|
||||||
bool scrollback_fill_enlarged_window;
|
bool scrollback_fill_enlarged_window;
|
||||||
char_type *select_by_word_characters;
|
char_type *select_by_word_characters;
|
||||||
|
char_type *select_by_word_characters_forward;
|
||||||
color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color, tab_bar_background, tab_bar_margin_color;
|
color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color, tab_bar_background, tab_bar_margin_color;
|
||||||
color_type mark1_foreground, mark1_background, mark2_foreground, mark2_background, mark3_foreground, mark3_background;
|
color_type mark1_foreground, mark1_background, mark2_foreground, mark2_background, mark3_foreground, mark3_background;
|
||||||
monotonic_t repaint_delay, input_delay;
|
monotonic_t repaint_delay, input_delay;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user