Beispiel #1
0
 def __delitem__(self, key):
     stc = self.__STC
     if type(key) is IntType:
         stc.SetSelection(stc.PositionFromLine(key),
                          stc.GetLineEndPosition(key) + 1)
         stc.ReplaceSelection('')
     elif type(key) is SliceType:
         stc.SetSelection(stc.PositionFromLine(key.start),
                          stc.GetLineEndPosition(key.stop) + 1)
         stc.ReplaceSelection('')
     else:
         raise TypeError, _('%s not supported') % ` type(key) `
Beispiel #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
Beispiel #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
Beispiel #4
0
    def StyleText(self, event):
        """Handle the EVT_STC_STYLENEEDED event"""

        stc = event.GetEventObject()
        # Last correctly styled character
        last_styled_pos = stc.GetEndStyled()
        # Get styling range for this call
        line = stc.LineFromPosition(last_styled_pos)
        start_pos = stc.PositionFromLine(line)
        end_pos = event.GetPosition()

        # Walk the line and find all the symbols to style
        # Note: little inefficient doing one char at a time
        #       but just to illustrate the process.
        while start_pos < end_pos:
            stc.StartStyling(start_pos, 0x1f)
            char = stc.GetCharAt(start_pos)
            if char in self.ortho_symbols:
                # Set Symbol Keyword style
                style = OrthoEventsLexer.STC_STYLE_ORTHO_KW
            else:
                # Set Default style
                style = OrthoEventsLexer.STC_STYLE_ORTHO_DEFAULT
            # Set the styling byte information for 1 char from
            # current styling position (start_pos) with the
            # given style.
            stc.SetStyling(1, style)
            start_pos += 1
Beispiel #5
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
Beispiel #6
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
Beispiel #7
0
 def __setitem__(self, key, value):
     stc = self.__STC
     if type(key) is IntType:
         assert type(value) is StringType
         if key < len(self):
             stc.SetSelection(stc.PositionFromLine(key),
                              stc.GetLineEndPosition(key))
             stc.ReplaceSelection(value)
         else:
             raise IndexError
     elif type(key) is SliceType:
         lines = eols[stc.GetEOLMode()].join(value)
         stc.SetSelection(stc.PositionFromLine(key.start),
                          stc.GetLineEndPosition(key.stop))
         stc.ReplaceSelection(lines)
     else:
         raise TypeError, _('%s not supported') % ` type(key) `
Beispiel #8
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()
Beispiel #9
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
    def OnPrintPage(self, page):
        stc = self.stc
        self.stcLineHeight = stc.TextHeight(0)

        # calculate sizes including margin and scale
        dc = self.GetDC()
        dw, dh = dc.GetSizeTuple()

        mw = self.margin * dw
        mh = self.margin * dh
        textAreaHeight = dh - mh * 2
        textAreaWidth = dw - mw * 2

        scale = float(textAreaHeight) / (self.stcLineHeight *
                                         self.linesPerPage)
        dc.SetUserScale(scale, scale)

        # render page titles and numbers
        f = dc.GetFont()
        f.SetFamily(wx.ROMAN)
        f.SetFaceName('Times New Roman')
        f.SetPointSize(f.GetPointSize() + 3)
        dc.SetFont(f)

        if self.filename:
            tlw, tlh = dc.GetTextExtent(self.filename)
            dc.DrawText(self.filename, int(dw / scale / 2 - tlw / 2),
                        int(mh / scale - tlh * 3))

        if self.doPageNums:
            pageLabel = _('Page: %d') % page
            plw, plh = dc.GetTextExtent(pageLabel)
            dc.DrawText(pageLabel, int(dw / scale / 2 - plw / 2),
                        int((textAreaHeight + mh) / scale + plh * 2))

        # render stc into dc
        stcStartPos = stc.PositionFromLine((page - 1) * self.linesPerPage)
        stcEndPos = stc.GetLineEndPosition(page * self.linesPerPage - 1)

        maxWidth = 32000
        stc.SetPrintColourMode(self.colourMode)
        ep = stc.FormatRange(
            1, stcStartPos, stcEndPos, dc, dc,
            wx.Rect(int(mw / scale), int(mh / scale), maxWidth,
                    int(textAreaHeight / scale)),
            wx.Rect(0, (page - 1) * self.linesPerPage * self.stcLineHeight,
                    maxWidth, self.stcLineHeight * self.linesPerPage))

        # warn when less characters than expected is rendered by the stc when
        # printing
        if not self.IsPreview():
            if ep < stcEndPos:
                print _('warning: on page %s: not enough chars rendered, diff:'
                        ) % (page, stcEndPos - ep)

        return True
Beispiel #11
0
 def reindentComment(self, stc, ln, dedent_only):
     cursor = stc.GetCurrentPos()
     fc = stc.PositionFromLine(ln)
     lc = stc.GetLineEndPosition(ln)
     text = stc.GetTextRange(fc, lc)
     count = len(text)
     pos = 0
     while pos < count and text[pos] == ' ':
         pos += 1
     stc.SetTargetStart(fc)
     stc.SetTargetEnd(lc)
     stc.ReplaceTarget(text[pos:count])
     cursor -= pos
     return cursor
Beispiel #12
0
 def reindentSourceLine(self, stc, ln, dedent_only):
     cursor = stc.GetCurrentPos()
     fc = stc.PositionFromLine(ln)
     lc = stc.GetLineEndPosition(ln)
     text = stc.GetTextRange(fc, lc)
     #dprint("1234567")
     #dprint(text)
     #col = stc.GetColumn(cursor)
     #dprint(" "*col + "_")
     if len(text) > 5:
         numbers = text[0:5]
         continuation = text[5]
         remainder = text[6:]
     else:
         numbers = text + " "*(5 - len(text))
         continuation = " "
         remainder = ""
     
     newind = self.findIndent(stc, ln) - 6
     if newind < 0:
         newind = 0
     #dprint("newind: %d" % newind)
     
     col = stc.GetColumn(cursor)
     if col < 5:
         cursor = fc + 6 + newind
     elif col > 5:
         before = len(remainder)
         remainder = remainder.lstrip()
         leading_blanks = before - len(remainder)
         #dprint("leading blanks: %d" % leading_blanks)
         if leading_blanks > newind:
             cursor -= leading_blanks - newind
         elif col - 6 <= newind:
             cursor = fc + 6 + newind
     remainder = remainder.lstrip()
     remainder = " "*newind + remainder
     
     numbers = numbers.strip()
     line = "%-5s%s%s" % (numbers, continuation, remainder)
     #dprint("1234567")
     #dprint(line)
     #col = stc.GetColumn(cursor)
     #dprint(" "*col + "_")
     stc.SetTargetStart(fc)
     stc.SetTargetEnd(lc)
     stc.ReplaceTarget(line)
     return cursor
Beispiel #13
0
 def getPreviousText(self, stc, linenum):
     """Find the text above the line with the same fold level.
     
     """
     fold = self.getFold(stc, linenum)
     ln = linenum - 1
     fc = lc = stc.GetLineEndPosition(ln)
     above = ''
     while ln > 0:
         f = self.getFold(stc, ln)
         if f != fold:
             above = stc.GetTextRange(fc, lc)
             break
         fc = stc.PositionFromLine(ln)
         ln -= 1
     return above
Beispiel #14
0
    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)
Beispiel #15
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()
Beispiel #16
0
    def getCodeChars(self, stc, ln, lc=-1):
        """Get a version of the given line with all non code chars blanked out.
        
        This function blanks out all non-code characters (comments, strings,
        etc) from the line and returns a copy of the interesting stuff.
        
        @param stc: stc of interest
        @param ln: line number
        @param lc: optional integer specifying the last position on the
        line to consider
        """
        fc = stc.PositionFromLine(ln)
        if lc < 0:
            lc = stc.GetLineEndPosition(ln)
        if lc < fc:
            # FIXME: fail hard during development
            raise IndexError("bad line specification for line %d: fc=%d lc=%d" % (ln, fc, lc))
        
        mask = (2 ** stc.GetStyleBits()) - 1
        
        out = []

        line = stc.GetStyledText(fc, lc)
        self.dprint(repr(line))
        i = len(line)
        
        # replace all uninteresting chars with blanks
        skip = self.getNonCodeStyles(stc)
        while i > 0:
            i -= 1
            s = ord(line[i]) & mask
            i -= 1
            if s in skip:
                c = ' '
            else:
                c = line[i]
            out.append(c)
        
        # Note that we assembled the string in reverse, so flip it around
        out = ''.join(reversed(out))
        return out
