mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Merge branch 'kovidgoyal:master' into master
This commit is contained in:
commit
1e3a61fe1e
@ -495,7 +495,7 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``eval(string)`` -- evaluates the string as a program, passing the local variables. This permits using the template processor to construct complex results from local variables. In :ref:`Template Program Mode <template_mode>`, because the `{` and `}` characters are interpreted before the template is evaluated you must use `[[` for the `{` character and `]]` for the ``}`` character. They are converted automatically. Note also that prefixes and suffixes (the `|prefix|suffix` syntax) cannot be used in the argument to this function when using :ref:`Template Program Mode <template_mode>`.
|
||||
* ``extra_file_size(file_name)`` -- returns the size in bytes of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``extra_file_modtime(file_name, format_spec)`` -- returns the modification time of the extra file ``file_name`` in the book's ``data/`` folder if it exists, otherwise ``-1``. The modtime is formatted according to ``format_spec`` (see ``format_date()`` for details). If ``format_spec`` is the empty string, returns the modtime as the floating point number of seconds since the epoch. See also the functions ``has_extra_files()``, ``extra_file_names()`` and ``extra_file_size()``. The epoch is OS dependent. This function can be used only in the GUI.
|
||||
* ``extra_file_names(sep)`` -- returns a ``sep``-separated list of extra files in the book's ``data/`` folder. See also the functions ``has_extra_files()``, ``extra_file_size()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``extra_file_names(sep [, pattern])`` returns a ``sep``-separated list of extra files in the book's ``data/`` folder. If the optional parameter ``pattern``, a regular expression, is supplied then the list is filtered to files that match ``pattern``. The pattern match is case insensitive. See also the functions ``has_extra_files()``, ``extra_file_modtime()`` and ``extra_file_size()``. This function can be used only in the GUI.
|
||||
* ``field(lookup_name)`` -- returns the value of the metadata field with lookup name ``lookup_name``.
|
||||
* ``field_exists(field_name)`` -- checks if a field (column) with the lookup name ``field_name`` exists, returning ``'1'`` if so and the empty string if not.
|
||||
* ``finish_formatting(val, fmt, prefix, suffix)`` -- apply the format, prefix, and suffix to a value in the same way as done in a template like ``{series_index:05.2f| - |- }``. This function is provided to ease conversion of complex single-function- or template-program-mode templates to `GPM` Templates. For example, the following program produces the same output as the above template::
|
||||
@ -557,7 +557,7 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
|
||||
* ``formats_sizes()`` -- return a comma-separated list of colon-separated ``FMT:SIZE`` items giving the sizes in bytes of the formats of a book. You can use the select function to get the size for a specific format. Note that format names are always uppercase, as in EPUB.
|
||||
* ``fractional_part(x)`` -- returns the value after the decimal point. For example, ``fractional_part(3.14)`` returns ``0.14``. Throws an exception if ``x`` is not a number.
|
||||
* ``has_cover()`` -- return ``'Yes'`` if the book has a cover, otherwise the empty string.
|
||||
* ``has_extra_files()`` -- returns ``'Yes'`` if there are any extra files for the book (files in the folder ``data/`` in the book's folder), otherwise ``''`` (the empty string). See also the functions ``extra_file_names()``, ``extra_file_size()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``has_extra_files([pattern])`` -- returns the count of extra files, otherwise '' (the empty string). If the optional parameter ``pattern`` (a regular expression) is supplied then the list is filtered to files that match ``pattern`` before the files are counted. The pattern match is case insensitive. See also the functions ``extra_file_names()``, ``extra_file_size()`` and ``extra_file_modtime()``. This function can be used only in the GUI.
|
||||
* ``is_marked()`` -- check whether the book is `marked` in calibre. If it is then return the value of the mark, either ``'true'`` (lower case) or a comma-separated list of named marks. Returns ``''`` (the empty string) if the book is not marked. This function works only in the GUI.
|
||||
* ``language_codes(lang_strings)`` -- return the `language codes <https://www.loc.gov/standards/iso639-2/php/code_list.php>`_ for the language names passed in `lang_strings`. The strings must be in the language of the current locale. ``Lang_strings`` is a comma-separated list.
|
||||
* ``list_contains(value, separator, [ pattern, found_val, ]* not_found_val)`` -- (Alias of ``in_list``) Interpreting the value as a list of items separated by ``separator``, evaluate the ``pattern`` against each value in the list. If the ``pattern`` matches any value then return ``found_val``, otherwise return ``not_found_val``. The ``pattern`` and ``found_value`` can be repeated as many times as desired, permitting returning different values depending on the search. The patterns are checked in order. The first match is returned. Aliases: ``in_list()``, ``list_contains()``
|
||||
|
@ -5,16 +5,17 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys
|
||||
import os, sys
|
||||
|
||||
from qt.core import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, QStyleOptionViewItem,
|
||||
QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QMenu, QKeySequence,
|
||||
QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, QMenu, QKeySequence, QUrl,
|
||||
QAbstractTextDocumentLayout, QFont, QFontInfo, QDate, QDateTimeEdit, QDateTime, QEvent,
|
||||
QStyleOptionComboBox, QStyleOptionSpinBox, QLocale, QSize, QLineEdit, QDialog, QPalette)
|
||||
|
||||
from calibre.ebooks.metadata import rating_to_stars, title_sort
|
||||
from calibre.gui2 import UNDEFINED_QDATETIME, rating_font, gprefs
|
||||
from calibre.constants import iswindows
|
||||
from calibre.gui2.markdown_editor import MarkdownEditDialog
|
||||
from calibre.gui2.widgets import EnLineEdit
|
||||
from calibre.gui2.widgets2 import populate_standard_spinbox_context_menu, RatingEditor, DateTimeEdit as DateTimeEditBase
|
||||
from calibre.gui2.complete2 import EditWithComplete
|
||||
@ -534,7 +535,14 @@ class CcLongTextDelegate(QStyledItemDelegate): # {{{
|
||||
text = ''
|
||||
else:
|
||||
text = m.db.data[index.row()][m.custom_columns[col]['rec_index']]
|
||||
d = PlainTextDialog(parent, text, column_name=m.custom_columns[col]['name'])
|
||||
column_format = m.custom_columns[m.column_map[index.column()]]['display'].get('interpret_as')
|
||||
if column_format == 'markdown':
|
||||
path = m.db.abspath(index.row(), index_is_id=False)
|
||||
base_url = QUrl.fromLocalFile(os.path.join(path, 'metadata.html')) if path else None
|
||||
d = MarkdownEditDialog(parent, text, column_name=m.custom_columns[col]['name'],
|
||||
base_url=base_url)
|
||||
else:
|
||||
d = PlainTextDialog(parent, text, column_name=m.custom_columns[col]['name'])
|
||||
if d.exec() == QDialog.DialogCode.Accepted:
|
||||
m.setData(index, d.text, Qt.ItemDataRole.EditRole)
|
||||
return None
|
||||
|
@ -1153,10 +1153,9 @@ class BooksView(QTableView): # {{{
|
||||
elif cc['datatype'] == 'enumeration':
|
||||
set_item_delegate(colhead, self.cc_enum_delegate)
|
||||
else:
|
||||
if colhead in self._model.editable_cols:
|
||||
dattr = colhead+'_delegate'
|
||||
delegate = colhead if hasattr(self, dattr) else 'text'
|
||||
set_item_delegate(colhead, getattr(self, delegate+'_delegate'))
|
||||
dattr = colhead+'_delegate'
|
||||
delegate = colhead if hasattr(self, dattr) else 'text'
|
||||
set_item_delegate(colhead, getattr(self, delegate+'_delegate'))
|
||||
|
||||
self.restore_state()
|
||||
self.set_ondevice_column_visibility()
|
||||
|
@ -3,13 +3,14 @@
|
||||
|
||||
import os
|
||||
from qt.core import (
|
||||
QPlainTextEdit, Qt, QTabWidget, QUrl, QVBoxLayout, QWidget, pyqtSignal,
|
||||
QDialog, QDialogButtonBox, QPlainTextEdit, QSize, Qt, QTabWidget, QUrl,
|
||||
QVBoxLayout, QWidget, pyqtSignal,
|
||||
)
|
||||
|
||||
from calibre.gui2 import safe_open_url
|
||||
from calibre.gui2 import safe_open_url, gprefs
|
||||
from calibre.gui2.book_details import css
|
||||
from calibre.gui2.widgets2 import HTMLDisplay
|
||||
from calibre.library.comments import markdown
|
||||
from calibre.library.comments import markdown as get_markdown
|
||||
|
||||
|
||||
class Preview(HTMLDisplay):
|
||||
@ -42,6 +43,56 @@ class MarkdownEdit(QPlainTextEdit):
|
||||
m.exec(ev.globalPos())
|
||||
|
||||
|
||||
class MarkdownEditDialog(QDialog):
|
||||
|
||||
def __init__(self, parent, text, column_name=None, base_url=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.setObjectName("MarkdownEditDialog")
|
||||
self.setWindowTitle(_("Edit markdown"))
|
||||
self.verticalLayout = l = QVBoxLayout(self)
|
||||
self.textbox = editor = Editor(self)
|
||||
editor.set_base_url(base_url)
|
||||
self.buttonBox = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, self)
|
||||
bb.accepted.connect(self.accept)
|
||||
bb.rejected.connect(self.reject)
|
||||
l.addWidget(editor)
|
||||
l.addWidget(bb)
|
||||
# Remove help icon on title bar
|
||||
icon = self.windowIcon()
|
||||
self.setWindowFlags(self.windowFlags()&(~Qt.WindowType.WindowContextHelpButtonHint))
|
||||
self.setWindowIcon(icon)
|
||||
|
||||
self.textbox.markdown =text
|
||||
# self.textbox.wyswyg_dirtied()
|
||||
|
||||
if column_name:
|
||||
self.setWindowTitle(_('Edit "{0}"').format(column_name))
|
||||
self.restore_geometry(gprefs, 'markdown_edit_dialog_geom')
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(650, 600)
|
||||
|
||||
def accept(self):
|
||||
self.save_geometry(gprefs, 'markdown_edit_dialog_geom')
|
||||
QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
self.save_geometry(gprefs, 'markdown_edit_dialog_geom')
|
||||
QDialog.reject(self)
|
||||
|
||||
def closeEvent(self, ev):
|
||||
self.save_geometry(gprefs, 'markdown_edit_dialog_geom')
|
||||
return QDialog.closeEvent(self, ev)
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self.textbox.markdown
|
||||
|
||||
@text.setter
|
||||
def text(self, val):
|
||||
self.textbox.markdown = val or ''
|
||||
|
||||
|
||||
class Editor(QWidget): # {{{
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@ -90,7 +141,7 @@ class Editor(QWidget): # {{{
|
||||
self.update_preview()
|
||||
|
||||
def update_preview(self):
|
||||
html = markdown(self.editor.toPlainText().strip())
|
||||
html = get_markdown(self.editor.toPlainText().strip())
|
||||
val = f'''\
|
||||
<html>
|
||||
<head></head>
|
||||
|
@ -29,14 +29,35 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
||||
'BlockQuote': re.compile(r'(?u)^\s*>+\s*'),
|
||||
'BlockQuoteCount': re.compile('^[ \t]*>[ \t]?'),
|
||||
'CodeSpan': re.compile('(?P<delim>`+).+?(?P=delim)'),
|
||||
'HR': re.compile(r'(?u)^(\s*(\*|-)\s*){3,}$'),
|
||||
'eHR': re.compile(r'(?u)^(\s*(\*|=)\s*){3,}$'),
|
||||
'HeaderLine': re.compile(r'(?u)^(-|=)+\s*$'),
|
||||
'HR': re.compile(r'(?u)^(\s*(\*|-|_)\s*){3,}$'),
|
||||
'Html': re.compile('<.+?>')
|
||||
}
|
||||
|
||||
key_theme_maps = {
|
||||
'Bold': "bold",
|
||||
'uBold': "bold",
|
||||
'Italic': "emphasis",
|
||||
'uItalic': "emphasis",
|
||||
'Link': "link",
|
||||
'Image': "image",
|
||||
'HeaderAtx': "header",
|
||||
'Header': "header",
|
||||
'HeaderLine': "header",
|
||||
'CodeBlock': "codeblock",
|
||||
'UnorderedList': "unorderedlist",
|
||||
'UnorderedListStar': "unorderedlist",
|
||||
'OrderedList': "orderedlist",
|
||||
'BlockQuote': "blockquote",
|
||||
'BlockQuoteCount': "blockquote",
|
||||
'CodeSpan': "codespan",
|
||||
'HR': "line",
|
||||
'Html': "html",
|
||||
}
|
||||
|
||||
light_theme = {
|
||||
"bold": {"color":"#859900", "font-weight":"bold", "font-style":"normal"},
|
||||
"emphasis": {"color":"#b58900", "font-weight":"bold", "font-style":"italic"},
|
||||
"bold": {"font-weight":"bold"},
|
||||
"emphasis": {"font-style":"italic"},
|
||||
"link": {"color":light_link_color.name(), "font-weight":"normal", "font-style":"normal"},
|
||||
"image": {"color":"#cb4b16", "font-weight":"normal", "font-style":"normal"},
|
||||
"header": {"color":"#2aa198", "font-weight":"bold", "font-style":"normal"},
|
||||
@ -50,8 +71,8 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
||||
}
|
||||
|
||||
dark_theme = {
|
||||
"bold": {"color":"#859900", "font-weight":"bold", "font-style":"normal"},
|
||||
"emphasis": {"color":"#b58900", "font-weight":"bold", "font-style":"italic"},
|
||||
"bold": {"font-weight":"bold"},
|
||||
"emphasis": {"font-style":"italic"},
|
||||
"link": {"color":dark_link_color.name(), "font-weight":"normal", "font-style":"normal"},
|
||||
"image": {"color":"#cb4b16", "font-weight":"normal", "font-style":"normal"},
|
||||
"header": {"color":"#2aa198", "font-weight":"bold", "font-style":"normal"},
|
||||
@ -73,101 +94,14 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
||||
self.theme = theme
|
||||
self.MARKDOWN_KWS_FORMAT = {}
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['bold']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['bold']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['bold']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['Bold'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['bold']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['bold']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['bold']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['uBold'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['emphasis']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['emphasis']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['emphasis']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['Italic'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['emphasis']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['emphasis']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['emphasis']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['uItalic'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['link']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['link']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['link']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['Link'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['image']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['image']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['image']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['Image'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['header']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['header']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['header']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['Header'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['header']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['header']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['header']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['HeaderAtx'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['unorderedlist']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['unorderedlist']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['unorderedlist']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['UnorderedList'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['orderedlist']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['orderedlist']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['orderedlist']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['OrderedList'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['blockquote']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['blockquote']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['blockquote']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['BlockQuote'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['codespan']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['codespan']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['codespan']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['CodeSpan'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['codeblock']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['codeblock']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['codeblock']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['CodeBlock'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['line']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['line']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['line']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['HR'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['line']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['line']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['line']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['eHR'] = format
|
||||
|
||||
format = QTextCharFormat()
|
||||
format.setForeground(QBrush(QColor(theme['html']['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if theme['html']['font-weight']=='bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(True if theme['html']['font-style']=='italic' else False)
|
||||
self.MARKDOWN_KWS_FORMAT['HTML'] = format
|
||||
for k,t in self.key_theme_maps.items():
|
||||
subtheme = theme[t]
|
||||
format = QTextCharFormat()
|
||||
if 'color' in subtheme:
|
||||
format.setForeground(QBrush(QColor(subtheme['color'])))
|
||||
format.setFontWeight(QFont.Weight.Bold if subtheme.get('font-weight') == 'bold' else QFont.Weight.Normal)
|
||||
format.setFontItalic(subtheme.get('font-style') == 'italic')
|
||||
self.MARKDOWN_KWS_FORMAT[k] = format
|
||||
|
||||
self.rehighlight()
|
||||
|
||||
@ -230,37 +164,27 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def highlightHorizontalLine(self, text, cursor, bf, strt):
|
||||
found = False
|
||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HR'],text):
|
||||
prevBlock = self.currentBlock().previous()
|
||||
prevCursor = QTextCursor(prevBlock)
|
||||
prev = prevBlock.text()
|
||||
prevAscii = str(prev.replace('\u2029','\n'))
|
||||
if prevAscii.strip():
|
||||
#print "Its a header"
|
||||
prevCursor.select(QTextCursor.LineUnderCursor)
|
||||
#prevCursor.setCharFormat(self.MARKDOWN_KWS_FORMAT['Header'])
|
||||
formatRange = QTextLayout.FormatRange()
|
||||
formatRange.format = self.MARKDOWN_KWS_FORMAT['Header']
|
||||
formatRange.length = prevCursor.block().length()
|
||||
formatRange.start = 0
|
||||
prevCursor.block().layout().setAdditionalFormats([formatRange])
|
||||
self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HR'])
|
||||
|
||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['eHR'],text):
|
||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HeaderLine'],text):
|
||||
prevBlock = self.currentBlock().previous()
|
||||
prevCursor = QTextCursor(prevBlock)
|
||||
prev = prevBlock.text()
|
||||
prevAscii = str(prev.replace('\u2029','\n'))
|
||||
if prevAscii.strip():
|
||||
#print "Its a header"
|
||||
prevCursor.select(QTextCursor.LineUnderCursor)
|
||||
prevCursor.select(QTextCursor.SelectionType.LineUnderCursor)
|
||||
#prevCursor.setCharFormat(self.MARKDOWN_KWS_FORMAT['Header'])
|
||||
formatRange = QTextLayout.FormatRange()
|
||||
formatRange.format = self.MARKDOWN_KWS_FORMAT['Header']
|
||||
formatRange.length = prevCursor.block().length()
|
||||
formatRange.start = 0
|
||||
prevCursor.block().layout().setAdditionalFormats([formatRange])
|
||||
prevCursor.block().layout().setFormats([formatRange])
|
||||
self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HeaderLine'])
|
||||
return True
|
||||
|
||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['HR'],text):
|
||||
self.setFormat(mo.start()+strt, mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HR'])
|
||||
found = True
|
||||
return found
|
||||
|
||||
def highlightAtxHeader(self, text, cursor, bf, strt):
|
||||
@ -342,4 +266,4 @@ class MarkdownHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def highlightHtml(self, text):
|
||||
for mo in re.finditer(self.MARKDOWN_KEYS_REGEX['Html'], text):
|
||||
self.setFormat(mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['HTML'])
|
||||
self.setFormat(mo.start(), mo.end() - mo.start(), self.MARKDOWN_KWS_FORMAT['Html'])
|
||||
|
@ -2391,16 +2391,28 @@ class BuiltinBookValues(BuiltinFormatterFunction):
|
||||
|
||||
class BuiltinHasExtraFiles(BuiltinFormatterFunction):
|
||||
name = 'has_extra_files'
|
||||
arg_count = 0
|
||||
arg_count = -1
|
||||
category = 'Template database functions'
|
||||
__doc__ = doc = _("has_extra_files() -- returns 'Yes' if there are any extra "
|
||||
__doc__ = doc = _("has_extra_files([pattern]) -- returns the count of extra "
|
||||
"files, otherwise '' (the empty string). "
|
||||
"If the optional parameter 'pattern' (a regular expression) "
|
||||
"is supplied then the list is filtered to files that match "
|
||||
"pattern before the files are counted. The pattern match is "
|
||||
"case insensitive. "
|
||||
'This function can be used only in the GUI.')
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals):
|
||||
def evaluate(self, formatter, kwargs, mi, locals, *args):
|
||||
if len(args) > 1:
|
||||
raise ValueError(_('Incorrect number of arguments for function {0}').format('has_extra_files'))
|
||||
pattern = args[0] if len(args) == 1 else None
|
||||
db = self.get_database(mi).new_api
|
||||
try:
|
||||
return 'Yes' if db.list_extra_files(mi.id, use_cache=True, pattern=DATA_FILE_PATTERN) else ''
|
||||
files = tuple(f.relpath.partition('/')[-1] for f in
|
||||
db.list_extra_files(mi.id, use_cache=True, pattern=DATA_FILE_PATTERN))
|
||||
if pattern:
|
||||
r = re.compile(pattern, re.IGNORECASE)
|
||||
files = tuple(filter(r.search, files))
|
||||
return len(files) if len(files) > 0 else ''
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
raise ValueError(e)
|
||||
@ -2408,17 +2420,27 @@ class BuiltinHasExtraFiles(BuiltinFormatterFunction):
|
||||
|
||||
class BuiltinExtraFileNames(BuiltinFormatterFunction):
|
||||
name = 'extra_file_names'
|
||||
arg_count = 1
|
||||
arg_count = -1
|
||||
category = 'Template database functions'
|
||||
__doc__ = doc = _("extra_file_names(sep) -- returns a sep-separated list of "
|
||||
"extra files in the book's '{}/' folder. "
|
||||
__doc__ = doc = _("extra_file_names(sep [, pattern]) -- returns a sep-separated "
|
||||
"list of extra files in the book's '{}/' folder. If the "
|
||||
"optional parameter 'pattern', a regular expression, is "
|
||||
"supplied then the list is filtered to files that match pattern. "
|
||||
"The pattern match is case insensitive. "
|
||||
'This function can be used only in the GUI.').format(DATA_DIR_NAME)
|
||||
|
||||
def evaluate(self, formatter, kwargs, mi, locals, sep):
|
||||
def evaluate(self, formatter, kwargs, mi, locals, sep, *args):
|
||||
if len(args) > 1:
|
||||
raise ValueError(_('Incorrect number of arguments for function {0}').format('has_extra_files'))
|
||||
pattern = args[0] if len(args) == 1 else None
|
||||
db = self.get_database(mi).new_api
|
||||
try:
|
||||
files = db.list_extra_files(mi.id, use_cache=True, pattern=DATA_FILE_PATTERN)
|
||||
return sep.join(file.relpath.partition('/')[-1] for file in files)
|
||||
files = tuple(f.relpath.partition('/')[-1] for f in
|
||||
db.list_extra_files(mi.id, use_cache=True, pattern=DATA_FILE_PATTERN))
|
||||
if pattern:
|
||||
r = re.compile(pattern, re.IGNORECASE)
|
||||
files = tuple(filter(r.search, files))
|
||||
return sep.join(files)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
raise ValueError(e)
|
||||
|
Loading…
x
Reference in New Issue
Block a user