Beispiel #1
0
def StyleText(stc, start, end):
    """Style the text
    @param stc: Styled text control instance
    @param start: Start position
    @param end: end position

    """
    cpos = 0
    stc.StartStyling(cpos, 0x1f)
    lexer = get_lexer_by_name("html+django")
    doctxt = stc.GetTextRange(0, end)
    wineol = stc.GetEOLChar() == "\r\n"
    for token, txt in lexer.get_tokens(doctxt):
        #        print token, txt
        style = TOKEN_MAP.get(token, STC_DJANGO_DEFAULT)
        if style == STC_DJANGO_PREPROCESSOR and txt.startswith(u'#'):
            style = STC_DJANGO_COMMENT
#        elif style == STC_DJANGO_STRING and txt[-1] not in '"\'':
#            style = STC_DJANGO_STRINGEOL

        tlen = len(txt)
        if wineol and "\n" in txt:
            tlen += txt.count("\n")

        if tlen:
            stc.SetStyling(tlen, style)
        cpos += tlen
        stc.StartStyling(cpos, 0x1f)
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 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 #4
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 #5
0
def StyleText(stc, start, end):
    """Style the text
    @param stc: Styled text control instance
    @param start: Start position
    @param end: end position
    @todo: performance improvements
    @todo: style errors caused by unicode characters (related to internal utf8)

    """
    cpos = 0
    stc.StartStyling(cpos, 0x1f)
    lexer = get_lexer_by_name("s")
    is_wineol = stc.GetEOLMode() == wx.stc.STC_EOL_CRLF
    for token, txt in lexer.get_tokens(stc.GetTextRange(0, end)):
        style = TOKEN_MAP.get(token, STC_S_DEFAULT)

        tlen = len(txt)

        # Account for \r\n end of line characters
        if is_wineol and "\n" in txt:
            tlen += txt.count("\n")

        if tlen:
            stc.SetStyling(tlen, style)
        cpos += tlen
        stc.StartStyling(cpos, 0x1f)
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' ')

    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 #7
0
    def _GenRtf(self):
        """Generates the RTF equivalent of the displayed text in the current
        stc document window.
        @precondition: self._stc must have been set by a call to Generate
        @return: generated rtf marked up text

        """
        # Buffer hasn't been set
        if self._stc is None:
            return u''

        # Optimizations
        stc = self._stc
        def_fore = stc.GetDefaultForeColour(as_hex=True)
        self._colortbl.AddColor(def_fore)
        def_back = stc.GetDefaultBackColour(as_hex=True)
        self._colortbl.AddColor(def_back)
        last_pos = stc.GetLineEndPosition(stc.GetLineCount())
        parse_pos = 0
        last_id = None
        last_fore = None
        last_back = None
        start = end = 0
        tmp_txt = list()
        font_tmp = "\\f0"
        fore_tmp = "\\cf%d"
        back_tmp = "\\cb%d"
        AddColor = self._colortbl.AddColor
        GetColorIndex = self._colortbl.GetColorIndex
        GetStyleAt = stc.GetStyleAt

        # Parse all characters/style bytes in document
        for parse_pos in xrange(last_pos + 1):
            sty_id = GetStyleAt(parse_pos)
            end = parse_pos

            # If style has changed build the previous section
            if sty_id != last_id:
                tag = stc.FindTagById(last_id)
                s_item = stc.GetItemByName(tag)
                AddColor(s_item.GetFore())
                AddColor(s_item.GetBack())
                tplate = font_tmp
                fid = GetColorIndex(s_item.GetFore())
                if fid != last_fore:
                    last_fore = fid
                    tplate = tplate + (fore_tmp % fid)
                bid = GetColorIndex(s_item.GetBack())
                if bid != last_back:
                    last_back = bid
                    tplate = tplate + (back_tmp % bid)
                tmp_txt.append(tplate + " " + \
                               self.TransformText(stc.GetTextRange(start, end)))
                start = end
            last_id = sty_id

        head = "{\\rtf1\\ansi\\deff0{\\fonttbl{\\f0 %s;}}" % \
                stc.GetDefaultFont().GetFaceName()
        return u"%s%s%s}" % (head, self._colortbl, "".join(tmp_txt))
Beispiel #8
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 #9
0
 def OnReplace(self, event):
     stc = self.docMgr.GetCurrDoc()
     d = drFindReplaceDialog(self, -1, "Replace", stc, 1)
     d.SetOptions(EpyGlob.ReplaceOptions)
     if stc.GetSelectionStart() < stc.GetSelectionEnd():
         d.SetFindString(
             stc.GetTextRange(stc.GetSelectionStart(),
                              stc.GetSelectionEnd()))
     else:
         d.SetFindString(stc.Finder.GetFindText())
     d.Show(True)