Beispiel #17
0
def StyleText(stc, start, end):
    """Style the text
    @param stc: Styled text control instance
    @param start: Start position
    @param end: end position

    """

    # First, figure out the line based on the position.
    line = stc.LineFromPosition(start)

    # Find the start of the line that's been styled before this one.
    while line > 0 and stc.GetLineState(line) == 0:
        line -= 1

    eline = stc.LineFromPosition(end)

    state = stc.GetLineState(line) - 1
    if state < 0:
        state = 0

    for ln in range(line, eline + 1):
        text = stc.GetLine(ln).encode('utf-8')
        len_text = len(text)
        text = text.strip()

        if len(text) == 0:
            state = 0
        else:
            if len(text) > 0:
                ch = text[0]
                ix = issl_table.find(ch)
                if ix >= 0:
                    state = ix + 1

        stc.StartStyling(stc.PositionFromLine(ln), 0xFF)
        stc.SetStyling(len_text, state)

        stc.SetLineState(ln, state + 1)
Beispiel #18
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
Beispiel #19
0
 def electricChar(self, stc, uchar):
     i = ord(uchar)
     if i >= ord('0') and i <= ord('9'):
         pos = stc.GetCurrentPos()
         s = stc.GetStyleAt(pos)
         col = stc.GetColumn(pos)
         if not stc.isStyleComment(s) and col < 5:
             ln = stc.LineFromPosition(pos)
             fc = stc.PositionFromLine(ln)
             lc = stc.GetLineEndPosition(ln)
             text = stc.GetTextRange(fc, lc)
             #dprint("pos=%d col=%d ln=%d fc=%d lc=%d len=%d" % (pos, col, ln, fc, lc, len(text)))
             #dprint("1234567")
             #dprint(text)
             if len(text) > 5:
                 numbers = text[0:5]
                 continuation = text[5]
                 remainder = text[6:]
             else:
                 numbers = text + " "*(5 - len(text))
                 continuation = " "
                 remainder = ""
             numbers = numbers[0:col] + uchar + numbers[col:]
             before = len(numbers)
             numbers = numbers.lstrip()
             if before > len(numbers):
                 col -= before - len(numbers)
             numbers = numbers.strip()
             #dprint("pos=%d col=%d ln=%d fc=%d lc=%d len=%d" % (pos, col, ln, fc, lc, len(text)))
             line = "%-5s%s%s" % (numbers, continuation, remainder)
             #dprint("1234567")
             #dprint(line)
             stc.SetTargetStart(fc)
             stc.SetTargetEnd(lc)
             stc.ReplaceTarget(line)
             stc.GotoPos(fc + col + 1)
             return True
     return False
Beispiel #20
0
    def StyleText(self, evt):
        """Handle the EVT_STC_STYLENEEDED event."""
        stc = evt.GetEventObject()
        last_styled_pos = stc.GetEndStyled()
        line = stc.LineFromPosition(last_styled_pos)
        start_pos = stc.PositionFromLine(line)
        end_pos = evt.GetPosition()

        while start_pos < end_pos:
            stc.StartStyling(start_pos, 0x1f)
            curchar = chr(stc.GetCharAt(start_pos))
            if curchar in self.alpha:
                start = stc.WordStartPosition(start_pos, True)
                end = start + 1
                while chr(stc.GetCharAt(end)) != " " and end < stc.GetLength():
                    end += 1
                word = stc.GetTextRange(start, end)
                if word in self.keywords:
                    style = self.STC_EXPR_KEYWORD
                    stc.SetStyling(len(word), style)
                elif word in self.keywords2:
                    style = self.STC_EXPR_KEYWORD2
                    stc.SetStyling(len(word), style)
                else:
                    style = self.STC_EXPR_DEFAULT
                    stc.SetStyling(len(word), style)
                start_pos += len(word)
            elif curchar == ";":
                eol = stc.GetLineEndPosition(stc.LineFromPosition(start_pos))
                style = self.STC_EXPR_COMMENT
                stc.SetStyling(eol - start_pos, style)
                start_pos = eol
            else:
                style = self.STC_EXPR_DEFAULT
                stc.SetStyling(1, style)
                start_pos += 1
Beispiel #21
0
    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
Beispiel #22
0
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
Beispiel #23
0
    def findIndent(self, stc, linenum):
        ln = linenum
        pos = 0

        fc = stc.PositionFromLine(ln)
        s = stc.GetStyleAt(fc)
        if stc.isStyleComment(s):
            # comment lines aren't indented at all in F77
            return pos

        # find the first line with content that is not starting with comment
        # text, and take the base indent position from that
        above = ''
        while ln > 0:
            ln -= 1
            fc = stc.PositionFromLine(ln)
            s = stc.GetStyleAt(fc)
            if stc.isStyleComment(s):
                continue
            lc = stc.GetLineEndPosition(ln)
            text = stc.GetTextRange(fc, lc)
            if len(text) < 6:
                # skip lines that have only labels
                continue
            if text[5] != ' ':
                # skip continuation lines
                continue
            above = text[6:]
            pos = 6
            while pos < len(text) and text[pos] == ' ':
                pos += 1
            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

        # 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

        # Now that we've found the base indent based on the lines above the
        # current line, check if the current line needs to be modified
        fc = stc.PositionFromLine(linenum)
        lc = stc.GetLineEndPosition(linenum)
        text = stc.GetTextRange(fc, lc)
        if len(text) > 6:
            # Note that no lines that I know of automatically indent
            # themselves, so we only check for lines that should unindent
            # themselves like ELSE, ENDIF, etc.
            text = text[6:]
            if self.reUnindent:
                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
Beispiel #24
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))
Beispiel #25
0
    def on_EVT_STC_STYLENEEDED(self, event):
        stc = event.GetEventObject()
        # Last correctly styled character
        last_styled_pos = stc.GetEndStyled()
        # Get styling range for this call
        lino = stc.LineFromPosition(last_styled_pos)
        start_pos = stc.PositionFromLine(lino)
        end_pos = event.GetPosition()

        text = self.GetTextRange(start_pos, end_pos)
        kw_positions = []
        #find any keywords to color them differently
        i = 0
        for kw in self.keywords:
            try:
                l = len(kw)
                while True:
                    j = text[i:].index(kw)
                    kw_positions.append((start_pos + i + j, l, kw))
                    i += j + l
            except:
                i = 0
        #find any comments in the pbs commands
        #we start looking for '#" at position 5 as text should begin with '#PBS ' anyway
        i = 5
        len_text = len(text)
        while i < len_text:
            if text[i] == '#' and not text[i - 1] == '\n':
                #found a '#' in the middle of a line (at position i), find the end of the line.
                j = i + text[i:].index('\n') + 1
                kw_positions.append((start_pos + i, j - i, text[i:j]))
                i = j
            else:
                i += 1

        kw_positions.sort(key=lambda tpl: tpl[0] + float(tpl[1]) * 0.01)
        #pprint.pprint( kw_positions )
        if not kw_positions:
            self.StartStyling(start_pos, 31)
            self.SetStyling(end_pos - start_pos, PbsLexer.STC_PBS_DEFAULT)
            return
        i = kw_positions[0][0]
        if i != start_pos:
            self.StartStyling(start_pos, 31)
            self.SetStyling(kw_positions[0][0] - start_pos,
                            PbsLexer.STC_PBS_DEFAULT)
        last = len(kw_positions) - 1
        for t, tpl in enumerate(kw_positions):
            self.StartStyling(tpl[0], 31)
            if tpl[2].startswith('#'):
                style = PbsLexer.STC_PBS_COMMENT
            else:
                style = PbsLexer.STC_PBS_KEYWORD
            self.SetStyling(tpl[0], style)
            if t < last:
                i1 = tpl[0] + tpl[1]
                i0n = kw_positions[t + 1][0]
            else:
                i1 = tpl[0] + tpl[1]
                i0n = end_pos
            if i1 < i0n:
                self.StartStyling(i1, 31)
                self.SetStyling(i0n - i1, PbsLexer.STC_PBS_DEFAULT)
Beispiel #26
0
 def adjustStart(self, stc, start):
     col = stc.GetColumn(start)
     if col != 0:
         start = stc.PositionFromLine(stc.LineFromPosition(start))
     return start
Beispiel #27
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