def _GenRtf(self): """Generates the RTF equivalent of the displayed text in the current stc document window. @precondition: self._stc must have been set by a call to Generate @return: generated rtf marked up text """ # Buffer hasn't been set if self._stc is None: return u'' # Optimizations stc = self._stc def_fore = stc.GetDefaultForeColour(as_hex=True) self._colortbl.AddColor(def_fore) def_back = stc.GetDefaultBackColour(as_hex=True) self._colortbl.AddColor(def_back) last_pos = stc.GetLineEndPosition(stc.GetLineCount()) parse_pos = 0 last_id = None last_fore = None last_back = None start = end = 0 tmp_txt = list() font_tmp = "\\f0" fore_tmp = "\\cf%d" back_tmp = "\\cb%d" AddColor = self._colortbl.AddColor GetColorIndex = self._colortbl.GetColorIndex GetStyleAt = stc.GetStyleAt # Parse all characters/style bytes in document for parse_pos in xrange(last_pos + 1): sty_id = GetStyleAt(parse_pos) end = parse_pos # If style has changed build the previous section if sty_id != last_id: tag = stc.FindTagById(last_id) s_item = stc.GetItemByName(tag) AddColor(s_item.GetFore()) AddColor(s_item.GetBack()) tplate = font_tmp fid = GetColorIndex(s_item.GetFore()) if fid != last_fore: last_fore = fid tplate = tplate + (fore_tmp % fid) bid = GetColorIndex(s_item.GetBack()) if bid != last_back: last_back = bid tplate = tplate + (back_tmp % bid) tmp_txt.append(tplate + " " + \ self.TransformText(stc.GetTextRange(start, end))) start = end last_id = sty_id head = "{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0 %s;}}" % \ stc.GetDefaultFont().GetFaceName() return u"%s%s%s}" % (head, self._colortbl, "".join(tmp_txt))
def __init__(self, stc, colourMode=0, filename='', doPageNums=1): wx.Printout.__init__(self) self.stc = stc self.colourMode = colourMode self.filename = filename self.doPageNums = doPageNums self.pageTotal, m = divmod(stc.GetLineCount(), self.linesPerPage) if m: self.pageTotal += 1
def StyleText(stc, start, end): """Style the text @param stc: Styled text control instance @param start: Start position @param end: end position """ max_styled_line = max_line_cache.get(id(stc), 0) # Set up the bad indentation indicator style. if stc.IndicatorGetStyle(1) != wx.stc.STC_INDIC_SQUIGGLE: stc.IndicatorSetStyle(1, wx.stc.STC_INDIC_SQUIGGLE) stc.IndicatorSetForeground(1, "#FF0000") # A change to one line can change others below it. So we restyle all # visible text with any change. (We restyle a bit more so we don't get # caught in things like triple-quoted strings.) try: vis_end_line = stc.GetLastVisibleLine() + 20 except: # Fails if we're in the preview. vis_end_line = stc.GetLineCount() vis_end_pos = stc.GetLineEndPosition(vis_end_line) end = max(end, vis_end_pos) # First, figure out the line based on the position. line = stc.LineFromPosition(start) # Jump back a bunch of lines, so that we always restyle the entire # screen. line = min(line - 60, max_styled_line) if line < 0: line = 0 # Find the start of the line that's been styled before this one. while line and stc.GetLineState(line) == 0: line -= 1 # The indentation starting the current block. (None to indicate # it hasn't been set yet.) block_indent = 0 # The type of block we're dealing with. block_type = BLOCK_RPY # Is this block's indentation optional? block_maybe_indents = False # A stack of outer blocks, giving the indent and type of those # blocks. block_stack = [] # Find the last line before line with a 0 indent. (Or the first # line if we don't have one line that.) base_line = line while base_line > 0: base_line -= 1 state = stc.GetLineState(base_line) if not state: continue indent = state & INDENT_MASK if indent == 0: break if base_line < 0: base_line = 0 # Figure out what sort of block we're in, and build up the stack # of non-closed blocks. for i in range(base_line, line): state = stc.GetLineState(i) if not state: continue indent = state & INDENT_MASK if block_indent is None: block_indent = indent if state & INDENTS: block_stack.append((block_indent, block_type)) block_indent = None block_type = state & BLOCK_MASK if state & MAYBE_INDENTS: block_maybe_indents = True else: block_maybe_indents = False while indent < block_indent: block_indent, block_type = block_stack.pop() # Clean out the old (no longer relevant) line states. for i in range(line, max_styled_line + 1): stc.SetLineState(i, 0) new_start = stc.PositionFromLine(line) text = stc.GetTextRangeUTF8(new_start, end) # End open strings. text += "\n\"\"\"'''" len_text = len(text) pos = 0 # stc.StartStyling(new_start, 0xff & (~wx.stc.STC_INDIC2_MASK)) sb = StyleBuffer(stc, new_start, 0xff & (~wx.stc.STC_INDIC2_MASK)) while pos < len_text: # The line and pos this statement begins on. statement_line = line m = line_start_re.match(text, pos) pos = m.end() indent = len(m.group('indent')) comment = m.group('comment') eol = m.group('eol') if eol: sb.style(indent, STC_RENPY_DEFAULT) # Style a line-long comment. if comment: sb.style(len(comment), STC_RENPY_COMMENT) # If the line is empty, continue. if eol: sb.style(len(eol), STC_RENPY_DEFAULT) line += 1 continue # Otherwise, we have a real line. Figure out the indentation of it. indent_indicator = 0 # If we're indented from the previous line and starting a new block, # deal with that. if block_indent is None and indent > block_stack[-1][0]: block_indent = indent # Deal with empty blocks. Not an error, because of label. if block_indent is None: if INDENT_ERRORS and not block_maybe_indents: indent_indicator = wx.stc.STC_INDIC1_MASK block_indent, block_type = block_stack.pop() # We outdented, go out a block or more. while block_indent > indent: block_indent, block_type = block_stack.pop() # Now check that we match the current block. if INDENT_ERRORS and indent != block_indent: # Indentation error. indent_indicator = wx.stc.STC_INDIC1_MASK # Style the indentation. sb.style(indent, STC_RENPY_DEFAULT | indent_indicator) # Store the line type. line_type = block_type >> 4 line_text = "" paren_depth = 0 while True: m = regex.match(text, pos) if not m: break pos = m.end() if pos > len_text: pos = len_text # Rules for applying styling. string = m.group("string") if string: line_text += string line += string.count("\n") i = 0 while string[i] in 'ur': i += 1 sb.style(i + 1, STC_RENPY_DEFAULT) sb.style(len(string) - 2 - i, STC_RENPY_STRING) sb.style(1, STC_RENPY_DEFAULT) continue word = m.group("word") if word: line_text += word style = STC_RENPY_DEFAULT if line_type == LINE_RPY: if word in RENPY_KEYWORDS: style = STC_RENPY_KEYWORD elif word in RENPY_PROPERTIES: style = STC_RENPY_KEYWORD2 elif line_type == LINE_PY: if word in PYTHON_KEYWORDS: style = STC_RENPY_KEYWORD sb.style(len(word), style) continue comment = m.group("comment") if comment: # Don't include comment text in line_text. sb.style(len(comment), STC_RENPY_COMMENT) continue # Style everything else. line_text += m.group(0) sb.style(len(m.group(0)), STC_RENPY_DEFAULT) # Rules for everything else. if m.group("open_paren"): paren_depth += 1 elif m.group("close_paren"): paren_depth -= 1 elif m.group("eol"): line += 1 if not paren_depth: break # End a runaway line, eventually. if len(line_text) > 8000: break line_text = line_text.strip() block_maybe_indents = False if line_text and line_text[-1] == ':': block_stack.append((block_indent, block_type)) block_indent = None indents = INDENTS if line_text.startswith("label"): indents |= MAYBE_INDENTS block_maybe_indents = True if line_type == LINE_RPY: block_type = BLOCK_RPY if renpy_python.match(line_text): block_type = BLOCK_PY else: block_type = BLOCK_PY else: indents = 0 new_state = indent | line_type | block_type | indents stc.SetLineState(statement_line, new_state) sb.apply() max_line_cache[id(stc)] = line