mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-06-24 18:07:01 +00:00
Port click on URL code to C
This commit is contained in:
parent
ed3427f349
commit
464291bbb1
7 changed files with 60 additions and 30 deletions
|
|
@ -21,7 +21,7 @@ from .keys import (
|
|||
)
|
||||
from .session import create_session
|
||||
from .tabs import SpecialWindow, TabManager
|
||||
from .utils import get_primary_selection, safe_print, set_primary_selection
|
||||
from .utils import get_primary_selection, safe_print, set_primary_selection, open_url
|
||||
from .window import load_shader_programs
|
||||
|
||||
|
||||
|
|
@ -247,6 +247,10 @@ class Boss:
|
|||
k = get_key_map(w.screen)[GLFW_KEY_UP if upwards else GLFW_KEY_DOWN]
|
||||
w.write_to_child(k * amt)
|
||||
|
||||
def open_url(self, url):
|
||||
if url:
|
||||
open_url(url, self.opts.open_url_with)
|
||||
|
||||
def gui_close_window(self, window):
|
||||
window.destroy()
|
||||
for tab in self.tab_manager:
|
||||
|
|
|
|||
21
kitty/line.c
21
kitty/line.c
|
|
@ -54,6 +54,8 @@ line_text_at(char_type ch, combining_type cc) {
|
|||
return ans;
|
||||
}
|
||||
|
||||
// URL detection {{{
|
||||
|
||||
static const char* url_prefixes[4] = {"https", "http", "file", "ftp"};
|
||||
static size_t url_prefix_lengths[sizeof(url_prefixes)/sizeof(url_prefixes[0])] = {0};
|
||||
typedef enum URL_PARSER_STATES {ANY, FIRST_SLASH, SECOND_SLASH} URL_PARSER_STATE;
|
||||
|
|
@ -137,12 +139,30 @@ line_url_start_at(Line *self, index_type x) {
|
|||
return self->xnum;
|
||||
}
|
||||
|
||||
index_type
|
||||
line_url_end_at(Line *self, index_type x) {
|
||||
index_type ans = x;
|
||||
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
|
||||
while (ans < self->xnum && is_url_char(self->cells[ans].ch & CHAR_MASK)) ans++;
|
||||
ans--;
|
||||
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch & CHAR_MASK)) ans--;
|
||||
return ans;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
url_start_at(Line *self, PyObject *x) {
|
||||
#define url_start_at_doc "url_start_at(x) -> Return the start cell number for a URL containing x or self->xnum if not found"
|
||||
return PyLong_FromUnsignedLong((unsigned long)line_url_start_at(self, PyLong_AsUnsignedLong(x)));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
url_end_at(Line *self, PyObject *x) {
|
||||
#define url_end_at_doc "url_end_at(x) -> Return the end cell number for a URL containing x or 0 if not found"
|
||||
return PyLong_FromUnsignedLong((unsigned long)line_url_end_at(self, PyLong_AsUnsignedLong(x)));
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
static PyObject*
|
||||
text_at(Line* self, Py_ssize_t xval) {
|
||||
#define text_at_doc "[x] -> Return the text in the specified cell"
|
||||
|
|
@ -567,6 +587,7 @@ static PyMethodDef methods[] = {
|
|||
METHOD(is_continued, METH_NOARGS)
|
||||
METHOD(width, METH_O)
|
||||
METHOD(url_start_at, METH_O)
|
||||
METHOD(url_end_at, METH_O)
|
||||
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *);
|
|||
void line_right_shift(Line *, unsigned int , unsigned int );
|
||||
void line_add_combining_char(Line *, uint32_t , unsigned int );
|
||||
index_type line_url_start_at(Line *self, index_type x);
|
||||
index_type line_url_end_at(Line *self, index_type x);
|
||||
index_type line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen);
|
||||
unsigned int line_length(Line *self);
|
||||
PyObject* unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc, char leading_char);
|
||||
|
|
|
|||
|
|
@ -216,6 +216,20 @@ HANDLER(add_click) {
|
|||
#undef N
|
||||
}
|
||||
|
||||
static inline void
|
||||
open_url(Window *w) {
|
||||
Line *line = screen_visual_line(w->render_data.screen, w->mouse_cell_y);
|
||||
if (line) {
|
||||
index_type start = line_url_start_at(line, w->mouse_cell_x);
|
||||
if (start < line->xnum) {
|
||||
index_type end = line_url_end_at(line, w->mouse_cell_x);
|
||||
if (end > start) {
|
||||
call_boss(open_url, "N", unicode_in_range(line, start, end + 1, true, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HANDLER(handle_button_event) {
|
||||
Tab *t = global_state.tabs + global_state.active_tab;
|
||||
bool is_release = !global_state.mouse_button_pressed[button];
|
||||
|
|
@ -236,7 +250,7 @@ HANDLER(handle_button_event) {
|
|||
update_drag(true, w, is_release);
|
||||
if (is_release) {
|
||||
if (modifiers == (int)OPT(open_url_modifiers)) {
|
||||
// TODO: click_url
|
||||
open_url(w);
|
||||
} else {
|
||||
if (is_release) add_click(w, button, modifiers, window_idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,3 +30,12 @@ normalize(uint32_t ch, uint32_t cc1, uint32_t cc2) {
|
|||
if (ans && cc2) ans = uc_composition(ans, cc2);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
can_strip_from_end_of_url(uint32_t ch) {
|
||||
// remove trailing punctuation
|
||||
return (
|
||||
(uc_is_general_category_withtable(ch, UC_CATEGORY_MASK_P) && ch != '/') ||
|
||||
ch == '>'
|
||||
) ? true : false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import re
|
||||
import sys
|
||||
import weakref
|
||||
from collections import deque
|
||||
|
|
@ -23,9 +22,7 @@ from .fast_data_types import (
|
|||
)
|
||||
from .rgb import to_color
|
||||
from .terminfo import get_capabilities
|
||||
from .utils import (
|
||||
color_as_int, load_shaders, open_url, parse_color_set, sanitize_title
|
||||
)
|
||||
from .utils import color_as_int, load_shaders, parse_color_set, sanitize_title
|
||||
|
||||
|
||||
class DynamicColor(Enum):
|
||||
|
|
@ -233,30 +230,6 @@ class Window:
|
|||
def text_for_selection(self):
|
||||
return ''.join(self.screen.text_for_selection())
|
||||
|
||||
# mouse handling {{{
|
||||
def click_url(self, x, y):
|
||||
x, y = self.cell_for_pos(x, y)
|
||||
if x is not None:
|
||||
l = self.screen.visual_line(y)
|
||||
if l is not None:
|
||||
text = str(l)
|
||||
for m in self.url_pat.finditer(text):
|
||||
if m.start() <= x < m.end():
|
||||
url = ''.join(l[i] for i in range(*m.span())).rstrip('.')
|
||||
# Remove trailing "] and similar
|
||||
url = re.sub(r'''["'][)}\]]$''', '', url)
|
||||
# Remove closing trailing character if it is matched by it's
|
||||
# corresponding opening character before the url
|
||||
if m.start() > 0:
|
||||
before = l[m.start() - 1]
|
||||
closing = {'(': ')', '[': ']', '{': '}', '<': '>', '"': '"', "'": "'", '`': '`', '|': '|', ':': ':'}.get(before)
|
||||
if closing is not None and url.endswith(closing):
|
||||
url = url[:-1]
|
||||
if url:
|
||||
open_url(url, self.opts.open_url_with)
|
||||
|
||||
# }}}
|
||||
|
||||
def destroy(self):
|
||||
if self.vao_id is not None:
|
||||
remove_vao(self.vao_id)
|
||||
|
|
|
|||
|
|
@ -222,6 +222,14 @@ class TestDataTypes(BaseTest):
|
|||
l.set_text(t, 0, len(t), C())
|
||||
return l
|
||||
|
||||
for trail in '.,]>)\\':
|
||||
l = create("http://xyz.com" + trail)
|
||||
self.ae(l.url_end_at(0), len(l) - 2)
|
||||
l = create("ftp://abc/")
|
||||
self.ae(l.url_end_at(0), len(l) - 1)
|
||||
l = create("http://-abcd] ")
|
||||
self.ae(l.url_end_at(0), len(l) - 3)
|
||||
|
||||
def lspace_test(n, scheme='http'):
|
||||
l = create(' ' * n + scheme + '://acme.com')
|
||||
for i in range(0, n):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue