This commit is contained in:
Kovid Goyal 2022-10-12 16:06:08 +05:30
commit 623b1d69f2
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 33 additions and 39 deletions

View File

@ -677,10 +677,17 @@ Here is an example of a PTM template that produces a list of all the authors for
def evaluate(book, context): def evaluate(book, context):
if book.series is None: if book.series is None:
return '' return ''
db = context.db.new_api
ans = set() ans = set()
db = context.db # Get the list of books in the series
for id_ in db.search_getting_ids(f'series:"={book.series}"', ''): ids = db.search(f'series:"={book.series}"', '')
ans.update(v.strip() for v in db.new_api.field_for('author_sort', id_).split('&')) if ids:
# Get all the author_sort values for the books in the series
author_sorts = (v for v in db.all_field_for('author_sort', ids).values())
# Add the names to the result set, removing duplicates
for aus in author_sorts:
ans.update(v.strip() for v in aus.split('&'))
# Make a sorted comma-separated string from the result set
return ', '.join(v.replace(',', ';') for v in sorted(ans)) return ', '.join(v.replace(',', ';') for v in sorted(ans))
The output in :guilabel:`Book details` looks like this: The output in :guilabel:`Book details` looks like this:

View File

@ -18,7 +18,8 @@ from calibre import sanitize_file_name
from calibre.constants import config_dir from calibre.constants import config_dir
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.book.formatter import SafeFormat from calibre.ebooks.metadata.book.formatter import SafeFormat
from calibre.gui2 import gprefs, error_dialog, choose_files, choose_save_file, pixmap_to_data from calibre.gui2 import (gprefs, error_dialog, choose_files, choose_save_file,
pixmap_to_data, question_dialog)
from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog from calibre.gui2.dialogs.template_dialog_ui import Ui_TemplateDialog
from calibre.library.coloring import (displayable_columns, color_row_key) from calibre.library.coloring import (displayable_columns, color_row_key)
from calibre.utils.config_base import tweaks from calibre.utils.config_base import tweaks
@ -84,45 +85,30 @@ class TemplateHighlighter(QSyntaxHighlighter):
r.append((re.compile(a), b)) r.append((re.compile(a), b))
if not for_python: if not for_python:
a( a(r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
r"\b[a-zA-Z]\w*\b(?!\(|\s+\()" r"|\$+#?[a-zA-Z]\w*",
r"|\$+#?[a-zA-Z]\w*", "identifier")
"identifier")
a(r"^program:", "keymode") a(r"^program:", "keymode")
a( a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]), "keyword")
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_GPM]), a("|".join([r"\b%s\b" % builtin for builtin in
"keyword")
a(
"|".join([r"\b%s\b" % builtin for builtin in
(builtin_functions if builtin_functions else (builtin_functions if builtin_functions else
formatter_functions().get_builtins())]), formatter_functions().get_builtins())]),
"builtin") "builtin")
a(r"""(?<!:)'[^']*'|"[^"]*\"""", "string") a(r"""(?<!:)'[^']*'|"[^"]*\"""", "string")
else: else:
a(r"^python:", "keymode") a(r"^python:", "keymode")
a("|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]), "keyword")
a( a("|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS_PYTHON]), "builtin")
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS_PYTHON]), a("|".join([r"\b%s\b" % constant for constant in self.CONSTANTS_PYTHON]), "constant")
"keyword")
a(
"|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS_PYTHON]),
"builtin")
a(
"|".join([r"\b%s\b" % constant for constant in self.CONSTANTS_PYTHON]),
"constant")
a(r"\bPyQt6\b|\bqt.core\b|\bQt?[A-Z][a-z]\w+\b", "pyqt") a(r"\bPyQt6\b|\bqt.core\b|\bQt?[A-Z][a-z]\w+\b", "pyqt")
a(r"@\w+(\.\w+)?\b", "decorator") a(r"@\w+(\.\w+)?\b", "decorator")
a(r"""('|").*?\1""", "string") a(r"""('|").*?\1""", "string")
stringRe = r"""((?:"|'){3}).*?\1""" stringRe = r"""((?:"|'){3}).*?\1"""
a(stringRe, "string") a(stringRe, "string")
self.stringRe = re.compile(stringRe) self.stringRe = re.compile(stringRe)
self.tripleSingleRe = re.compile(r"""'''(?!")""") self.tripleSingleRe = re.compile(r"""'''(?!")""")
self.tripleDoubleRe = re.compile(r'''"""(?!')''') self.tripleDoubleRe = re.compile(r'''"""(?!')''')
a(r'#[^\n]*', "comment")
a( a(
r"\b[+-]?[0-9]+[lL]?\b" r"\b[+-]?[0-9]+[lL]?\b"
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b" r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
@ -197,17 +183,6 @@ class TemplateHighlighter(QSyntaxHighlighter):
elif text[0] == "#": elif text[0] == "#":
self.setFormat(0, textLength, self.Formats["comment"]) self.setFormat(0, textLength, self.Formats["comment"])
return return
elif self.for_python:
stack = []
for i, c in enumerate(text):
if c in ('"', "'"):
if stack and stack[-1] == c:
stack.pop()
else:
stack.append(c)
elif c == "#" and len(stack) == 0:
self.setFormat(i, len(text), self.Formats["comment"])
return
for regex, format_ in self.Rules: for regex, format_ in self.Rules:
for m in regex.finditer(text): for m in regex.finditer(text):
@ -430,6 +405,8 @@ class TemplateDialog(QDialog, Ui_TemplateDialog):
self.textbox.setPlainText(text) self.textbox.setPlainText(text)
else: else:
text = '' text = ''
self.original_text = text
self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK')) self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(_('&OK'))
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel')) self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(_('&Cancel'))
@ -852,6 +829,16 @@ def evaluate(book, context):
gprefs['template_editor_table_widths'] = self.table_column_widths gprefs['template_editor_table_widths'] = self.table_column_widths
gprefs['template_editor_dialog_geometry'] = bytearray(self.saveGeometry()) gprefs['template_editor_dialog_geometry'] = bytearray(self.saveGeometry())
def keyPressEvent(self, ev):
if ev.key() == Qt.Key.Key_Escape:
# Check about ESC to avoid killing the dialog by mistake
if self.textbox.toPlainText() != self.original_text:
r = question_dialog(self, _('Discard changes?'),
_('Do you really want to close this dialog, discarding any changes?'))
if not r:
return
QDialog.keyPressEvent(self, ev)
def accept(self): def accept(self):
txt = str(self.textbox.toPlainText()).rstrip() txt = str(self.textbox.toPlainText()).rstrip()
if (self.coloring or self.iconing or self.embleming) and not txt: if (self.coloring or self.iconing or self.embleming) and not txt: