#textInfos/offsets.py #A part of NonVisual Desktop Access (NVDA) #This file is covered by the GNU General Public License. #See the file COPYING for more details. #Copyright (C) 2006 Michael Curran , James Teh import re import ctypes import unicodedata import NVDAHelper import config import textInfos class Offsets(object): """Represents two offsets.""" def __init__(self,startOffset,endOffset): """ @param startOffset: the first offset. @type startOffset: integer @param endOffset: the second offset. @type endOffset: integer """ self.startOffset=startOffset self.endOffset=endOffset def __eq__(self,other): if isinstance(other,self.__class__) and self.startOffset==other.startOffset and self.endOffset==other.endOffset: return True else: return False def __ne__(self,other): return not self==other def findStartOfLine(text,offset,lineLength=None): """Searches backwards through the given text from the given offset, until it finds the offset that is the start of the line. With out a set line length, it searches for new line / cariage return characters, with a set line length it simply moves back to sit on a multiple of the line length. @param text: the text to search @type text: string @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @type lineLength: int or None @return: the found offset @rtype: int """ if not text: return 0 if offset>=len(text): offset=len(text)-1 if isinstance(lineLength,int): return offset-(offset%lineLength) if text[offset]=='\n' and offset>=0 and text[offset-1]=='\r': offset-=1 start=text.rfind('\n',0,offset) if start<0: start=text.rfind('\r',0,offset) if start<0: start=-1 return start+1 def findEndOfLine(text,offset,lineLength=None): """Searches forwards through the given text from the given offset, until it finds the offset that is the start of the next line. With out a set line length, it searches for new line / cariage return characters, with a set line length it simply moves forward to sit on a multiple of the line length. @param text: the text to search @type text: unicode @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @type lineLength: int or None @return: the found offset @rtype: int """ if not text: return 0 if offset>=len(text): offset=len(text)-1 if isinstance(lineLength,int): return (offset-(offset%lineLength)+lineLength) end=offset if text[end]!='\n': end=text.find('\n',offset) if end<0: if text[offset]!='\r': end=text.find('\r',offset) if end<0: end=len(text)-1 return end+1 def findStartOfWord(text,offset,lineLength=None): """Searches backwards through the given text from the given offset, until it finds the offset that is the start of the word. It checks to see if a character is alphanumeric, or is another symbol , or is white space. @param text: the text to search @type text: unicode @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @type lineLength: int or None @return: the found offset @rtype: int """ if offset>=len(text): return offset while offset>0 and text[offset].isspace(): offset-=1 if unicodedata.category(text[offset])[0] not in "LMN": return offset else: while offset>0 and unicodedata.category(text[offset-1])[0] in "LMN": offset-=1 return offset def findEndOfWord(text,offset,lineLength=None): """Searches forwards through the given text from the given offset, until it finds the offset that is the start of the next word. It checks to see if a character is alphanumeric, or is another symbol , or is white space. @param text: the text to search @type text: unicode @param offset: the offset of the text to start at @type offset: int @param lineLength: The number of characters that makes up a line, None if new line characters should be looked at instead @type lineLength: int or None @return: the found offset @rtype: int """ if offset>=len(text): return offset+1 if unicodedata.category(text[offset])[0] in "LMN": while offset0: diff=1 return diff def setEndPoint(self,other,which): if which=="startToStart": self._startOffset=other._startOffset elif which=="startToEnd": self._startOffset=other._endOffset elif which=="endToStart": self._endOffset=other._startOffset elif which=="endToEnd": self._endOffset=other._endOffset else: raise ValueError("bad argument - which: %s"%which) if self._startOffset>self._endOffset: # start should never be after end. if which in ("startToStart","startToEnd"): self._endOffset=self._startOffset else: self._startOffset=self._endOffset def getTextWithFields(self,formatConfig=None): if not formatConfig: formatConfig=config.conf["documentFormatting"] if self.detectFormattingAfterCursorMaybeSlow and not formatConfig['detectFormatAfterCursor']: field,(boundStart,boundEnd)=self._getFormatFieldAndOffsets(self._startOffset,formatConfig,calculateOffsets=False) text=self.text return [textInfos.FieldCommand('formatChange',field),text] commandList=[] offset=self._startOffset while offset0 and offset>lastOffset) or (direction<0 and offsetlowLimit or direction>0): lastOffset=offset if direction<0 and offset>lowLimit: offset-=1 newStart,newEnd=self._getUnitOffsets(unit,offset) if direction<0: offset=newStart elif direction>0: offset=newEnd count=count+1 if direction>0 else count-1 if endPoint=="start": if (direction>0 and offset<=self._startOffset) or (direction<0 and offset>=self._startOffset) or offset=highLimit: return 0 self._startOffset=offset elif endPoint=="end": if (direction>0 and offset<=self._endOffset) or (direction<0 and offset>=self._endOffset) or offsethighLimit: return 0 self._endOffset=offset else: if (direction>0 and offset<=self._startOffset) or (direction<0 and offset>=self._startOffset) or offset=highLimit: return 0 self._startOffset=self._endOffset=offset if self._startOffset>self._endOffset: tempOffset=self._startOffset self._startOffset=self._endOffset self._endOffset=tempOffset return count def find(self,text,caseSensitive=False,reverse=False): if reverse: # When searching in reverse, we reverse both strings and do a forwards search. text = text[::-1] # Start searching one before the start to avoid finding the current match. inText=self._getTextRange(0,self._startOffset)[::-1] else: # Start searching one past the start to avoid finding the current match. inText=self._getTextRange(self._startOffset+1,self._getStoryLength()) m=re.search(re.escape(text),inText,(0 if caseSensitive else re.IGNORECASE)|re.UNICODE) if not m: return False if reverse: offset=self._startOffset-m.end() else: offset=self._startOffset+1+m.start() self._startOffset=self._endOffset=offset return True def updateCaret(self): return self._setCaretOffset(self._startOffset) def updateSelection(self): return self._setSelectionOffsets(self._startOffset,self._endOffset) def _get_bookmark(self): return Offsets(self._startOffset,self._endOffset)