Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
    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
Exemple #6
0
    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()
Exemple #7
0
 def electricChar(self, stc, uchar):
     """Reindent the line and insert a newline when special chars are typed.
     
     Like emacs, a semicolon or curly brace causes the line to be reindented
     and the next line to be indented to the correct column.
     
     @param stc: stc instance
     
     @param uchar: unicode character that was just typed by the user (note
     that it hasn't been inserted into the document yet.)
     
     @return: True if this method handled the character and the text
     was modified; False if the calling event handler should handle the
     character.
     """
     implicit_return = True
     
     if uchar == u';' or uchar == u':' or uchar == '{' or uchar == '}':
         pos = stc.GetCurrentPos()
         s = stc.GetStyleAt(pos)
         if not stc.isStyleComment(s) and not stc.isStyleString(s):
             if uchar == u':':
                 # FIXME: currently only process the : if the current
                 # line is a case statement.  Emacs also indents labels
                 # and namespace operators with a :: by checking if the
                 # last character on the previous line is a : and if so
                 # collapses the current line with the previous line and
                 # reindents the new line
                 linenum = stc.GetCurrentLine()
                 line = self.getCodeChars(stc, linenum, pos) + ":"
                 if not self.reCase.match(line) and not self.reClassAttrScope.match(line):
                     c, prev = self.getLastNonWhitespaceChar(stc, pos)
                     if c == u':':
                         # Found previous ':', so make it a double colon
                         stc.SetSelection(prev + 1, pos)
                         #dprint("selection: %d - %d" % (prev + 1, pos))
                     implicit_return = False
             elif uchar == u';':
                 # Don't process the semicolon if we're in the middle of an
                 # open statement
                 if self.isInsideStatement(stc, pos):
                     return False
             stc.BeginUndoAction()
             start, end = stc.GetSelection()
             if start == end:
                 stc.AddText(uchar)
             else:
                 stc.ReplaceSelection(uchar)
             
             # Always reindent the line, but only process a return if needed
             self.processTab(stc)
             if implicit_return:
                 self.processReturn(stc)
             
             stc.EndUndoAction()
             return True
     return False
Exemple #8
0
 def reindentLine(self, stc, linenum=None, dedent_only=False):
     if linenum is None:
         linenum = stc.GetCurrentLine()
     
     pos = stc.GetCurrentPos()
     s = stc.GetStyleAt(pos)
     if stc.isStyleComment(s):
         return self.reindentComment(stc, linenum, dedent_only)
     else:
         return self.reindentSourceLine(stc, linenum, dedent_only)
Exemple #9
0
def pyparseit():
    '''
    inside triple quotes
    '''
    stc = getSTC(stcclass=PythonMode, lexer="Python")

    tests = splittests(test_cases)
    dprint(len(tests))
    for test in tests:
        prepareSTC(stc, test[0])

        indent = stc.findIndent(stc.GetCurrentLine())
        indentstr = stc.GetIndentString(indent)
        dprint("indent = '%s'" % indentstr)
        print stc.GetText()
        print indentstr + "^"
Exemple #10
0
    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()
Exemple #11
0
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
Exemple #12
0
    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
Exemple #13
0
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))