mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix upper-case saved search names not being recognized
This commit is contained in:
commit
c69be19011
@ -8,7 +8,7 @@ Virtual Libraries
|
||||
============================
|
||||
|
||||
In |app|, a virtual library is a way to tell |app| to open only a subset of a
|
||||
normal library. For example, if you want to only work with books by a certain
|
||||
normal library. For example, you might want to only work with books by a certain
|
||||
author, or books having only a certain tag. Using virtual libraries is the
|
||||
preferred way of partitioning your large book collection into smaller sub
|
||||
collections. It is superior to splitting up your library into multiple smaller
|
||||
@ -16,9 +16,9 @@ libraries as, when you want to search through your entire collection, you can
|
||||
simply go back to the full library. There is no way to search through multiple
|
||||
separate libraries simultaneously in |app|.
|
||||
|
||||
A virtual library is different to a simple search. A search will only restrict
|
||||
the list of books shown in the book list. A virtual library does that an in
|
||||
addition, it also restricts the entries shown in the :guilabel:`Tag Browser` to
|
||||
A virtual library is different from a simple search. A search will only restrict
|
||||
the list of books shown in the book list. A virtual library does that, and in
|
||||
addition it also restricts the entries shown in the :guilabel:`Tag Browser` to
|
||||
the left. The Tag Browser will only show tags, authors, series, publishers, etc.
|
||||
that come from the books in the virtual library. A virtual library thus behaves
|
||||
as though the actual library contains only the restricted set of books.
|
||||
@ -47,14 +47,15 @@ selected author.
|
||||
You can switch back to the full library at any time by once again clicking the
|
||||
:guilabel:`Virtual Library` and selecting the entry named :guilabel:`<None>`.
|
||||
|
||||
Virtual Libraries are based on *searches*. You can use any search as the basis
|
||||
of a virtual library. The virtual library will contain only the books matched
|
||||
by that search. First, type in the search you want to use in the search bar,
|
||||
when you are happy with the returned results, click the Virtual Library button,
|
||||
choose Create Library and enter a name for the new virtual library. The virtual
|
||||
library will then be created based on the search you just typed in. Searches
|
||||
are very powerful, for examples of the kinds of things you can do with them,
|
||||
see :ref:`search_interface`.
|
||||
Virtual Libraries are based on *searches*. You can use any search as the
|
||||
basis of a virtual library. The virtual library will contain only the
|
||||
books matched by that search. First, type in the search you want to use
|
||||
in the search bar or build a search using the :guilabel:`Tag Browser`.
|
||||
When you are happy with the returned results, click the Virtual Library
|
||||
button, choose Create Library and enter a name for the new virtual
|
||||
library. The virtual library will then be created based on the search
|
||||
you just typed in. Searches are very powerful, for examples of the kinds
|
||||
of things you can do with them, see :ref:`search_interface`.
|
||||
|
||||
Working with Virtual Libraries
|
||||
-------------------------------------
|
||||
|
@ -146,6 +146,14 @@ class Parser(object):
|
||||
self.current_token += 1
|
||||
return res
|
||||
|
||||
def lcase_token(self, advance=False):
|
||||
if self.is_eof():
|
||||
return None
|
||||
res = self.tokens[self.current_token][1]
|
||||
if advance:
|
||||
self.current_token += 1
|
||||
return icu_lower(res)
|
||||
|
||||
def token_type(self):
|
||||
if self.is_eof():
|
||||
return self.EOF
|
||||
@ -159,7 +167,7 @@ class Parser(object):
|
||||
|
||||
def parse(self, expr, locations):
|
||||
self.locations = locations
|
||||
self.tokens = self.lex_scanner.scan(icu_lower(expr))[0]
|
||||
self.tokens = self.lex_scanner.scan(expr)[0]
|
||||
self.current_token = 0
|
||||
prog = self.or_expression()
|
||||
if not self.is_eof():
|
||||
@ -169,24 +177,25 @@ class Parser(object):
|
||||
|
||||
def or_expression(self):
|
||||
lhs = self.and_expression()
|
||||
if self.token() == 'or':
|
||||
if self.lcase_token() == 'or':
|
||||
self.advance()
|
||||
return ['or', lhs, self.or_expression()]
|
||||
return lhs
|
||||
|
||||
def and_expression(self):
|
||||
lhs = self.not_expression()
|
||||
if self.token() == 'and':
|
||||
if self.lcase_token() == 'and':
|
||||
self.advance()
|
||||
return ['and', lhs, self.and_expression()]
|
||||
|
||||
# Account for the optional 'and'
|
||||
if self.token_type() in [self.WORD, self.QUOTED_WORD] and self.token() != 'or':
|
||||
if (self.token_type() in [self.WORD, self.QUOTED_WORD] and
|
||||
self.lcase_token() != 'or'):
|
||||
return ['and', lhs, self.and_expression()]
|
||||
return lhs
|
||||
|
||||
def not_expression(self):
|
||||
if self.token() == 'not':
|
||||
if self.lcase_token() == 'not':
|
||||
self.advance()
|
||||
return ['not', self.not_expression()]
|
||||
return self.location_expression()
|
||||
@ -226,7 +235,7 @@ class Parser(object):
|
||||
words = words[1:]
|
||||
if len(words) == 1 and self.token_type() == self.QUOTED_WORD:
|
||||
return ['token', loc, self.token(advance=True)]
|
||||
return ['token', loc, ':'.join(words)]
|
||||
return ['token', icu_lower(loc), ':'.join(words)]
|
||||
|
||||
return ['token', 'all', ':'.join(words)]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user