Beispiel #10
0
 def iterStyles(self, stc, start, end):
     """Splits the text into ranges based on similar styles.
     
     This method is a generator to provide the means to style the text
     by breaking the text range up into styling groups where each group
     contains the same style.
     
     Should be overridden in subclasses to provide custom styling.
     
     @returns: generator where each item is a tuple containing the start
     position, the number of characters to style, and the style ID number.
     """
     text = stc.GetTextRange(start, end)
     yield start, len(text), 0
Beispiel #11
0
    def OnFind(self, event):
        stc = self.docMgr.GetCurrDoc()
        d = drFindReplaceDialog(self, -1, "Find", stc)

        #d.SetOptions(self.FindOptions)

        if stc.GetSelectionStart() < stc.GetSelectionEnd():
            d.SetFindString(stc.GetSelectedText())
        elif config.prefs.findreplaceundercursor:
            pos = stc.GetCurrentPos()
            d.SetFindString(
                stc.GetTextRange(stc.WordStartPosition(pos, 1),
                                 stc.WordEndPosition(pos, 1)))
        d.Show(True)
Beispiel #12
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 #13
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 #14
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
def StyleText(stc, start, end):
    """Style the text
    @param stc: Styled text control instance
    @param start: Start position
    @param end: end position

    """
    for index, token, txt in lexer.get_tokens_unprocessed(
            stc.GetTextRange(0, end)):
        #        print index, token, txt
        style = TOKEN_MAP.get(token, STC_NONMEM_DEFAULT)

        #        print "Text=%s, len=%s" % (txt, len(txt))
        stc.StartStyling(index, 0x1f)
        tlen = len(txt)
        if tlen:
            stc.SetStyling(len(txt), style)
Beispiel #16
0
    def find_errors(self, stc, dictionaries, start=None, end=None):
        ## t = time.time()
        if start == None:
            start = 0
        if end == None:
            end = stc.GetTextLength()

        nf = {}
        badwords = []

        def check():
            word = to_check[start:_start]
            if word:
                word = word.lower()
                if word in nf:
                    badwords.append((start, _start))
                    return
                for j in dictionaries:
                    if word in j:
                        break
                else:
                    badwords.append((start, _start))
                    nf[word] = None

        count = 1
        to_check = stc.GetTextRange(start, end)
        for match in non_word_re.finditer(to_check):
            count += 1
            _start = match.start()
            check()
            start = match.end()
        _start = end
        check()
        ## if nf:
        ## nf = nf.keys()
        ## nf.sort()
        ## print '\n'.join(nf)

        ## print "checked ~%i in %.1f"%(count, time.time()-t)
        return badwords
Beispiel #17
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 #18
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 #19
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 #20
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 #21
0
    def GenerateBody(self):
        """Generates the body of the html from the stc's content. To do
        this it does a character by character parse of the stc to determine
        style regions and generate css and and styled spans of html in order
        to generate an 'exact' html reqresentation of the stc's window.
        @return: the body section of the html generated from the text control

        """
        html = list()
        parse_pos = 0
        style_start = 0
        style_end = 0
        last_pos = self.stc.GetLineEndPosition(self.stc.GetLineCount()) + 1

        # Get Document start point info
        last_id = self.stc.GetStyleAt(parse_pos)
        tag = self.stc.FindTagById(last_id)
        if tag != wx.EmptyString:
            s_item = StyleItem()
            s_item.SetAttrFromStr(self.stc.GetStyleByName(tag))
            self.css[tag] = CssItem(tag.split('_')[0], s_item)

        # Optimizations
        stc = self.stc
        GetStyleAt = stc.GetStyleAt

        # Build Html
        while parse_pos < last_pos:
            parse_pos += 1
            curr_id = GetStyleAt(parse_pos)
            style_end = parse_pos
            # If style region has changed close section
            if curr_id == 0 and GetStyleAt(parse_pos + 1) == last_id:
                curr_id = last_id

            if curr_id != last_id or parse_pos == last_pos:
                tmp = stc.GetTextRange(style_start, style_end)
                tmp = self.TransformText(tmp)
                if tmp.isspace() or tag in ["default_style", "operator_style"]:
                    html.append(tmp)
                else:
                    tmp2 = "<span class=\"%s\">%s</span>"
                    html.append(tmp2 % (tag.split('_')[0], tmp))

                last_id = curr_id
                style_start = style_end
                tag = stc.FindTagById(last_id)
                if tag not in self.css:
                    s_item = StyleItem()
                    s_item.SetAttrFromStr(stc.GetStyleByName(tag))
                    self.css[tag] = CssItem(tag.split('_')[0], s_item)

        # Case for unstyled documents
        if len(html) == 0:
            s_item = StyleItem()
            s_item.SetAttrFromStr(stc.GetStyleByName('default_style'))
            self.css['default_style'] = CssItem('default', s_item)
            html.append(self.TransformText(stc.GetText()))
        else:
            self.OptimizeCss()

        return "<body class=\"default\">\n<pre>\n%s\n</pre>\n</body>" % \
                                                                   "".join(html)
Beispiel #22
0
    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
Beispiel #23
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