codekingpro/portable-devtools
114k
1# Does Python source formatting for Scintilla controls.2import array3import string4 5import win32api6import win32con7import win32ui8 9from . import scintillacon10 11WM_KICKIDLE = 0x036A12 13# Used to indicate that style should use default color14from win32con import CLR_INVALID15 16debugging = 017if debugging:18 # Output must go to another process else the result of19 # the printing itself will trigger again trigger a trace.20 21 import win32trace22 import win32traceutil23 24 def trace(*args):25 win32trace.write(" ".join(map(str, args)) + "\n")26 27else:28 trace = lambda *args: None29 30 31class Style:32 """Represents a single format"""33 34 def __init__(self, name, format, background=CLR_INVALID):35 self.name = name # Name the format representes eg, "String", "Class"36 # Default background for each style is only used when there are no37 # saved settings (generally on first startup)38 self.background = self.default_background = background39 if type(format) == type(""):40 self.aliased = format41 self.format = None42 else:43 self.format = format44 self.aliased = None45 self.stylenum = None # Not yet registered.46 47 def IsBasedOnDefault(self):48 return len(self.format) == 549 50 # If the currently extended font defintion matches the51 # default format, restore the format to the "simple" format.52 def NormalizeAgainstDefault(self, defaultFormat):53 if self.IsBasedOnDefault():54 return 0 # No more to do, and not changed.55 bIsDefault = (56 self.format[7] == defaultFormat[7] and self.format[2] == defaultFormat[2]57 )58 if bIsDefault:59 self.ForceAgainstDefault()60 return bIsDefault61 62 def ForceAgainstDefault(self):63 self.format = self.format[:5]64 65 def GetCompleteFormat(self, defaultFormat):66 # Get the complete style after applying any relevant defaults.67 if len(self.format) == 5: # It is a default one68 fmt = self.format + defaultFormat[5:]69 else:70 fmt = self.format71 flags = (72 win32con.CFM_BOLD73 | win32con.CFM_CHARSET74 | win32con.CFM_COLOR75 | win32con.CFM_FACE76 | win32con.CFM_ITALIC77 | win32con.CFM_SIZE78 )79 return (flags,) + fmt[1:]80 81 82# The Formatter interface83# used primarily when the actual formatting is done by Scintilla!84class FormatterBase:85 def __init__(self, scintilla):86 self.scintilla = scintilla87 self.baseFormatFixed = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New")88 self.baseFormatProp = (-402653169, 0, 200, 0, 0, 0, 49, "Arial")89 self.bUseFixed = 190 self.styles = {} # Indexed by name91 self.styles_by_id = {} # Indexed by allocated ID.92 self.SetStyles()93 94 def HookFormatter(self, parent=None):95 raise NotImplementedError()96 97 # Used by the IDLE extensions to quickly determine if a character is a string.98 def GetStringStyle(self, pos):99 try:100 style = self.styles_by_id[self.scintilla.SCIGetStyleAt(pos)]101 except KeyError:102 # A style we dont know about - probably not even a .py file - can't be a string103 return None104 if style.name in self.string_style_names:105 return style106 return None107 108 def RegisterStyle(self, style, stylenum):109 assert stylenum is not None, "We must have a style number"110 assert style.stylenum is None, "Style has already been registered"111 assert stylenum not in self.styles, "We are reusing a style number!"112 style.stylenum = stylenum113 self.styles[style.name] = style114 self.styles_by_id[stylenum] = style115 116 def SetStyles(self):117 raise NotImplementedError()118 119 def GetSampleText(self):120 return "Sample Text for the Format Dialog"121 122 def GetDefaultFormat(self):123 if self.bUseFixed:124 return self.baseFormatFixed125 return self.baseFormatProp126 127 # Update the control with the new style format.128 def _ReformatStyle(self, style):129 ## Selection (background only for now)130 ## Passing False for WPARAM to SCI_SETSELBACK is documented as resetting to scintilla default,131 ## but does not work - selection background is not visible at all.132 ## Default value in SPECIAL_STYLES taken from scintilla source.133 if style.name == STYLE_SELECTION:134 clr = style.background135 self.scintilla.SendScintilla(scintillacon.SCI_SETSELBACK, True, clr)136 137 ## Can't change font for selection, but could set color138 ## However, the font color dropbox has no option for default, and thus would139 ## always override syntax coloring140 ## clr = style.format[4]141 ## self.scintilla.SendScintilla(scintillacon.SCI_SETSELFORE, clr != CLR_INVALID, clr)142 return143 144 assert style.stylenum is not None, "Unregistered style."145 # print "Reformat style", style.name, style.stylenum146 scintilla = self.scintilla147 stylenum = style.stylenum148 # Now we have the style number, indirect for the actual style.149 if style.aliased is not None:150 style = self.styles[style.aliased]151 f = style.format152 if style.IsBasedOnDefault():153 baseFormat = self.GetDefaultFormat()154 else:155 baseFormat = f156 scintilla.SCIStyleSetFore(stylenum, f[4])157 scintilla.SCIStyleSetFont(stylenum, baseFormat[7], baseFormat[5])158 if f[1] & 1:159 scintilla.SCIStyleSetBold(stylenum, 1)160 else:161 scintilla.SCIStyleSetBold(stylenum, 0)162 if f[1] & 2:163 scintilla.SCIStyleSetItalic(stylenum, 1)164 else:165 scintilla.SCIStyleSetItalic(stylenum, 0)166 scintilla.SCIStyleSetSize(stylenum, int(baseFormat[2] / 20))167 scintilla.SCIStyleSetEOLFilled(stylenum, 1) # Only needed for unclosed strings.168 169 ## Default style background to whitespace background if set,170 ## otherwise use system window color171 bg = style.background172 if bg == CLR_INVALID:173 bg = self.styles[STYLE_DEFAULT].background174 if bg == CLR_INVALID:175 bg = win32api.GetSysColor(win32con.COLOR_WINDOW)176 scintilla.SCIStyleSetBack(stylenum, bg)177 178 def GetStyleByNum(self, stylenum):179 return self.styles_by_id[stylenum]180 181 def ApplyFormattingStyles(self, bReload=1):182 if bReload:183 self.LoadPreferences()184 baseFormat = self.GetDefaultFormat()185 defaultStyle = Style("default", baseFormat)186 defaultStyle.stylenum = scintillacon.STYLE_DEFAULT187 self._ReformatStyle(defaultStyle)188 for style in list(self.styles.values()):189 if style.aliased is None:190 style.NormalizeAgainstDefault(baseFormat)191 self._ReformatStyle(style)192 self.scintilla.InvalidateRect()193 194 # Some functions for loading and saving preferences. By default195 # an INI file (well, MFC maps this to the registry) is used.196 def LoadPreferences(self):197 self.baseFormatFixed = eval(198 self.LoadPreference("Base Format Fixed", str(self.baseFormatFixed))199 )200 self.baseFormatProp = eval(201 self.LoadPreference("Base Format Proportional", str(self.baseFormatProp))202 )203 self.bUseFixed = int(self.LoadPreference("Use Fixed", 1))204 205 for style in list(self.styles.values()):206 new = self.LoadPreference(style.name, str(style.format))207 try:208 style.format = eval(new)209 except:210 print("Error loading style data for", style.name)211 # Use "vanilla" background hardcoded in PYTHON_STYLES if no settings in registry212 style.background = int(213 self.LoadPreference(214 style.name + " background", style.default_background215 )216 )217 218 def LoadPreference(self, name, default):219 return win32ui.GetProfileVal("Format", name, default)220 221 def SavePreferences(self):222 self.SavePreference("Base Format Fixed", str(self.baseFormatFixed))223 self.SavePreference("Base Format Proportional", str(self.baseFormatProp))224 self.SavePreference("Use Fixed", self.bUseFixed)225 for style in list(self.styles.values()):226 if style.aliased is None:227 self.SavePreference(style.name, str(style.format))228 bg_name = style.name + " background"229 self.SavePreference(bg_name, style.background)230 231 def SavePreference(self, name, value):232 win32ui.WriteProfileVal("Format", name, value)233 234 235# An abstract formatter236# For all formatters we actually implement here.237# (as opposed to those formatters built in to Scintilla)238class Formatter(FormatterBase):239 def __init__(self, scintilla):240 self.bCompleteWhileIdle = 0241 self.bHaveIdleHandler = 0 # Dont currently have an idle handle242 self.nextstylenum = 0243 FormatterBase.__init__(self, scintilla)244 245 def HookFormatter(self, parent=None):246 if parent is None:247 parent = self.scintilla.GetParent() # was GetParentFrame()!?248 parent.HookNotify(self.OnStyleNeeded, scintillacon.SCN_STYLENEEDED)249 250 def OnStyleNeeded(self, std, extra):251 notify = self.scintilla.SCIUnpackNotifyMessage(extra)252 endStyledChar = self.scintilla.SendScintilla(scintillacon.SCI_GETENDSTYLED)253 lineEndStyled = self.scintilla.LineFromChar(endStyledChar)254 endStyled = self.scintilla.LineIndex(lineEndStyled)255 # print "enPosPaint %d endStyledChar %d lineEndStyled %d endStyled %d" % (endPosPaint, endStyledChar, lineEndStyled, endStyled)256 self.Colorize(endStyled, notify.position)257 258 def ColorSeg(self, start, end, styleName):259 end = end + 1260 # assert end-start>=0, "Can't have negative styling"261 stylenum = self.styles[styleName].stylenum262 while start < end:263 self.style_buffer[start] = stylenum264 start = start + 1265 # self.scintilla.SCISetStyling(end - start + 1, stylenum)266 267 def RegisterStyle(self, style, stylenum=None):268 if stylenum is None:269 stylenum = self.nextstylenum270 self.nextstylenum = self.nextstylenum + 1271 FormatterBase.RegisterStyle(self, style, stylenum)272 273 def ColorizeString(self, str, charStart, styleStart):274 raise RuntimeError("You must override this method")275 276 def Colorize(self, start=0, end=-1):277 scintilla = self.scintilla278 # scintilla's formatting is all done in terms of utf, so279 # we work with utf8 bytes instead of unicode. This magically280 # works as any extended chars found in the utf8 don't change281 # the semantics.282 stringVal = scintilla.GetTextRange(start, end, decode=False)283 if start > 0:284 stylenum = scintilla.SCIGetStyleAt(start - 1)285 styleStart = self.GetStyleByNum(stylenum).name286 else:287 styleStart = None288 # trace("Coloring", start, end, end-start, len(stringVal), styleStart, self.scintilla.SCIGetCharAt(start))289 scintilla.SCIStartStyling(start, 31)290 self.style_buffer = array.array("b", (0,) * len(stringVal))291 self.ColorizeString(stringVal, styleStart)292 scintilla.SCISetStylingEx(self.style_buffer)293 self.style_buffer = None294 # trace("After styling, end styled is", self.scintilla.SCIGetEndStyled())295 if (296 self.bCompleteWhileIdle297 and not self.bHaveIdleHandler298 and end != -1299 and end < scintilla.GetTextLength()300 ):301 self.bHaveIdleHandler = 1302 win32ui.GetApp().AddIdleHandler(self.DoMoreColoring)303 # Kicking idle makes the app seem slower when initially repainting!304 305 # win32ui.GetMainFrame().PostMessage(WM_KICKIDLE, 0, 0)306 307 def DoMoreColoring(self, handler, count):308 try:309 scintilla = self.scintilla310 endStyled = scintilla.SCIGetEndStyled()311 lineStartStyled = scintilla.LineFromChar(endStyled)312 start = scintilla.LineIndex(lineStartStyled)313 end = scintilla.LineIndex(lineStartStyled + 1)314 textlen = scintilla.GetTextLength()315 if end < 0:316 end = textlen317 318 finished = end >= textlen319 self.Colorize(start, end)320 except (win32ui.error, AttributeError):321 # Window may have closed before we finished - no big deal!322 finished = 1323 324 if finished:325 self.bHaveIdleHandler = 0326 win32ui.GetApp().DeleteIdleHandler(handler)327 return not finished328 329 330# A Formatter that knows how to format Python source331from keyword import iskeyword, kwlist332 333wordstarts = "_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"334wordchars = "._0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"335operators = "%^&*()-+=|{}[]:;<>,/?!.~"336 337STYLE_DEFAULT = "Whitespace"338STYLE_COMMENT = "Comment"339STYLE_COMMENT_BLOCK = "Comment Blocks"340STYLE_NUMBER = "Number"341STYLE_STRING = "String"342STYLE_SQSTRING = "SQ String"343STYLE_TQSSTRING = "TQS String"344STYLE_TQDSTRING = "TQD String"345STYLE_KEYWORD = "Keyword"346STYLE_CLASS = "Class"347STYLE_METHOD = "Method"348STYLE_OPERATOR = "Operator"349STYLE_IDENTIFIER = "Identifier"350STYLE_BRACE = "Brace/Paren - matching"351STYLE_BRACEBAD = "Brace/Paren - unmatched"352STYLE_STRINGEOL = "String with no terminator"353STYLE_LINENUMBER = "Line numbers"354STYLE_INDENTGUIDE = "Indent guide"355STYLE_SELECTION = "Selection"356 357STRING_STYLES = [358 STYLE_STRING,359 STYLE_SQSTRING,360 STYLE_TQSSTRING,361 STYLE_TQDSTRING,362 STYLE_STRINGEOL,363]364 365# These styles can have any ID - they are not special to scintilla itself.366# However, if we use the built-in lexer, then we must use its style numbers367# so in that case, they _are_ special.368# (name, format, background, scintilla id)369PYTHON_STYLES = [370 (STYLE_DEFAULT, (0, 0, 200, 0, 0x808080), CLR_INVALID, scintillacon.SCE_P_DEFAULT),371 (372 STYLE_COMMENT,373 (0, 2, 200, 0, 0x008000),374 CLR_INVALID,375 scintillacon.SCE_P_COMMENTLINE,376 ),377 (378 STYLE_COMMENT_BLOCK,379 (0, 2, 200, 0, 0x808080),380 CLR_INVALID,381 scintillacon.SCE_P_COMMENTBLOCK,382 ),383 (STYLE_NUMBER, (0, 0, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_NUMBER),384 (STYLE_STRING, (0, 0, 200, 0, 0x008080), CLR_INVALID, scintillacon.SCE_P_STRING),385 (STYLE_SQSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_CHARACTER),386 (STYLE_TQSSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLE),387 (STYLE_TQDSTRING, STYLE_STRING, CLR_INVALID, scintillacon.SCE_P_TRIPLEDOUBLE),388 (STYLE_STRINGEOL, (0, 0, 200, 0, 0x000000), 0x008080, scintillacon.SCE_P_STRINGEOL),389 (STYLE_KEYWORD, (0, 1, 200, 0, 0x800000), CLR_INVALID, scintillacon.SCE_P_WORD),390 (STYLE_CLASS, (0, 1, 200, 0, 0xFF0000), CLR_INVALID, scintillacon.SCE_P_CLASSNAME),391 (STYLE_METHOD, (0, 1, 200, 0, 0x808000), CLR_INVALID, scintillacon.SCE_P_DEFNAME),392 (393 STYLE_OPERATOR,394 (0, 0, 200, 0, 0x000000),395 CLR_INVALID,396 scintillacon.SCE_P_OPERATOR,397 ),398 (399 STYLE_IDENTIFIER,400 (0, 0, 200, 0, 0x000000),401 CLR_INVALID,402 scintillacon.SCE_P_IDENTIFIER,403 ),404]405 406# These styles _always_ have this specific style number, regardless of407# internal or external formatter.408SPECIAL_STYLES = [409 (STYLE_BRACE, (0, 0, 200, 0, 0x000000), 0xFFFF80, scintillacon.STYLE_BRACELIGHT),410 (STYLE_BRACEBAD, (0, 0, 200, 0, 0x000000), 0x8EA5F2, scintillacon.STYLE_BRACEBAD),411 (412 STYLE_LINENUMBER,413 (0, 0, 200, 0, 0x000000),414 win32api.GetSysColor(win32con.COLOR_3DFACE),415 scintillacon.STYLE_LINENUMBER,416 ),417 (418 STYLE_INDENTGUIDE,419 (0, 0, 200, 0, 0x000000),420 CLR_INVALID,421 scintillacon.STYLE_INDENTGUIDE,422 ),423 ## Not actually a style; requires special handling to send appropriate messages to scintilla424 (425 STYLE_SELECTION,426 (0, 0, 200, 0, CLR_INVALID),427 win32api.RGB(0xC0, 0xC0, 0xC0),428 999999,429 ),430]431 432PythonSampleCode = """\433# Some Python434class Sample(Super):435 def Fn(self):436\tself.v = 1024437dest = 'dest.html'438x = func(a + 1)|)439s = "I forget...440## A large441## comment block"""442 443 444class PythonSourceFormatter(Formatter):445 string_style_names = STRING_STYLES446 447 def GetSampleText(self):448 return PythonSampleCode449 450 def LoadStyles(self):451 pass452 453 def SetStyles(self):454 for name, format, bg, ignore in PYTHON_STYLES:455 self.RegisterStyle(Style(name, format, bg))456 for name, format, bg, sc_id in SPECIAL_STYLES:457 self.RegisterStyle(Style(name, format, bg), sc_id)458 459 def ClassifyWord(self, cdoc, start, end, prevWord):460 word = cdoc[start : end + 1].decode("latin-1")461 attr = STYLE_IDENTIFIER462 if prevWord == "class":463 attr = STYLE_CLASS464 elif prevWord == "def":465 attr = STYLE_METHOD466 elif word[0] in string.digits:467 attr = STYLE_NUMBER468 elif iskeyword(word):469 attr = STYLE_KEYWORD470 self.ColorSeg(start, end, attr)471 return word472 473 def ColorizeString(self, str, styleStart):474 if styleStart is None:475 styleStart = STYLE_DEFAULT476 return self.ColorizePythonCode(str, 0, styleStart)477 478 def ColorizePythonCode(self, cdoc, charStart, styleStart):479 # Straight translation of C++, should do better480 lengthDoc = len(cdoc)481 if lengthDoc <= charStart:482 return483 prevWord = ""484 state = styleStart485 chPrev = chPrev2 = chPrev3 = " "486 chNext2 = chNext = cdoc[charStart : charStart + 1].decode("latin-1")487 startSeg = i = charStart488 while i < lengthDoc:489 ch = chNext490 chNext = " "491 if i + 1 < lengthDoc:492 chNext = cdoc[i + 1 : i + 2].decode("latin-1")493 chNext2 = " "494 if i + 2 < lengthDoc:495 chNext2 = cdoc[i + 2 : i + 3].decode("latin-1")496 if state == STYLE_DEFAULT:497 if ch in wordstarts:498 self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)499 state = STYLE_KEYWORD500 startSeg = i501 elif ch == "#":502 self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)503 if chNext == "#":504 state = STYLE_COMMENT_BLOCK505 else:506 state = STYLE_COMMENT507 startSeg = i508 elif ch == '"':509 self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)510 startSeg = i511 state = STYLE_COMMENT512 if chNext == '"' and chNext2 == '"':513 i = i + 2514 state = STYLE_TQDSTRING515 ch = " "516 chPrev = " "517 chNext = " "518 if i + 1 < lengthDoc:519 chNext = cdoc[i + 1]520 else:521 state = STYLE_STRING522 elif ch == "'":523 self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)524 startSeg = i525 state = STYLE_COMMENT526 if chNext == "'" and chNext2 == "'":527 i = i + 2528 state = STYLE_TQSSTRING529 ch = " "530 chPrev = " "531 chNext = " "532 if i + 1 < lengthDoc:533 chNext = cdoc[i + 1]534 else:535 state = STYLE_SQSTRING536 elif ch in operators:537 self.ColorSeg(startSeg, i - 1, STYLE_DEFAULT)538 self.ColorSeg(i, i, STYLE_OPERATOR)539 startSeg = i + 1540 elif state == STYLE_KEYWORD:541 if ch not in wordchars:542 prevWord = self.ClassifyWord(cdoc, startSeg, i - 1, prevWord)543 state = STYLE_DEFAULT544 startSeg = i545 if ch == "#":546 if chNext == "#":547 state = STYLE_COMMENT_BLOCK548 else:549 state = STYLE_COMMENT550 elif ch == '"':551 if chNext == '"' and chNext2 == '"':552 i = i + 2553 state = STYLE_TQDSTRING554 ch = " "555 chPrev = " "556 chNext = " "557 if i + 1 < lengthDoc:558 chNext = cdoc[i + 1]559 else:560 state = STYLE_STRING561 elif ch == "'":562 if chNext == "'" and chNext2 == "'":563 i = i + 2564 state = STYLE_TQSSTRING565 ch = " "566 chPrev = " "567 chNext = " "568 if i + 1 < lengthDoc:569 chNext = cdoc[i + 1]570 else:571 state = STYLE_SQSTRING572 elif ch in operators:573 self.ColorSeg(startSeg, i, STYLE_OPERATOR)574 startSeg = i + 1575 elif state == STYLE_COMMENT or state == STYLE_COMMENT_BLOCK:576 if ch == "\r" or ch == "\n":577 self.ColorSeg(startSeg, i - 1, state)578 state = STYLE_DEFAULT579 startSeg = i580 elif state == STYLE_STRING:581 if ch == "\\":582 if chNext == '"' or chNext == "'" or chNext == "\\":583 i = i + 1584 ch = chNext585 chNext = " "586 if i + 1 < lengthDoc:587 chNext = cdoc[i + 1]588 elif ch == '"':589 self.ColorSeg(startSeg, i, STYLE_STRING)590 state = STYLE_DEFAULT591 startSeg = i + 1592 elif state == STYLE_SQSTRING:593 if ch == "\\":594 if chNext == '"' or chNext == "'" or chNext == "\\":595 i = i + 1596 ch = chNext597 chNext = " "598 if i + 1 < lengthDoc:599 chNext = cdoc[i + 1]600 elif ch == "'":601 self.ColorSeg(startSeg, i, STYLE_SQSTRING)602 state = STYLE_DEFAULT603 startSeg = i + 1604 elif state == STYLE_TQSSTRING:605 if ch == "'" and chPrev == "'" and chPrev2 == "'" and chPrev3 != "\\":606 self.ColorSeg(startSeg, i, STYLE_TQSSTRING)607 state = STYLE_DEFAULT608 startSeg = i + 1609 elif (610 state == STYLE_TQDSTRING611 and ch == '"'612 and chPrev == '"'613 and chPrev2 == '"'614 and chPrev3 != "\\"615 ):616 self.ColorSeg(startSeg, i, STYLE_TQDSTRING)617 state = STYLE_DEFAULT618 startSeg = i + 1619 chPrev3 = chPrev2620 chPrev2 = chPrev621 chPrev = ch622 i = i + 1623 if startSeg < lengthDoc:624 if state == STYLE_KEYWORD:625 self.ClassifyWord(cdoc, startSeg, lengthDoc - 1, prevWord)626 else:627 self.ColorSeg(startSeg, lengthDoc - 1, state)628 629 630# These taken from the SciTE properties file.631source_formatter_extensions = [632 (".py .pys .pyw".split(), scintillacon.SCLEX_PYTHON),633 (".html .htm .asp .shtml".split(), scintillacon.SCLEX_HTML),634 (635 "c .cc .cpp .cxx .h .hh .hpp .hxx .idl .odl .php3 .phtml .inc .js".split(),636 scintillacon.SCLEX_CPP,637 ),638 (".vbs .frm .ctl .cls".split(), scintillacon.SCLEX_VB),639 (".pl .pm .cgi .pod".split(), scintillacon.SCLEX_PERL),640 (".sql .spec .body .sps .spb .sf .sp".split(), scintillacon.SCLEX_SQL),641 (".tex .sty".split(), scintillacon.SCLEX_LATEX),642 (".xml .xul".split(), scintillacon.SCLEX_XML),643 (".err".split(), scintillacon.SCLEX_ERRORLIST),644 (".mak".split(), scintillacon.SCLEX_MAKEFILE),645 (".bat .cmd".split(), scintillacon.SCLEX_BATCH),646]647 648 649class BuiltinSourceFormatter(FormatterBase):650 # A class that represents a formatter built-in to Scintilla651 def __init__(self, scintilla, ext):652 self.ext = ext653 FormatterBase.__init__(self, scintilla)654 655 def Colorize(self, start=0, end=-1):656 self.scintilla.SendScintilla(scintillacon.SCI_COLOURISE, start, end)657 658 def RegisterStyle(self, style, stylenum=None):659 assert style.stylenum is None, "Style has already been registered"660 if stylenum is None:661 stylenum = self.nextstylenum662 self.nextstylenum = self.nextstylenum + 1663 assert self.styles.get(stylenum) is None, "We are reusing a style number!"664 style.stylenum = stylenum665 self.styles[style.name] = style666 self.styles_by_id[stylenum] = style667 668 def HookFormatter(self, parent=None):669 sc = self.scintilla670 for exts, formatter in source_formatter_extensions:671 if self.ext in exts:672 formatter_use = formatter673 break674 else:675 formatter_use = scintillacon.SCLEX_PYTHON676 sc.SendScintilla(scintillacon.SCI_SETLEXER, formatter_use)677 keywords = " ".join(kwlist)678 sc.SCISetKeywords(keywords)679 680 681class BuiltinPythonSourceFormatter(BuiltinSourceFormatter):682 sci_lexer_name = scintillacon.SCLEX_PYTHON683 string_style_names = STRING_STYLES684 685 def __init__(self, sc, ext=".py"):686 BuiltinSourceFormatter.__init__(self, sc, ext)687 688 def SetStyles(self):689 for name, format, bg, sc_id in PYTHON_STYLES:690 self.RegisterStyle(Style(name, format, bg), sc_id)691 for name, format, bg, sc_id in SPECIAL_STYLES:692 self.RegisterStyle(Style(name, format, bg), sc_id)693 694 def GetSampleText(self):695 return PythonSampleCode696 