def getBoundTextRangeSL(leftBoundary, rightBoundary, pos, doc): ''' Get the range between any symbol specified in leftBoundary set and rightBoundary Search starts from given cursor position... NOTE `SL' suffix means Single Line -- i.e. when search, do not cross one line boundaries! ''' if not doc.lineLength(pos.line()): return KTextEditor.Range(pos, pos) lineStr = doc.line(pos.line()) # Get the current line as string to analyse found = False # NOTE If cursor positioned at the end of a line, column() # will be equal to the line length and lineStr[cc] will # fail... So it must be handled before the `for' loop... initialPos = min(len(lineStr) - 1, pos.column() - 1) # Let initial index be less than line length for cc in range(initialPos, -1, -1): # Moving towards the line start found = lineStr[ cc] in leftBoundary # Check the current char for left boundary terminators if found: break # Break the loop if found smth startPos = KTextEditor.Cursor(pos.line(), cc + int(found)) cc = pos.column() for cc in range(pos.column(), len(lineStr)): # Moving towards the line end if lineStr[ cc] in rightBoundary: # Check the current char for right boundary terminators break # Break the loop if found smth endPos = KTextEditor.Cursor(pos.line(), cc) return KTextEditor.Range(startPos, endPos)
def setSelectionFromCurrentPosition(start, end, pos=None): view = kate.activeView() pos = pos or view.cursorPosition() cursor1 = KTextEditor.Cursor(pos.line() + start[0], pos.column() + start[1]) cursor2 = KTextEditor.Cursor(pos.line() + end[0], pos.column() + end[1]) view.setSelection(KTextEditor.Range(cursor1, cursor2)) view.setCursorPosition(cursor1)
def navigateToMatch(self, index): """Jump to the selected entry.""" (fileName, icon, text, nextLine, column, fileAndLine) = self.matchesModel.read(index) if not nextLine: return # # Add a history record for the current point. # cursor = kate.activeView().cursorPosition() currentLine = cursor.line() document = kate.activeDocument() self.historyModel.add( document.localFilePath(), "arrow-right", document.line(currentLine), currentLine, cursor.column(), "{}:{}".format(document.documentName(), currentLine + 1)) # # Navigate to the point in the file. # document = kate.documentManager.openUrl(KUrl.fromPath(fileName)) kate.mainInterfaceWindow().activateView(document) point = KTextEditor.Cursor(nextLine, column) kate.activeView().setCursorPosition(point) # # Add this new point to the history. # self.historyModel.add(fileName, icon, text, nextLine, column, fileAndLine)
def boostFormatText(textRange, indent, breakPositions): document = kate.activeDocument() originalText = document.text(textRange) print("Original text:\n'" + originalText + "'") # Slice text whithin a given range into pieces to be realigned ranges = list() prevPos = textRange.start() breakCh = None indentStr = ' ' * (indent + 2) breakPositions.append(textRange.end()) for b in breakPositions: print("* prev pos: " + str(prevPos.line()) + ", " + str(prevPos.column())) print("* current pos: " + str(b.line()) + ", " + str(b.column())) chunk = (document.text(KTextEditor.Range(prevPos, b))).strip() print("* current chunk:\n'" + chunk + "'") t = ('\n ').join(chunk.splitlines()) print("* current line:\n'" + t + "'") if breakCh: outText += indentStr + breakCh + ' ' + t + '\n' else: outText = '\n' + indentStr + ' ' + t + '\n' breakCh = document.character(b) prevPos = KTextEditor.Cursor(b.line(), b.column() + 1) outText += indentStr print("Out text:\n'" + outText + "'") if outText != originalText: document.startEditing() document.replaceText(textRange, outText) document.endEditing()
def _moveCursorTFirstError(line, column=None): try: column = column or 0 cursor = KTextEditor.Cursor(line - 1, column - 1) view = kate.activeView() view.setCursorPosition(cursor) except KeyError: pass
def navigateToHistory(self, index): """Jump to the selected entry.""" (fileName, icon, text, line, column, fileAndLine) = self.historyModel.read(index) # # Navigate to the original point in the file. # document = kate.documentManager.openUrl(KUrl.fromPath(fileName)) kate.mainInterfaceWindow().activateView(document) point = KTextEditor.Cursor(line, column) kate.activeView().setCursorPosition(point)
def killRestOfLine(): '''Remove text from cursor position to the end of the current line''' doc = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() endPosition = KTextEditor.Cursor(pos.line(), doc.lineLength(pos.line())) killRange = KTextEditor.Range(pos, endPosition) doc.startEditing() doc.removeText(killRange) doc.endEditing()
def insertColor(): ''' Insert/edit #color using color chooser dialog If cursor positioned in a #color 'word', this action will edit it, otherwise a new #color will be inserted into a document. ''' document = kate.activeDocument() view = kate.activeView() cursor = view.cursorPosition() if not view.selection(): # If no selection, try to get a #color under cursor colorRange = common.getBoundTextRangeSL(_LEFT_COLOR_BOUNDARY, _RIGHT_COLOR_BOUNDARY, cursor, document) else: # Some text selected, just use it as input... colorRange = view.selectionRange() if colorRange.isValid(): currentColor = document.text(colorRange) else: currentColor = kate.configuration[_INSERT_COLOR_LCC] color = QtGui.QColor(currentColor) # If no text selected (i.e. user don't want to override selection) # and (guessed) #color string is not valid, entered color will # be inserted at the current cursor position. if not color.isValid(): color = QtGui.QColor(kate.configuration[_INSERT_COLOR_LCC]) if not view.selection(): colorRange = KTextEditor.Range( cursor, cursor) # Will not override the text under cursor... # Choose a #color via dialog result = kdeui.KColorDialog.getColor(color) if result == kdeui.KColorDialog.Accepted: # Is user pressed Ok? colorStr = color.name() # Get it as #color text # Remember for future use kate.configuration[_INSERT_COLOR_LCC] = colorStr document.startEditing() document.replaceText( colorRange, colorStr) # Replace selected/found range w/ a new text document.endEditing() # Select just entered #color, if smth was selected before if view.selection(): startPos = colorRange.start() endPos = KTextEditor.Cursor(startPos.line(), startPos.column() + len(colorStr)) view.setSelection(KTextEditor.Range(startPos, endPos))
def turnFromBlockComment(): document = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() if view.selection(): sr = view.selectionRange() start = sr.start().line() end = sr.end().line() else: # Try to detect block comment (/* ... */) r = common.getTextBlockAroundCursor( document, pos, [pred.blockCommentStart, neg(pred.startsWith('*'))], [pred.blockCommentEnd, neg(pred.startsWith('*'))]) start = r.start().line() - 1 end = r.end().line() + 1 # Replace comments insertionText = list() align = None for i in range(start, end): line = str(document.line(i)) sline = line.lstrip() if align == None: align = ' ' * (len(line) - len(sline)) if sline.startswith('/**') or sline.startswith('*/'): continue if sline.startswith('*'): insertionText.append(align + sline.replace('*', '///', 1)) originRange = KTextEditor.Range(start, 0, end, 0) pos.setPosition(start, len(align) + 3) insertPos = KTextEditor.Cursor(start, 0) # Update the document if bool(insertionText): document.startEditing() # Start edit transaction: document.removeText(originRange) # Remove current line # insert resulting text line by line... document.insertText(insertPos, '\n'.join(insertionText) + '\n') # Move cursor to desired position view.setCursorPosition(pos) document.endEditing() # End transaction
def turnToBlockComment(): document = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() if view.selection(): sr = view.selectionRange() start = sr.start().line() end = sr.end().line() else: r = common.getTextBlockAroundCursor( document, pos, [neg(any_of(pred.startsWith('///'), pred.startsWith('//!')))], [neg(any_of(pred.startsWith('///'), pred.startsWith('//!')))]) start = r.start().line() end = r.end().line() # Replace comments in every line insertionText = list() align = None for i in range(start, end): line = str(document.line(i)) sline = line.lstrip() if align == None: align = ' ' * (len(line) - len(sline)) insertionText.append( align + sline.replace('///', ' *', 1).replace('//!', ' *', 1)) originRange = KTextEditor.Range(start, 0, end, 0) pos.setPosition(start + 1, len(align) + 3) insertPos = KTextEditor.Cursor(start, 0) # Update the document if bool(insertionText): document.startEditing() # Start edit transaction: document.removeText(originRange) # Remove current line # insert resulting text ... document.insertText( insertPos, align + '/**\n' + '\n'.join(insertionText) + '\n' + align + ' */\n') # Move cursor to desired position view.setCursorPosition(pos) document.endEditing() # End transaction
def killLeadOfLine(): ''' Remove text from a start of a line to the current cursor position but keep leading spaces (to avoid breaking indentation) NOTE This function suppose spaces as indentation character! TODO Get indent character from config ''' doc = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() indent = common.getCurrentLineIndentation(view) startPosition = KTextEditor.Cursor(pos.line(), 0) killRange = KTextEditor.Range(startPosition, pos) doc.startEditing() doc.removeText(killRange) doc.insertText(startPosition, ' ' * indent) doc.endEditing()
def getRangeTopology(breakChars): '''Get range opened w/ `openCh' and closed w/ `closeCh' @return tuple w/ current range, list of nested ranges and list of positions of break characters @note Assume cursor positioned whithin that range already. ''' document = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() stack = list() nestedRanges = list() breakPositions = list() firstIteration = True found = False # Iterate from the current line towards a document start for cl in range(pos.line(), -1, -1): lineStr = str(document.line(cl)) if not firstIteration: # skip first iteration pos.setColumn( len(lineStr)) # set current column to the end of current line else: firstIteration = False # do nothing on first iteration # Iterate from the current column to a line start for cc in range(pos.column() - 1, -1, -1): #print("c: current position" + str(cl) + "," + str(cc) + ",ch='" + lineStr[cc] + "'") # Check open/close brackets if lineStr[ cc] == ')': # found closing char: append its position to the stack stack.append((cl, cc, False)) print("o( Add position: " + str(stack[-1])) continue if lineStr[cc] == '(': # found open char... if len( stack ): # if stack isn't empty (i.e. there are some closing chars met) print("o( Pop position: " + str(stack[-1])) nrl, nrc, isT = stack.pop( ) # remove last position from the stack if not isT: nestedRanges.append( # and append a nested range KTextEditor.Range(cl, cc, nrl, nrc)) else: raise LookupError("Misbalanced brackets: '(' @" + str(cl + 1) + ',' + str(cc + 1) + " and '>' @ " + str(nrl + 1) + ',' + str(nrc + 1)) else: # otherwise, openPos = (cl, cc + 1, False ) # remember range start (exclude an open char) print("o( Found position: " + str(openPos)) found = True break continue # Check for template angel brackets if lineStr[cc] == '>': if looksLikeTemplateAngelBracket(lineStr, cc): stack.append((cl, cc, True)) print("o< Add position: " + str(stack[-1])) else: print("o< Doesn't looks like template: " + str(cl) + "," + str(cc)) continue if lineStr[cc] == '<': if not looksLikeTemplateAngelBracket(lineStr, cc): print("o< Doesn't looks like template: " + str(cl) + "," + str(cc + 1)) elif len( stack ): # if stack isn't empty (i.e. there are some closing chars met) print("o< Pop position: " + str(stack[-1])) nrl, nrc, isT = stack.pop( ) # remove last position from the stack if isT: nestedRanges.append( # and append a nested range KTextEditor.Range(cl, cc, nrl, nrc)) else: raise LookupError("Misbalanced brackets: '<' @" + str(cl + 1) + ',' + str(cc + 1) + " and ')' @ " + str(nrl + 1) + ',' + str(nrc + 1)) raise LookupError("Misbalanced brackets") else: openPos = (cl, cc + 1, True ) # remember range start (exclude an open char) print("o< Found position: " + str(openPos)) found = True break continue if lineStr[cc] in breakChars and len(stack) == 0: breakPositions.append(KTextEditor.Cursor(cl, cc)) # Did we found smth on the current line? if found: break # Yep! Break the outer loop if not found: return (KTextEditor.Range(), list(), list() ) # Return empty ranges if nothing found assert (len(stack) == 0) # stack expected to be empty! breakPositions.reverse( ) # reverse breakers list required cuz we found 'em in a reverse order :) # Iterate from the current position towards the end of a document pos = view.cursorPosition() # get current cursor position again firstIteration = True found = False for cl in range(pos.line(), document.lines()): lineStr = str(document.line(cl)) if not firstIteration: # skip first iteration pos.setColumn(0) # set current column to the start of current line else: firstIteration = False # do nothing on first iteration for cc in range(pos.column(), len(lineStr)): #print("c: current position" + str(cl) + "," + str(cc) + ",ch='" + lineStr[cc] + "'") # Check open/close brackets if lineStr[cc] == '(': stack.append((cl, cc, False)) print("c) Add position: " + str(stack[-1])) continue if lineStr[cc] == ')': if len(stack): print("c) Pop position: " + str(stack[-1])) nrl, nrc, isT = stack.pop( ) # remove a last position from the stack if not isT: nestedRanges.append( # and append a nested range KTextEditor.Range(nrl, nrc, cl, cc)) else: raise LookupError("Misbalanced brackets: '<' @" + str(nrl + 1) + ',' + str(nrc + 1) + " and ')' @ " + str(cl + 1) + ',' + str(cc + 1)) else: closePos = (cl, cc, False) # remember the range end print("c) Found position: " + str(closePos)) found = True break continue # Check for template angel brackets if lineStr[cc] == '<': if looksLikeTemplateAngelBracket(lineStr, cc): stack.append((cl, cc, True)) print("c> Add position: " + str(stack[-1])) else: print("c> Doesn't looks like template: " + str(cl) + "," + str(cc)) continue if lineStr[cc] == '>': if not looksLikeTemplateAngelBracket(lineStr, cc): print("c> Doesn't looks like template: " + str(cl) + "," + str(cc)) elif len( stack ): # if stack isn't empty (i.e. there are some closing chars met) print("c> Pop position: " + str(stack[-1])) nrl, nrc, isT = stack.pop( ) # remove last position from the stack if isT: nestedRanges.append( # and append a nested range KTextEditor.Range(cl, cc, nrl, nrc)) else: raise LookupError("Misbalanced brackets: '(' @" + str(nrl + 1) + ',' + str(nrc + 1) + " and '>' @ " + str(cl + 1) + ',' + str(cc + 1)) else: closePos = (cl, cc, True) # remember the range end print("c> Found position: " + str(closePos)) found = True break continue if lineStr[cc] in breakChars and len(stack) == 0: breakPositions.append(KTextEditor.Cursor(cl, cc)) # Did we found smth on the current line? if found: break # Yep! Break the outer loop if not found: return (KTextEditor.Range(), list(), list() ) # Return empty ranges if nothing found assert (len(stack) == 0) # stack expected to be empty! if openPos[2] != closePos[2]: raise LookupError("Misbalanced brackets: at " + str(openPos[0] + 1) + ',' + str(openPos[1] + 1) + " and " + str(closePos[0] + 1) + ',' + str(closePos[1] + 1)) return (KTextEditor.Range(openPos[0], openPos[1], closePos[0], closePos[1]), nestedRanges, breakPositions)
def sortImports(): document = kate.activeDocument() document.setText(SortImports(file_contents=document.text()).output) document.activeView().setCursorPosition(KTextEditor.Cursor(0, 0))