mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Completion for anchors
This commit is contained in:
parent
709e04bd16
commit
5bcd936470
@ -12,9 +12,11 @@ from collections import namedtuple, OrderedDict
|
|||||||
from PyQt5.Qt import QObject, pyqtSignal, Qt
|
from PyQt5.Qt import QObject, pyqtSignal, Qt
|
||||||
|
|
||||||
from calibre import prepare_string_for_xml
|
from calibre import prepare_string_for_xml
|
||||||
|
from calibre.ebooks.oeb.base import xml2text
|
||||||
from calibre.ebooks.oeb.polish.container import OEB_STYLES, OEB_FONTS, name_to_href
|
from calibre.ebooks.oeb.polish.container import OEB_STYLES, OEB_FONTS, name_to_href
|
||||||
|
from calibre.ebooks.oeb.polish.parsing import parse
|
||||||
from calibre.gui2 import is_gui_thread
|
from calibre.gui2 import is_gui_thread
|
||||||
from calibre.gui2.tweak_book import current_container
|
from calibre.gui2.tweak_book import current_container, editors
|
||||||
from calibre.gui2.tweak_book.completion.utils import control, data, DataError
|
from calibre.gui2.tweak_book.completion.utils import control, data, DataError
|
||||||
from calibre.utils.ipc import eintr_retry_call
|
from calibre.utils.ipc import eintr_retry_call
|
||||||
from calibre.utils.matcher import Matcher
|
from calibre.utils.matcher import Matcher
|
||||||
@ -44,6 +46,13 @@ def names_data(request_data):
|
|||||||
c = current_container()
|
c = current_container()
|
||||||
return c.mime_map, {n for n, is_linear in c.spine_names}
|
return c.mime_map, {n for n, is_linear in c.spine_names}
|
||||||
|
|
||||||
|
@data
|
||||||
|
def file_data(name):
|
||||||
|
'Get the data for name. Returns a unicode string if name is a text document/stylesheet'
|
||||||
|
if name in editors:
|
||||||
|
return editors[name].get_raw_data()
|
||||||
|
return current_container().raw_data(name)
|
||||||
|
|
||||||
def get_data(data_conn, data_type, data=None):
|
def get_data(data_conn, data_type, data=None):
|
||||||
eintr_retry_call(data_conn.send, Request(None, data_type, data, None))
|
eintr_retry_call(data_conn.send, Request(None, data_type, data, None))
|
||||||
result, tb = eintr_retry_call(data_conn.recv)
|
result, tb = eintr_retry_call(data_conn.recv)
|
||||||
@ -81,6 +90,57 @@ def complete_names(names_data, data_conn):
|
|||||||
descriptions = {href:d(name) for name, href in nmap.iteritems()}
|
descriptions = {href:d(name) for name, href in nmap.iteritems()}
|
||||||
return items, descriptions, {}
|
return items, descriptions, {}
|
||||||
|
|
||||||
|
|
||||||
|
def description_for_anchor(elem):
|
||||||
|
def check(x, min_len=4):
|
||||||
|
if x:
|
||||||
|
x = x.strip()
|
||||||
|
if len(x) >= min_len:
|
||||||
|
return x[:30]
|
||||||
|
|
||||||
|
desc = check(elem.get('title'))
|
||||||
|
if desc is not None:
|
||||||
|
return desc
|
||||||
|
desc = check(elem.text)
|
||||||
|
if desc is not None:
|
||||||
|
return desc
|
||||||
|
if len(elem) > 0:
|
||||||
|
desc = check(elem[0].text)
|
||||||
|
if desc is not None:
|
||||||
|
return desc
|
||||||
|
# Get full text for tags that have only a few descendants
|
||||||
|
for i, x in enumerate(elem.iterdescendants('*')):
|
||||||
|
if i > 5:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
desc = check(xml2text(elem), min_len=1)
|
||||||
|
if desc is not None:
|
||||||
|
return desc
|
||||||
|
|
||||||
|
def create_anchor_map(root):
|
||||||
|
ans = {}
|
||||||
|
for elem in root.xpath('//*[@id or @name]'):
|
||||||
|
anchor = elem.get('id') or elem.get('name')
|
||||||
|
if anchor and anchor not in ans:
|
||||||
|
ans[anchor] = description_for_anchor(elem)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
@control
|
||||||
|
def complete_anchor(name, data_conn):
|
||||||
|
if name not in file_cache:
|
||||||
|
data = raw = get_data(data_conn, 'file_data', name)
|
||||||
|
if isinstance(raw, type('')):
|
||||||
|
try:
|
||||||
|
root = parse(raw, decoder=lambda x:x.decode('utf-8'))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
data = (root, create_anchor_map(root))
|
||||||
|
file_cache[name] = data
|
||||||
|
data = file_cache[name]
|
||||||
|
if isinstance(data, tuple) and len(data) > 1 and isinstance(data[1], dict):
|
||||||
|
return frozenset(data[1]), data[1], {}
|
||||||
|
|
||||||
_current_matcher = (None, None, None)
|
_current_matcher = (None, None, None)
|
||||||
|
|
||||||
def handle_control_request(request, data_conn):
|
def handle_control_request(request, data_conn):
|
||||||
|
@ -13,14 +13,15 @@ from cssutils import parseStyle
|
|||||||
from PyQt5.Qt import QTextEdit, Qt
|
from PyQt5.Qt import QTextEdit, Qt
|
||||||
|
|
||||||
from calibre import prepare_string_for_xml, xml_entity_to_unicode
|
from calibre import prepare_string_for_xml, xml_entity_to_unicode
|
||||||
|
from calibre.ebooks.oeb.polish.container import OEB_DOCS
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
from calibre.gui2.tweak_book.editor.syntax.html import ATTR_NAME, ATTR_END, ATTR_START, ATTR_VALUE
|
from calibre.gui2.tweak_book.editor.syntax.html import ATTR_NAME, ATTR_END, ATTR_START, ATTR_VALUE
|
||||||
from calibre.utils.icu import utf16_length
|
|
||||||
from calibre.gui2.tweak_book import tprefs, current_container
|
from calibre.gui2.tweak_book import tprefs, current_container
|
||||||
from calibre.gui2.tweak_book.editor.smarts import NullSmarts
|
from calibre.gui2.tweak_book.editor.smarts import NullSmarts
|
||||||
from calibre.gui2.tweak_book.editor.smarts.utils import (
|
from calibre.gui2.tweak_book.editor.smarts.utils import (
|
||||||
no_modifiers, get_leading_whitespace_on_block, get_text_before_cursor,
|
no_modifiers, get_leading_whitespace_on_block, get_text_before_cursor,
|
||||||
get_text_after_cursor, smart_home, smart_backspace, smart_tab, expand_tabs)
|
get_text_after_cursor, smart_home, smart_backspace, smart_tab, expand_tabs)
|
||||||
|
from calibre.utils.icu import utf16_length
|
||||||
|
|
||||||
get_offset = itemgetter(0)
|
get_offset = itemgetter(0)
|
||||||
PARAGRAPH_SEPARATOR = '\u2029'
|
PARAGRAPH_SEPARATOR = '\u2029'
|
||||||
@ -646,8 +647,16 @@ class Smarts(NullSmarts):
|
|||||||
if doc_name and attr in {'href', 'src'}:
|
if doc_name and attr in {'href', 'src'}:
|
||||||
# A link
|
# A link
|
||||||
query = m.group(2) or m.group(3) or ''
|
query = m.group(2) or m.group(3) or ''
|
||||||
|
c = current_container()
|
||||||
names_type = {'a':'text_link', 'img':'image', 'image':'image', 'link':'stylesheet'}.get(tagname)
|
names_type = {'a':'text_link', 'img':'image', 'image':'image', 'link':'stylesheet'}.get(tagname)
|
||||||
return 'complete_names', (names_type, doc_name, current_container().root), query
|
idx = query.find('#')
|
||||||
|
if idx > -1 and names_type in (None, 'text_link'):
|
||||||
|
href, query = query[:idx], query[idx+1:]
|
||||||
|
name = c.href_to_name(href) if href else doc_name
|
||||||
|
if c.mime_map.get(name) in OEB_DOCS:
|
||||||
|
return 'complete_anchor', name, query
|
||||||
|
|
||||||
|
return 'complete_names', (names_type, doc_name, c.root), query
|
||||||
|
|
||||||
if __name__ == '__main__': # {{{
|
if __name__ == '__main__': # {{{
|
||||||
from calibre.gui2.tweak_book.editor.widget import launch_editor
|
from calibre.gui2.tweak_book.editor.widget import launch_editor
|
||||||
|
Loading…
x
Reference in New Issue
Block a user