1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2003 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing the lexer mixin class. 8""" 9 10import Preferences 11 12 13class Lexer: 14 """ 15 Class to implement the lexer mixin class. 16 """ 17 def __init__(self): 18 """ 19 Constructor 20 """ 21 self.commentString = '' 22 self.streamCommentString = { 23 'start': '', 24 'end': '' 25 } 26 self.boxCommentString = { 27 'start': '', 28 'middle': '', 29 'end': '' 30 } 31 32 # last indented line wrapper 33 self.lastIndented = -1 34 self.lastIndentedIndex = -1 35 36 # always keep tabs (for languages where tabs are esential 37 self._alwaysKeepTabs = False 38 39 # descriptions for keyword sets 40 self.keywordSetDescriptions = [] 41 42 def initProperties(self): 43 """ 44 Public slot to initialize the properties. 45 """ 46 # default implementation is a do nothing 47 return 48 49 def commentStr(self): 50 """ 51 Public method to return the comment string. 52 53 @return comment string (string) 54 """ 55 return self.commentString 56 57 def canBlockComment(self): 58 """ 59 Public method to determine, whether the lexer language supports a 60 block comment. 61 62 @return flag (boolean) 63 """ 64 return self.commentString != "" 65 66 def streamCommentStr(self): 67 """ 68 Public method to return the stream comment strings. 69 70 @return stream comment strings (dictionary with two strings) 71 """ 72 return self.streamCommentString 73 74 def canStreamComment(self): 75 """ 76 Public method to determine, whether the lexer language supports a 77 stream comment. 78 79 @return flag (boolean) 80 """ 81 return ( 82 self.streamCommentString['start'] != "" and 83 self.streamCommentString['end'] != "" 84 ) 85 86 def boxCommentStr(self): 87 """ 88 Public method to return the box comment strings. 89 90 @return box comment strings (dictionary with three QStrings) 91 """ 92 return self.boxCommentString 93 94 def canBoxComment(self): 95 """ 96 Public method to determine, whether the lexer language supports a 97 box comment. 98 99 @return flag (boolean) 100 """ 101 return ( 102 (self.boxCommentString['start'] != "") and 103 (self.boxCommentString['middle'] != "") and 104 (self.boxCommentString['end'] != "") 105 ) 106 107 def alwaysKeepTabs(self): 108 """ 109 Public method to check, if tab conversion is allowed. 110 111 @return flag indicating to keep tabs (boolean) 112 """ 113 return self._alwaysKeepTabs 114 115 def hasSmartIndent(self): 116 """ 117 Public method indicating whether lexer can do smart indentation. 118 119 @return flag indicating availability of smartIndentLine and 120 smartIndentSelection methods (boolean) 121 """ 122 return hasattr(self, 'getIndentationDifference') 123 124 def smartIndentLine(self, editor): 125 """ 126 Public method to handle smart indentation for a line. 127 128 @param editor reference to the QScintilla editor object 129 """ 130 cline, cindex = editor.getCursorPosition() 131 132 # get leading spaces 133 lead_spaces = editor.indentation(cline) 134 135 # get the indentation difference 136 indentDifference = self.getIndentationDifference(cline, editor) 137 138 if indentDifference != 0: 139 editor.setIndentation(cline, lead_spaces + indentDifference) 140 editor.setCursorPosition(cline, cindex + indentDifference) 141 142 self.lastIndented = cline 143 144 def smartIndentSelection(self, editor): 145 """ 146 Public method to handle smart indentation for a selection of lines. 147 148 Note: The assumption is, that the first line determines the new 149 indentation level. 150 151 @param editor reference to the QScintilla editor object 152 """ 153 if not editor.hasSelectedText(): 154 return 155 156 # get the selection 157 lineFrom, indexFrom, lineTo, indexTo = editor.getSelection() 158 if lineFrom != self.lastIndented: 159 self.lastIndentedIndex = indexFrom 160 161 endLine = lineTo if indexTo else lineTo - 1 162 163 # get the indentation difference 164 indentDifference = self.getIndentationDifference(lineFrom, editor) 165 166 editor.beginUndoAction() 167 # iterate over the lines 168 for line in range(lineFrom, endLine + 1): 169 editor.setIndentation( 170 line, editor.indentation(line) + indentDifference) 171 editor.endUndoAction() 172 173 indexStart = ( 174 indexFrom + indentDifference 175 if self.lastIndentedIndex != 0 else 176 0 177 ) 178 if indexStart < 0: 179 indexStart = 0 180 indexEnd = indexTo != 0 and (indexTo + indentDifference) or 0 181 if indexEnd < 0: 182 indexEnd = 0 183 editor.setSelection(lineFrom, indexStart, lineTo, indexEnd) 184 185 self.lastIndented = lineFrom 186 187 def autoCompletionWordSeparators(self): 188 """ 189 Public method to return the list of separators for autocompletion. 190 191 @return list of separators (list of strings) 192 """ 193 return [] 194 195 def isCommentStyle(self, style): 196 """ 197 Public method to check, if a style is a comment style. 198 199 @param style style to check (integer) 200 @return flag indicating a comment style (boolean) 201 """ 202 return True 203 204 def isStringStyle(self, style): 205 """ 206 Public method to check, if a style is a string style. 207 208 @param style style to check (integer) 209 @return flag indicating a string style (boolean) 210 """ 211 return True 212 213 def keywords(self, kwSet): 214 """ 215 Public method to get the keywords. 216 217 @param kwSet number of the keyword set 218 @type int 219 @return space separated list of keywords 220 @rtype str or None 221 """ 222 keywords_ = Preferences.getEditorKeywords(self.language()) 223 if keywords_ and len(keywords_) > kwSet: 224 kw = keywords_[kwSet] 225 if kw == "": 226 return self.defaultKeywords(kwSet) 227 else: 228 return kw 229 else: 230 return self.defaultKeywords(kwSet) 231 232 def keywordsDescription(self, kwSet): 233 """ 234 Public method to get the description for a keywords set. 235 236 @param kwSet number of the keyword set 237 @type int 238 @return description of the keyword set 239 @rtype str 240 """ 241 if kwSet > len(self.keywordSetDescriptions): 242 return "" 243 else: 244 return self.keywordSetDescriptions[kwSet - 1] 245 246 def defaultKeywords(self, kwSet): 247 """ 248 Public method to get the default keywords. 249 250 @param kwSet number of the keyword set 251 @type int 252 @return space separated list of keywords 253 @rtype str or None 254 """ 255 return None # __IGNORE_WARNING_M831__ 256 257 def maximumKeywordSet(self): 258 """ 259 Public method to get the maximum keyword set. 260 261 Note: A return value of 0 indicates to determine this dynamically. 262 263 @return maximum keyword set 264 @rtype int 265 """ 266 return len(self.keywordSetDescriptions) 267 268 def lexerName(self): 269 """ 270 Public method to return the lexer name. 271 272 @return lexer name (string) 273 """ 274 return self.lexer() 275 276 def hasSubstyles(self): 277 """ 278 Public method to indicate the support of sub-styles. 279 280 @return flag indicating sub-styling support 281 @rtype bool 282 """ 283 return False 284