Пример #1
0
 def electricChar(self, stc, uchar):
     """Reindent the line and insert a newline when special chars are typed.
     
     For python mode, a colon should reindent the line (for example, after
     an else statement, it should dedent it one level)
     """
     if uchar == u':':
         pos = stc.GetCurrentPos()
         s = stc.GetStyleAt(pos)
         if stc.isStyleComment(s) or stc.isStyleString(s):
             # These will report true if the cursor is before the first
             # character of a comment or string, meaning that:
             #
             #    else#blah
             #
             # where the cursor is between the 'e' and the '#' will fail.
             # So, we have to check for this as a special case and allow it
             if pos > 0:
                 s = stc.GetStyleAt(pos-1)
                 allow = not stc.isStyleComment(s) and not stc.isStyleString(s)
             else:
                 allow = False
         else:
             allow = True
         if allow:
             stc.BeginUndoAction()
             start, end = stc.GetSelection()
             if start == end:
                 stc.AddText(uchar)
             else:
                 stc.ReplaceSelection(uchar)
             self.reindentLine(stc, dedent_only=True)
             stc.EndUndoAction()
             return True
     return False
Пример #2
0
 def coupleBalance(self, stc, ln, open, close):
     """Search the line to see if there are unmatched braces
     
     Search the line for unmatched braces given the open and close matching
     pair.  This takes into account the style of the document to make sure
     that the brace isn't in a comment or string.
     
     @param stc: the StyledTextCtrl instance
     @param ln: line number
     @param open: the opening brace character, e.g. "("
     @param close: the complimentary closing brace character, e.g. ")"
     
     @return: brace mismatch count: 0 for matching braces, positive for a
     surplus of opening braces, and negative for a surplus of closing braces
     """
     if ln < 0:
         return 0
     r = 0
     fc = stc.GetLineIndentPosition(ln)
     lc = stc.GetLineEndPosition(ln)
     line = stc.GetStyledText(fc, lc)
     self.dprint(repr(line))
     i = len(line)
     while i > 0:
         i -= 1
         s = line[i]
         i -= 1
         c = line[i]
         if c == open and not (stc.isStyleComment(s) and stc.isStyleString(s)):
             self.dprint("found %s at column %d" % (open, i/2))
             r += 1
         elif c == close and not (stc.isStyleComment(s) and stc.isStyleString(s)):
             self.dprint("found %s at column %d" % (close, i/2))
             r -= 1
     return r
Пример #3
0
 def electricBackspace(self, stc):
     """Delete all whitespace before the cursor unless in a string or comment
     """
     start, end = stc.GetSelection()
     if start != end:
         stc.ReplaceSelection("")
         return
     pos = stc.GetCurrentPos()
     if pos <= 0:
         return
     s = stc.GetStyleAt(pos - 1)
     if stc.isStyleComment(s) or stc.isStyleString(s):
         stc.CmdKeyExecute(wx.stc.STC_CMD_DELETEBACK)
     else:
         self.dprint("backspace from pos %d" % pos)
         start = pos
         while start > 0:
             c = stc.GetCharAt(start - 1)
             if c == ord(' ') or c == ord('\t') or c == 10 or c == 13:
                 start -= 1
             else:
                 break
         if start < pos:
             stc.SetTargetStart(start)
             stc.SetTargetEnd(pos)
             stc.ReplaceTarget('')
         else:
             stc.CmdKeyExecute(wx.stc.STC_CMD_DELETEBACK)
Пример #4
0
 def electricDelete(self, stc):
     """Delete all whitespace after the cursor unless in a string or comment
     """
     start, end = stc.GetSelection()
     if start != end:
         stc.ReplaceSelection("")
         return
     pos = stc.GetCurrentPos()
     s = stc.GetStyleAt(pos)
     if stc.isStyleComment(s) or stc.isStyleString(s):
         stc.CmdKeyExecute(wx.stc.STC_CMD_CLEAR)
     else:
         self.dprint("deleting from pos %d" % pos)
         end = pos
         while end < stc.GetLength():
             c = stc.GetCharAt(end)
             if c == ord(' ') or c == ord('\t') or c == 10 or c == 13:
                 end += 1
             else:
                 break
         if end > pos:
             stc.SetTargetStart(pos)
             stc.SetTargetEnd(end)
             stc.ReplaceTarget('')
         else:
             stc.CmdKeyExecute(wx.stc.STC_CMD_CLEAR)
Пример #5
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
Пример #6
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)
Пример #7
0
 def electricChar(self, stc, uchar):
     """Reindent the line and insert a newline when special chars are typed.
     
     For python mode, a colon should reindent the line (for example, after
     an else statement, it should dedent it one level)
     """
     if uchar == u':':
         pos = stc.GetCurrentPos()
         s = stc.GetStyleAt(pos)
         if stc.isStyleComment(s) or stc.isStyleString(s):
             # These will report true if the cursor is before the first
             # character of a comment or string, meaning that:
             #
             #    else#blah
             #
             # where the cursor is between the 'e' and the '#' will fail.
             # So, we have to check for this as a special case and allow it
             if pos > 0:
                 s = stc.GetStyleAt(pos - 1)
                 allow = not stc.isStyleComment(
                     s) and not stc.isStyleString(s)
             else:
                 allow = False
         else:
             allow = True
         if allow:
             stc.BeginUndoAction()
             start, end = stc.GetSelection()
             if start == end:
                 stc.AddText(uchar)
             else:
                 stc.ReplaceSelection(uchar)
             self.reindentLine(stc, dedent_only=True)
             stc.EndUndoAction()
             return True
     return False
Пример #8
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
Пример #9
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
Пример #10
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