def AutoIndenter(stc, pos, ichar): """Auto indent cpp code. uses \n the text buffer will handle any eol character formatting. @param stc: EditraStyledTextCtrl @param pos: current carat position @param ichar: Indentation character @return: string """ rtxt = u'' line = stc.GetCurrentLine() text = stc.GetTextRange(stc.PositionFromLine(line), pos) indent = stc.GetLineIndentation(line) if ichar == u"\t": tabw = stc.GetTabWidth() else: tabw = stc.GetIndent() i_space = indent / tabw ndent = u"\n" + ichar * i_space rtxt = ndent + ((indent - (tabw * i_space)) * u' ') def_pat = re.compile('\s*(class|def)\s+[a-zA-Z_][a-zA-Z0-9_]*') text = text.strip() if text.endswith('{') or def_pat.match(text): rtxt += ichar return rtxt
def AutoIndenter(stc, pos, ichar): """Auto indent Inno Setup Scripts. uses \n the text buffer will handle any eol character formatting. @param stc: EditraStyledTextCtrl @param pos: current carat position @param ichar: Indentation character @return: string """ rtxt = u'' line = stc.GetCurrentLine() text = stc.GetTextRange(stc.PositionFromLine(line), pos) indent = stc.GetLineIndentation(line) if ichar == u"\t": tabw = stc.GetTabWidth() else: tabw = stc.GetIndent() i_space = indent / tabw ndent = u"\n" + ichar * i_space rtxt = ndent + ((indent - (tabw * i_space)) * u' ') if_pat = re.compile('if\s+.*\sthen') text = text.strip() if text == u'begin' or if_pat.match(text): rtxt += ichar return rtxt
def AutoIndenter(stc, pos, ichar): """Auto indent python code. uses \n the text buffer will handle any eol character formatting. @param stc: EditraStyledTextCtrl @param pos: current carat position @param ichar: Indentation character @return: string """ rtxt = u'' line = stc.GetCurrentLine() spos = stc.PositionFromLine(line) text = stc.GetTextRange(spos, pos) epos = stc.GetLineEndPosition(line) inspace = text.isspace() # Cursor is in the indent area somewhere if inspace: return u"\n" + text # Check if the cursor is in column 0 and just return newline. if not len(text): return u"\n" # Ignore empty lines and backtrace to find the previous line that we can # get the indent position from # while text.isspace(): # line -= 1 # if line < 0: # return u'' # text = stc.GetTextRange(stc.PositionFromLine(line), pos) indent = stc.GetLineIndentation(line) if ichar == u"\t": tabw = stc.GetTabWidth() else: tabw = stc.GetIndent() i_space = indent / tabw end_spaces = ((indent - (tabw * i_space)) * u" ") tokens = filter(None, text.strip().split()) if tokens and not inspace: if tokens[-1].endswith(u":"): if tokens[0].rstrip(u":") in INDENT_KW: i_space += 1 elif tokens[-1].endswith(u"\\"): i_space += 1 elif tokens[0] in UNINDENT_KW: i_space = max(i_space - 1, 0) rval = u"\n" + (ichar * i_space) + end_spaces if inspace and ichar != u"\t": rpos = indent - (pos - spos) if rpos < len(rval) and rpos > 0: rval = rval[:-rpos] elif rpos >= len(rval): rval = u"\n" return rval
def AutoIndenter(stc, pos, ichar): """Auto indent cpp code. uses \n the text buffer will handle any eol character formatting. @param stc: EditraStyledTextCtrl @param pos: current carat position @param ichar: Indentation character @return: string """ rtxt = u'' line = stc.GetCurrentLine() text = stc.GetTextRange(stc.PositionFromLine(line), pos) indent = stc.GetLineIndentation(line) if ichar == u"\t": tabw = stc.GetTabWidth() else: tabw = stc.GetIndent() i_space = indent / tabw ndent = u"\n" + ichar * i_space rtxt = ndent + ((indent - (tabw * i_space)) * u' ') blks = '(program|function|subroutine|if|do|while)' blk_pat = re.compile(blks + '\s*[(a-zA-Z][a-zA-Z0-9]*', re.IGNORECASE) text = text.strip() if text.endswith('{') or blk_pat.match(text) or text == 'else': rtxt += ichar return rtxt
def reindentLine(self, stc, linenum=None, dedent_only=False): """Reindent the specified line to the correct level. Changes the indentation of the given line by inserting or deleting whitespace as required. This operation is typically bound to the tab key, but regardless to the actual keypress to which it is bound is *only* called in response to a user keypress. @param stc: the stc of interest @param linenum: the line number, or None to use the current line @param dedent_only: flag to indicate that indentation should only be removed, not added @return: the new cursor position, in case the cursor has moved as a result of the indention. """ if linenum is None: linenum = stc.GetCurrentLine() if linenum == 0: # first line is always indented correctly return stc.GetCurrentPos() linestart = stc.PositionFromLine(linenum) # actual indention of current line indcol = stc.GetLineIndentation(linenum) # columns pos = stc.GetCurrentPos() indpos = stc.GetLineIndentPosition(linenum) # absolute character position col = stc.GetColumn(pos) self.dprint("linestart=%d indpos=%d pos=%d col=%d indcol=%d" % (linestart, indpos, pos, col, indcol)) newind = self.findIndent(stc, linenum) if newind is None: return pos if dedent_only and newind > indcol: return pos # the target to be replaced is the leading indention of the # current line indstr = stc.GetIndentString(newind) self.dprint("linenum=%d indstr='%s'" % (linenum, indstr)) stc.SetTargetStart(linestart) stc.SetTargetEnd(indpos) stc.ReplaceTarget(indstr) # recalculate cursor position, because it may have moved if it # was within the target after = stc.GetLineIndentPosition(linenum) self.dprint("after: indent=%d cursor=%d" % (after, stc.GetCurrentPos())) if pos < linestart: return pos newpos = pos - indpos + after if newpos < linestart: # we were in the indent region, but the region was made smaller return after elif pos < indpos: # in the indent region return after return newpos
def processReturn(self, stc): """Add a newline and indent to the proper tab level. Indent to the level of the line above. This uses the findIndent method to determine the proper indentation of the line about to be added, inserts the appropriate end-of-line characters, and indents the new line to that indentation level. @param stc: stc of interest """ linesep = stc.getLinesep() stc.BeginUndoAction() # reindent current line (if necessary), then process the return #pos = stc.reindentLine() linenum = stc.GetCurrentLine() pos = stc.GetCurrentPos() col = stc.GetColumn(pos) #linestart = stc.PositionFromLine(linenum) #line = stc.GetLine(linenum)[:pos-linestart] #get info about the current line's indentation ind = stc.GetLineIndentation(linenum) self.dprint("format = %s col=%d ind = %d" % (repr(linesep), col, ind)) stc.SetTargetStart(pos) stc.SetTargetEnd(pos) if col <= ind: newline = linesep + self.getNewLineIndentString(stc, col, ind) elif not pos: newline = linesep else: stc.ReplaceTarget(linesep) pos += len(linesep) end = min(pos + 1, stc.GetTextLength()) # Scintilla always returns a fold level of zero on the last line, # so when trying to indent the last line, must add a newline # character. if pos == end and self.folding_last_line_bug: stc.AddText("\n") end = stc.GetTextLength() # When we insert a new line, the colorization isn't always # immediately updated, so we have to force that here before # calling findIndent to guarantee that the new line will have the # correct fold property set. stc.Colourise(stc.PositionFromLine(linenum), end) stc.SetTargetStart(pos) stc.SetTargetEnd(pos) ind = self.findIndent(stc, linenum + 1) self.dprint("pos=%d ind=%d fold=%d" % (pos, ind, (stc.GetFoldLevel(linenum+1)&wx.stc.STC_FOLDLEVELNUMBERMASK) - wx.stc.STC_FOLDLEVELBASE)) newline = stc.GetIndentString(ind) stc.ReplaceTarget(newline) stc.GotoPos(pos + len(newline)) stc.EndUndoAction()
def findIndent(self, stc, linenum): """Reindent the specified line to the correct level. Given a line, use some regex matching to determine the correct indent level. """ # The text begins at indpos; check some special cases to see if there # should be a dedent before = stc.GetLineIndentPosition(linenum) end = stc.GetLineEndPosition(linenum) cmd = stc.GetTextRange(before, end) dprint(cmd) # skip blank lines if len(cmd) > 0: # don't reindent comments if cmd[0] == "#": return stc.GetLineIndentation(linenum) match = self.commandre.match(cmd) if match: # it's a command, so it shouldn't be indented. self.dprint("It's a command! indent=0") return 0 # OK, not a command, so it depends on context. while linenum > 0: linenum -= 1 start = stc.PositionFromLine(linenum) style = stc.GetStyleAt(start) self.dprint("line=%d start=%d style=%d" % (linenum, start, style)) if style == 5 or style == 3: # OK, it's a possible command. end = stc.GetLineEndPosition(linenum) cmd = stc.GetTextRange(start, end) match = self.commandre.match(cmd) if match: # Yep, a command. This line should be tabbed self.dprint("tabbed!") return 8 return 0 elif style == 3: return 0 # If all else fails, just use the same amount of indentation as before return stc.GetLineIndentation(linenum)
def findIndent(self, stc, linenum=None): """Reindent the specified line to the correct level. Given a line, use Scintilla's built-in folding to determine the indention level of the current line. """ if linenum is None: linenum = stc.GetCurrentLine() linestart = stc.PositionFromLine(linenum) # actual indention of current line ind = stc.GetLineIndentation(linenum) # columns pos = stc.GetLineIndentPosition(linenum) # absolute character position # folding says this should be the current indention fold = stc.GetFoldLevel(linenum)&wx.stc.STC_FOLDLEVELNUMBERMASK - wx.stc.STC_FOLDLEVELBASE self.dprint("ind = %s (char num=%d), fold = %s" % (ind, pos, fold)) return fold * stc.GetIndent()
def AutoIndenter(stc, pos, ichar): """Auto indent xtext code. uses \n the text buffer will handle any eol character formatting. This code is based on python AutoIndenter. @param stc: EditraStyledTextCtrl @param pos: current carat position @param ichar: Indentation character @return: string """ rtxt = u'' line = stc.GetCurrentLine() spos = stc.PositionFromLine(line) text = stc.GetTextRange(spos, pos) inspace = text.isspace() # Cursor is in the indent area somewhere or in the column 0. if inspace or not len(text): return u"\n" + text text = text.strip() if text.endswith(";"): return u"\n" indent = stc.GetLineIndentation(line) if ichar == u"\t": tabw = stc.GetTabWidth() else: tabw = stc.GetIndent() i_space = indent / tabw end_spaces = ((indent - (tabw * i_space)) * u" ") if text.endswith(u":"): i_space += 1 rval = u"\n" + ichar * i_space + end_spaces return rval
def findIndent(self, stc, linenum): """Determine the correct indentation for the line. This routine uses regular expressions to determine the indentation level of the line. @param linenum: current line number @param return: the number of columns to indent, or None to leave as-is """ if linenum < 1: return None #// find the first line with content that is not starting with comment text, #// and take the position from that ln = linenum pos = 0 above = '' while ln > 0: ln -= 1 fc = stc.GetLineIndentPosition(ln) lc = stc.GetLineEndPosition(ln) self.dprint("ln=%d fc=%d lc=%d line=-->%s<--" % (ln, fc, lc, stc.GetLine(ln))) # skip blank lines if fc < lc: s = stc.GetStyleAt(fc) if stc.isStyleComment(s): continue pos = stc.GetLineIndentation(ln) above = stc.GetTextRange(fc, lc) break # // try 'couples' for an opening on the above line first. since we only adjust by 1 unit, # // we only need 1 match. adjustment = 0 if '(' in self.couples and self.coupleBalance(stc, ln, '(', ')') > 0: adjustment += 1 elif '[' in self.couples and self.coupleBalance(stc, ln, '[', ']') > 0: adjustment += 1 elif '{' in self.couples and self.coupleBalance(stc, ln, '{', '}') > 0: adjustment += 1 # // Try 'couples' for a closing on this line first. since we only adjust by 1 unit, # // we only need 1 match. For unindenting, we look for a closing character # // *at the beginning of the line* # // NOTE Assume that a closing brace with the configured attribute on the start # // of the line is closing. # // When acting on processChar, the character isn't highlighted. So I could # // either not check, assuming that the first char *is* meant to close, or do a # // match test if the attrib is 0. How ever, doing that is # // a potentially huge job, if the match is several hundred lines away. # // Currently, the check is done. # { # KateTextLine::Ptr tl = doc->plainKateTextLine( line.line() ); # int i = tl->firstChar(); # if ( i > -1 ) # { # QChar ch = tl->getChar( i ); # uchar at = tl->attribute( i ); # kdDebug(13030)<<"attrib is "<<at<<endl; # if ( d->couples & Parens && ch == ')' # && ( at == d->coupleAttrib # || (! at && hasRelevantOpening( KateDocCursor( line.line(), i, doc ) )) # ) # ) # adjustment--; # else if ( d->couples & Braces && ch == '}' # && ( at == d->coupleAttrib # || (! at && hasRelevantOpening( KateDocCursor( line.line(), i, doc ) )) # ) # ) # adjustment--; # else if ( d->couples & Brackets && ch == ']' # && ( at == d->coupleAttrib # || (! at && hasRelevantOpening( KateDocCursor( line.line(), i, doc ) )) # ) # ) # adjustment--; # } # } # Haven't figured out what that was for, so ignoring for now. # // check if we should indent, unless the line starts with comment text, # // or the match is in comment text # Here we look at the line above the current line if self.reIndentAfter: match = self.reIndentAfter.search(above) self.dprint(above) if match: self.dprint("reIndentAfter: found %s at %d" % (match.group(0), match.start(0))) adjustment += 1 # // else, check if this line should indent unless ... # ktl = doc->plainKateTextLine( line.line() ); # if ( ! d->reIndent.isEmpty() # && (matchpos = d->reIndent.search( doc->textLine( line.line() ) )) > -1 # && ! ISCOMMENT ) # adjustment++; fc = stc.GetLineIndentPosition(linenum) lc = stc.GetLineEndPosition(linenum) s = stc.GetStyleAt(fc) if self.reIndent and lc > fc and not stc.isStyleComment(s): text = stc.GetTextRange(fc, lc) match = self.reIndent.search(text) self.dprint(text) if match: self.dprint("reIndent: found %s at %d" % (match.group(0), match.start(0))) adjustment += 1 # // else, check if the current line indicates if we should remove indentation unless ... if self.reUnindent and lc > fc and not stc.isStyleComment(s): text = stc.GetTextRange(fc, lc) match = self.reUnindent.search(text) if match: self.dprint("reUnndent: found %s at %d" % (match.group(0), match.start(0))) adjustment -= 1 # Find the actual number of spaces to indent if adjustment > 0: pos += stc.GetIndent() elif adjustment < 0: pos -= stc.GetIndent() if pos < 0: pos = 0 return pos
def findIndent(self, stc, linenum=None): """Reindent the specified line to the correct level. Given a line, use Scintilla's built-in folding to determine the indention level of the current line. """ if linenum is None: linenum = stc.GetCurrentLine() linestart = stc.PositionFromLine(linenum) # actual indention of current line col = stc.GetLineIndentation(linenum) # columns pos = stc.GetLineIndentPosition(linenum) # absolute character position # folding says this should be the current indention fold = (stc.GetFoldLevel(linenum)&wx.stc.STC_FOLDLEVELNUMBERMASK) - wx.stc.STC_FOLDLEVELBASE c = stc.GetCharAt(pos) s = stc.GetStyleAt(pos) indent = stc.GetIndent() partial = 0 self.dprint("col=%d (pos=%d), fold=%d char=%s" % (col, pos, fold, repr(chr(c)))) if c == ord('}'): # Scintilla doesn't automatically dedent the closing brace, so we # force that here. fold -= 1 elif c == ord('{'): # Opening brace on a line by itself always stays at the fold level pass elif c == ord('#') and s == 9: # Force preprocessor directives to start at column zero fold = 0 else: start = self.getFoldSectionStart(stc, linenum) opener = self.getBraceOpener(stc, start-1) self.dprint(opener) # First, try to match on the current line to see if we know enough # about it to figure its indent level matched = False line = self.getCodeChars(stc, linenum) if opener == "switch": # case statements are partially dedented relative to the # scintilla level if self.reCase.match(line): matched = True partial = - (indent / 2) elif opener == "class": # public/private/protected statements are partially dedented # relative to the scintilla level if self.reClassAttrScope.match(line): matched = True partial = - (indent / 2) # labels are matched after case statements to prevent the # 'default:' label from getting confused with a regular label if not matched and self.reLabel.match(line): fold = 0 matched = True # If we can't determine the indent level when only looking at # the current line, start backing up to find the first non blank # statement above the line. We then look to see if we should # indent relative to that statement (e.g. if the statement is a # continuation) or relative to the fold level supplied by scintilla if not matched: for ln in xrange(linenum - 1, start - 1, -1): line = self.getCodeChars(stc, ln) self.dprint(line) if not line.strip() or self.reLabel.match(line): continue if opener == "switch": if self.reCase.match(line): # a case statement will be interpreted as a continuation break if self.reIndentAfter.match(line): self.dprint("continuation") fold += 1 else: self.dprint("terminated statement") break return (fold * indent) + partial
def findIndent(self, stc, linenum): """No-op that returns the current indent level.""" return stc.GetLineIndentation(linenum)
def AutoIndenter(stc, current_pos, indent_char): """ Determines the indentation rule. 0) If the line is empty except for whitespace, indent to the current column. 1) If all strings and parenthesis are closed, then indent based on how this line has been styled. 2) If we're in a string, indent to one more than the position at which the string started. 3) If we've opened more parenthesis then we closed on the current line, indent by 1. 4) If we've closed more parenthesis than we opened on the current line, dedent by 1. 5) Otherwise, keep the current indentation. """ line = stc.LineFromPosition(current_pos) while line >= 0: line_state = stc.GetLineState(line) if line_state: break line -= 1 start = stc.PositionFromLine(line) text = stc.GetTextRangeUTF8(start, current_pos) pos = -1 len_text = len(text) # States for the indenting state machine. ISTATE_INDENT = 0 # Line indentation. ISTATE_CODE = 1 # Normal code. ISTATE_COMMENT = 2 # Comment. ISTATE_COMMENT_LINE = 3 # Full-line comment. ISTATE_STRING = 4 # In a string. ISTATE_EOL = 5 # At the end of the line. state = ISTATE_EOL # The indentation of the last non-blank, non-comment line. prior_indent = 0 # The number of parens that are open in the statement. open_parens = 0 # The net change in parens on the current line. net_parens = 0 # Where the current line started. line_start = 0 # The quote characters used to close the current string. quote_chars = None # The indentation to use if we're in a quote. quote_indent = 0 while pos + 1 < len_text: pos += 1 c = text[pos] if state == ISTATE_EOL: line_start = pos net_parens = 0 state = ISTATE_INDENT if state == ISTATE_INDENT: if c == " ": continue elif c == "\n": state = ISTATE_EOL continue elif c == "#": state = ISTATE_COMMENT_LINE continue state = ISTATE_CODE prior_indent = pos - line_start # Intentionally fall through. if state == ISTATE_COMMENT or state == ISTATE_COMMENT_LINE: if c == "\n": state = ISTATE_EOL continue continue elif state == ISTATE_CODE: if c == "\n": state = ISTATE_EOL continue if c in "\"'`": start = text[pos:pos + 3] if start == "'''" or start == '"""': quote_chars = start quote_indent = pos - line_start pos += 2 state = ISTATE_STRING continue quote_chars = c quote_indent = 1 + pos - line_start state = ISTATE_STRING continue if c in "([{": net_parens += 1 open_parens += 1 continue if c in ")]}": net_parens -= 1 open_parens -= 1 continue if c == "#": state = ISTATE_COMMENT continue continue elif state == ISTATE_STRING: if c == "\n": line_start = pos + 1 continue if c == "\\": pos += 1 continue if c == quote_chars: state = ISTATE_CODE continue if text[pos:pos + 3] == quote_chars: pos += 2 state = ISTATE_CODE continue continue # Compute the indent of the line itself. INDENTWIDTH = profiler.Profile_Get("INDENTWIDTH") line_indent = line_state & INDENT_MASK if state == ISTATE_STRING: indent = quote_indent elif state == ISTATE_COMMENT_LINE: l = stc.GetCurrentLine() indent = stc.GetLineIndentation(l) elif open_parens <= 0: if state == ISTATE_INDENT or state == ISTATE_EOL: l = stc.GetCurrentLine() if stc.GetLineIndentPosition(l) == stc.GetLineEndPosition(l): indent = stc.GetColumn(current_pos) else: indent = line_indent elif line_state & INDENTS: indent = line_indent + INDENTWIDTH else: indent = line_indent elif net_parens > 0: indent = prior_indent + INDENTWIDTH elif net_parens < 0: indent = max(line_indent + INDENTWIDTH, prior_indent - INDENTWIDTH) else: indent = prior_indent # Implement the indent. eolch = stc.GetEOLChar() stc.AddText(eolch) l = stc.GetCurrentLine() stc.SetLineIndentation(l, indent) stc.GotoPos(stc.GetLineIndentPosition(l))
def findIndent(self, stc, linenum): """Find proper indentation of the current Python source line. This uses IDLE's python parsing routine to find the indent level of the specified line based on the python code that comes before it. @param linenum: line number @return: integer indicating number of columns to indent. """ indentwidth = stc.GetIndent() tabwidth = stc.GetTabWidth() indent = stc.GetLineIndentation(linenum) y = PyParse.Parser(indentwidth, tabwidth) # FIXME: context line hack straight from IDLE for context in [50, 500, 5000000]: firstline = linenum - context if firstline < 0: firstline = 0 start = stc.PositionFromLine(firstline) # end is the position before the first character of the line, so # we're looking at the code up to the start of the current line. end = stc.PositionFromLine(linenum) rawtext = stc.GetTextRange(start, end) # Handle two issues with this loop. 1: Remove comments that start # at column zero so they don't affect the indenting. 2: PyParse # is hardcoded for "\n" style newlines only, so by splitting the # lines here we can change whatever the newlines are into "\n" # characters. lines = [] for line in rawtext.splitlines(): if len(line) > 0: if line[0] != '#': lines.append(line) lines.append('') # include a blank line at the end rawtext = "\n".join(lines) y.set_str(rawtext) bod = y.find_good_parse_start(build_char_in_string_func( stc, start)) if bod is not None or firstline == 0: break #dprint(rawtext) self.dprint("bod = %s" % bod) y.set_lo(bod or 0) c = y.get_continuation_type() self.dprint("continuation type: %s" % c) extra_data = None if c != PyParse.C_NONE: # The current stmt hasn't ended yet. if c == PyParse.C_STRING_FIRST_LINE: s = stc.GetStyleAt(end) if s == 6 or s == 7: # Inside a triple quoted string (TQS) self.dprint("C_STRING_FIRST_LINE in TQS") indentstr = y.get_base_indent_string() indent = len(indentstr.expandtabs(tabwidth)) else: # after the first line of a string; do not indent at all self.dprint("C_STRING_FIRST_LINE") pass elif c == PyParse.C_STRING_NEXT_LINES: # inside a string which started before this line; # just mimic the current indent #text.insert("insert", indent) s = stc.GetStyleAt(end) if s == 6 or s == 7: # Inside a triple quoted string (TQS) self.dprint("C_STRING_NEXT_LINES in TQS") indentstr = y.get_base_indent_string() indent = len(indentstr.expandtabs(tabwidth)) else: # FIXME: Does this ever happen without being in a TQS??? self.dprint("C_STRING_NEXT_LINES") elif c == PyParse.C_BRACKET: # line up with the first (if any) element of the # last open bracket structure; else indent one # level beyond the indent of the line with the # last open bracket self.dprint("C_BRACKET") #self.reindent_to(y.compute_bracket_indent()) indent = y.compute_bracket_indent() elif c == PyParse.C_BACKSLASH: # if more than one line in this stmt already, just # mimic the current indent; else if initial line # has a start on an assignment stmt, indent to # beyond leftmost =; else to beyond first chunk of # non-whitespace on initial line if y.get_num_lines_in_stmt() > 1: pass else: indent = y.compute_backslash_indent() else: assert 0, "bogus continuation type %r" % (c, ) else: # This line starts a brand new stmt; indent relative to # indentation of initial line of closest preceding # interesting stmt. indentstr = y.get_base_indent_string() indent = len(indentstr.expandtabs(tabwidth)) if y.is_block_opener(): self.dprint("block opener") indent += indentwidth extra_data = "block opener" elif indent and y.is_block_closer(): self.dprint("block dedent") indent = ((indent - 1) // indentwidth) * indentwidth extra_data = "block dedent" self.dprint("indent = %d" % indent) # check some special cases to see if they line should be dedented by # a level before = stc.GetLineIndentPosition(linenum) style = stc.GetStyleAt(before) end = stc.GetLineEndPosition(linenum) cmd = stc.GetTextRange(before, end) #dprint("checking %s" % cmd) if linenum > 0 and style == wx.stc.STC_P_WORD and ( cmd.startswith('else') or cmd.startswith('elif') or cmd.startswith('except') or cmd.startswith('finally')): self.dprint("Found a dedent: %s" % cmd) if extra_data != "block dedent": # If we aren't right after a return or something that already # caused a dedent, dedent it indent -= indentwidth return indent