Port click on URL code to C

This commit is contained in:
Kovid Goyal 2017-09-14 20:03:28 +05:30
parent ed3427f349
commit 464291bbb1
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
7 changed files with 60 additions and 30 deletions

View file

@ -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:

View file

@ -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 */
};

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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):