%PDF- %PDF-
Direktori : /lib/python3/dist-packages/orca/ |
Current File : //lib/python3/dist-packages/orca/find.py |
# Orca # # Copyright 2006-2008 Sun Microsystems Inc. # Copyright 2022 Igalia, S.L. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., Franklin Street, Fifth Floor, # Boston MA 02110-1301 USA. """Provides support for a flat review find.""" __id__ = "$Id$" __version__ = "$Revision$" __date__ = "$Date$" __copyright__ = "Copyright (c) 2006-2008 Sun Microsystems Inc." \ "Copyright (c) 2022 Igalia, S.L." __license__ = "LGPL" import copy import re from . import debug from . import messages from . import orca_state from . import script_manager from .flat_review import Context class _SearchQueryMatch: """Represents a SearchQuery match.""" def __init__(self, context, pattern): self._line = context.lineIndex self._zone = context.zoneIndex self._word = context.wordIndex self._char = context.charIndex self._pattern = pattern self._lineString = context.getCurrent(Context.LINE)[0] def __str__(self): return "SEARCH QUERY MATCH: '%s' (line %i, zone %i, word %i, char %i) for '%s'" % \ (self._lineString, self._line, self._zone, self._word, self._char, self._pattern) def __eq__(self, other): if not other: return False return self._lineString == other._lineString and \ self._line == other._line and \ self._zone == other._zone and \ self._word == other._word and \ self._char == other._char class SearchQuery: """Represents a search that the user wants to perform.""" def __init__(self): """Creates a new SearchQuery. A searchQuery has the following properties: searchString - the string to find searchBackwards - if true, search upward for matches caseSensitive - if true, case counts matchEntireWord - if true, only match on the entire string startAtTop - if true, begin the search from the top of the window, rather than at the current location windowWrap - if true, when the top/bottom edge of the window is reached wrap to the bottom/top and continue searching """ self.searchString = "" self.searchBackwards = False self.caseSensitive = False self.matchEntireWord = False self.windowWrap = False self.startAtTop = False self.debugLevel = debug.LEVEL_INFO self._contextLocation = [0, 0, 0, 0] self._match = None self._wrapped = False def __str__(self): string = f"FIND QUERY: '{self.searchString}'." options = [] if self.searchBackwards: options.append("search backwards") if self.caseSensitive: options.append("case sensitive") if self.matchEntireWord: options.append("match entire word") if self.windowWrap: options.append("wrap") if self.startAtTop: options.append("start at top") if options: string += f" Options: {', '.join(options)}" if self._match: string += f" Last match: {self._match}" return string def previousMatch(self): if not orca_state.searchQuery: return None return orca_state.searchQuery._match def _saveContextLocation(self, context): self._contextLocation = [context.lineIndex, context.zoneIndex, context.wordIndex, context.charIndex] def _restoreContextLocation(self, context): context.setCurrent(*self._contextLocation) self._contextLocation = [0, 0, 0, 0] def _currentContextMatches(self, context, pattern, contextType): if contextType == Context.LINE: typeString = "LINE" elif contextType == Context.ZONE: typeString = "ZONE" elif contextType == Context.WORD: typeString = "WORD" else: return False string = context.getCurrent(contextType)[0] match = re.search(pattern, string) msg = "FIND: %s='%s'. Match: %s" % (typeString, string.replace("\n", "\\n"), match) debug.println(self.debugLevel, msg, True) return bool(match) def _move(self, context, contextType): if contextType == Context.WORD: if self.searchBackwards: return context.goPrevious(Context.WORD, Context.WRAP_LINE) return context.goNext(Context.WORD, Context.WRAP_LINE) if contextType == Context.ZONE: if self.searchBackwards: moved = context.goPrevious(Context.ZONE, Context.WRAP_LINE) context.goEnd(Context.ZONE) return moved return context.goNext(Context.ZONE, Context.WRAP_LINE) if contextType == Context.LINE: if self.searchBackwards: moved = context.goPrevious(Context.LINE, Context.WRAP_LINE) context.goEnd(Context.LINE) else: moved = context.goNext(Context.LINE, Context.WRAP_LINE) if moved: return True if not self.windowWrap or self._wrapped: return False self._wrapped = True script = script_manager.getManager().getActiveScript() if self.searchBackwards: script.presentMessage(messages.WRAPPING_TO_BOTTOM) moved = context.goPrevious(Context.LINE, Context.WRAP_ALL) else: script.presentMessage(messages.WRAPPING_TO_TOP) moved = context.goNext(Context.LINE, Context.WRAP_ALL) return moved return False def _findMatchIn(self, context, pattern, contextType): found = self._currentContextMatches(context, pattern, contextType) while not found: if not self._move(context, contextType): break found = self._currentContextMatches(context, pattern, contextType) return found def _findMatch(self, context, pattern): if not self._findMatchIn(context, pattern, Context.LINE): return False if not self._findMatchIn(context, pattern, Context.ZONE): return False if not self._findMatchIn(context, pattern, Context.WORD): return False if not self.previousMatch(): return True candidateMatch = _SearchQueryMatch(context, pattern) if candidateMatch != self.previousMatch(): return True if self._move(context, Context.WORD) \ and self._findMatchIn(context, pattern, Context.WORD): return True if self._move(context, Context.ZONE) \ and self._findMatchIn(context, pattern, Context.ZONE): return True if self._move(context, Context.LINE): return self._findMatch(context, pattern) return False def findQuery(self, context): """Performs a search on the string specified in searchQuery. Arguments: - context: The context from active script Returns: - The context of the match, if found """ debug.println(self.debugLevel, str(self), True) flags = re.U if not self.caseSensitive: flags = flags | re.IGNORECASE if self.matchEntireWord: regexp = "\\b" + self.searchString + "\\b" else: regexp = self.searchString pattern = re.compile(regexp, flags) self._saveContextLocation(context) if self.startAtTop: context.goBegin(Context.WINDOW) location = None if self._findMatch(context, pattern): self._saveContextLocation(context) self._match = _SearchQueryMatch(context, pattern) self._wrapped = False location = copy.copy(context) else: self._restoreContextLocation(context) orca_state.searchQuery = copy.copy(self) return location def getLastQuery(): """Grabs the last search query performed from orca_state. Returns: - A copy of the last search query, if it exists """ lastQuery = copy.copy(orca_state.searchQuery) return lastQuery