def open(self): document = kate.activeDocument().url() fileName = KFileDialog.getOpenUrl(document) if fileName != "": if self.part.openUrl(fileName): # Invalid page number so we get the correct function, not the slot function wich doesn't return a bool # Disable okular's file watcher, if file open, due to KDE Bug 329101 if kate.activeDocument() != None: if kate.documentManager.findUrl(self.part.url()) == None: self.part.setWatchFileModeEnabled(True) else: self.check_watcher(kate.activeDocument()) self.kate_window.showToolView(self.tool_view) self.act_preview_file.setEnabled(True) self.act_go_jump.setEnabled(True) #self.act_show_panel.setEnabled(True) print(self.part.currentDocument()) #self.part.openSourceReference.disconnect() self.part.openSourceReference.connect(self.onSourceReferenceActivated) #print("¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤") #print("Widget: ", self.part.pageView().viewport()) #self.part.pageView().setObjectName("Testooo") #self.filter = mouseEventFilter(self) #self.part.pageView().viewport().installEventFilter(self.filter) self.part.enableTOC(True) return True return False
def importUrls(): currentDocument = kate.activeDocument() path = unicode(currentDocument.url().directory()) path_split = path.split('/') application = path_split[len(path_split) - 1] or TEXT_TO_CHANGE insertText(TEXT_URLS % {'app': application, 'change': TEXT_TO_CHANGE})
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 closeTagAtCursor(): document = kate.activeDocument() view = document.activeView() currentPosition = view.cursorPosition() insertionPosition = view.cursorPosition() tag = openingTagBeforeCursor(document, insertionPosition) onPreviousLine = False tagLine = None if tag is None: insertionPosition.setLine(insertionPosition.line() - 1) if insertionPosition.isValid(): insertionPosition.setColumn(document.lineLength(insertionPosition.line())) if insertionPosition.isValid(): tag = openingTagBeforeCursor(document, insertionPosition) tagLine = document.line(insertionPosition.line()) onPreviousLine = True insertionPosition.setLine(currentPosition.line() + 1) insertionPosition.setColumn(0) if tag is None: kate.gui.popup('No opening tag found', 2, icon='dialog-warning', minTextWidth=200) return currentLine = document.line(currentPosition.line()) insertionText = '</%s>' % tag if onPreviousLine: leadingSpacing = re.search('^\s*', tagLine).group(0) insertionText = '%s%s\n' % (leadingSpacing, insertionText) document.startEditing() document.insertText(insertionPosition, insertionText) view.setCursorPosition(currentPosition) document.endEditing()
def checkJslint(currentDocument=None): """Check your js code with the jslint tool""" if not (not currentDocument or (is_mymetype_js(currentDocument) and not currentDocument.isModified())): return move_cursor = not currentDocument currentDocument = currentDocument or kate.activeDocument() mark_iface = currentDocument.markInterface() clearMarksOfError(currentDocument, mark_iface) hideOldPopUps() path = unicode(currentDocument.url().path()) mark_key = '%s-jslint' % path text = unicode(currentDocument.text()) errors = check_JSLint(text.encode('utf-8', 'ignore')) errors_to_show = [] # Prepare errors found for painting for error in errors: matches = pattern.search(error) if matches: errors_to_show.append({ "message": matches.groups()[2], "line": int(matches.groups()[0]), "column": int(matches.groups()[1]) + 1, }) if len(errors_to_show) == 0: showOk("JSLint Ok") return showErrors('JSLint Errors:', errors_to_show, mark_key, currentDocument, move_cursor=move_cursor)
def checkAll(doc=None, excludes=None, exclude_all=False): """Check the syntax, pep8 and pyflakes errors of the document""" if not (not doc or (is_mymetype_python(doc) and not doc.isModified())): return from python_checkers.parse_checker import parseCode excludes = excludes or [] currentDoc = doc or kate.activeDocument() mark_iface = currentDoc.markInterface() clearMarksOfError(currentDoc, mark_iface) hideOldPopUps() if not exclude_all: if not 'parseCode' in excludes: parseCode.f(currentDoc, refresh=False) if not 'checkPyflakes' in excludes: try: from python_checkers.pyflakes_checker import checkPyflakes checkPyflakes.f(currentDoc, refresh=False) except ImportError: pass if not 'checkPep8' in excludes: try: from python_checkers.pep8_checker import checkPep8 checkPep8.f(currentDoc, refresh=False) except ImportError: import pdb; pdb.set_trace() if not doc and currentDoc.isModified() and not excludes: kate.gui.popup('You must save the file first', 3, icon='dialog-warning', minTextWidth=200)
def insertText(text, strip_line=False, start_in_current_column=False, delete_spaces_initial=False, move_to=True): currentDocument = kate.activeDocument() view = currentDocument.activeView() currentPosition = view.cursorPosition() spaces = '' if strip_line: text = '\n'.join([line.strip() for line in text.splitlines()]) if start_in_current_column: number_of_spaces = currentPosition.position()[1] spaces = ' ' * number_of_spaces text = '\n'.join([i > 0 and '%s%s' % (spaces, line) or line for i, line in enumerate(text.splitlines())]) if delete_spaces_initial: currentPosition.setColumn(0) currentDocument.insertText(currentPosition, text) text_to_change_len = len(TEXT_TO_CHANGE) if move_to and TEXT_TO_CHANGE in text: currentPosition = view.cursorPosition() pos_xxx = text.index(TEXT_TO_CHANGE) lines = text[pos_xxx + text_to_change_len:].count('\n') column = len(text[:pos_xxx].split('\n')[-1]) - currentPosition.column() setSelectionFromCurrentPosition((-lines, column), (-lines, column + text_to_change_len))
def insertText(text, strip_line=False, start_in_current_column=False, delete_spaces_initial=False, move_to=True): currentDocument = kate.activeDocument() view = currentDocument.activeView() currentPosition = view.cursorPosition() spaces = '' if strip_line: text = '\n'.join([line.strip() for line in text.splitlines()]) if start_in_current_column: number_of_spaces = currentPosition.position()[1] spaces = ' ' * number_of_spaces text = '\n'.join([ i > 0 and '%s%s' % (spaces, line) or line for i, line in enumerate(text.splitlines()) ]) if delete_spaces_initial: currentPosition.setColumn(0) currentDocument.insertText(currentPosition, text) text_to_change_len = len(TEXT_TO_CHANGE) if move_to and TEXT_TO_CHANGE in text: currentPosition = view.cursorPosition() pos_xxx = text.index(TEXT_TO_CHANGE) lines = text[pos_xxx + text_to_change_len:].count('\n') column = len(text[:pos_xxx].split('\n')[-1]) - currentPosition.column() setSelectionFromCurrentPosition((-lines, column), (-lines, column + text_to_change_len))
def checkAll(doc=None, excludes=None, exclude_all=False): """Check the syntax, pep8 and pyflakes errors of the document""" if not (not doc or (is_mymetype_python(doc) and not doc.isModified())): return from python_checkers.parse_checker import parseCode excludes = excludes or [] currentDoc = doc or kate.activeDocument() mark_iface = currentDoc.markInterface() clearMarksOfError(currentDoc, mark_iface) hideOldPopUps() if not exclude_all: if not 'parseCode' in excludes: parseCode.f(currentDoc, refresh=False) if not 'checkPyflakes' in excludes: try: from python_checkers.pyflakes_checker import checkPyflakes checkPyflakes.f(currentDoc, refresh=False) except ImportError: pass if not 'checkPep8' in excludes: try: from python_checkers.pep8_checker import checkPep8 checkPep8.f(currentDoc, refresh=False) except ImportError: import pdb pdb.set_trace() if not doc and currentDoc.isModified() and not excludes: kate.gui.popup('You must save the file first', 3, icon='dialog-warning', minTextWidth=200)
def checkPyflakes(currentDocument=None, refresh=True): """Check the pyflakes errors of the document""" if not canCheckDocument(currentDocument): return if refresh: checkAll.f(currentDocument, ['checkPyflakes'], exclude_all=not currentDocument) move_cursor = not currentDocument currentDocument = currentDocument or kate.activeDocument() path = unicode(currentDocument.url().path()) mark_key = '%s-pyflakes' % path text = unicode(currentDocument.text()) errors = pyflakes(text.encode('utf-8', 'ignore'), path) errors_to_show = [] if len(errors) == 0: showOk("Pyflakes Ok") return # Prepare errors found for painting for error in errors: errors_to_show.append({ "message": error.message % error.message_args, "line": error.lineno, }) showErrors('Pyflakes Errors:', errors_to_show, mark_key, currentDocument, move_cursor=move_cursor)
def on_btnSettings_clicked(self): settingsDialog = SettingsDialog(kate.activeDocument().url(), self) settingsDialog.txtIncludePatterns.setPlainText("\n".join([r.pattern for r in self.lister.includeFilters])) settingsDialog.txtExcludePatterns.setPlainText("\n".join([r.pattern for r in self.lister.excludeFilters])) for path in self.projectPaths: settingsDialog.listProjectPaths.addItem(path) if settingsDialog.exec_(): configPaths = self.config.group("ProjectPaths") for key in configPaths.keyList(): configPaths.deleteEntry(key) self.projectPaths = [] i = 0 while i < settingsDialog.listProjectPaths.count(): item = settingsDialog.listProjectPaths.item(i) configPaths.writePathEntry("path%s" % i, item.text()) self.projectPaths.append(item.text()) i += 1 configFilters = self.config.group("Filters") includeFilters = settingsDialog.txtIncludePatterns.toPlainText() self.lister.setIncludeFilters(includeFilters) configFilters.writeEntry("include", includeFilters) excludeFilters = settingsDialog.txtExcludePatterns.toPlainText() self.lister.setExcludeFilters(excludeFilters) configFilters.writeEntry("exclude", excludeFilters) self.config.sync()
def changeParagraphWidth(step): view = kate.activeView() doc = kate.activeDocument() pos = view.cursorPosition() originRange, isBlock = getParagraphRange(doc, pos) if originRange.isEmpty(): ui.popup("Sorry", "can't detect commented paragraph at cursor...", "face-sad") return # Dunno what to do on empty range! indent = common.getCurrentLineIndentation(view) # detect current align # Processing: # 0) split text into left stripped lines originalText = view.document().text(originRange) lines = [line.lstrip() for line in originalText.split('\n')] # 1) detect comment style comment = [c.strip() for c in lines[0].split(' ')][0] # 2) strip leading comments (and possible left spaces) from each line lines = [line[len(comment):].lstrip() for line in lines] # 3) get a desired width of the current paragraph if step == -1: # 3.1) For shrink it is really simple: we just want to fit last word # to the next line, and it is enough to specify max(line size) - 1 newSize = len(max(lines, key=len)) - 1 elif step == 1: # 3.2) To extend paragraph we just want to append a first word from the next # after longest line. currentMax = 0 prevLineWasLongest = False delta = 0 for line in lines: # 3.2.1) if current maximum was changed on prevoius iteration, # get length of a first word on a line if prevLineWasLongest: # NOTE +1 for one space delta = len([word.strip() for word in line.split(' ')][0]) + 1 # 3.2.2) is current line longer than we've seen before? lineSize = len(line) prevLineWasLongest = bool(currentMax < lineSize) if prevLineWasLongest: currentMax = lineSize newSize = currentMax + delta else: assert (not "Incorrect step specified") # 4) wrap the text res = textwrap.wrap(' '.join(lines), newSize, break_long_words=False) # 5) form a text from the result list align = ' ' * indent + comment + ' ' text = align + ('\n' + align).join(res) + '\n' # Return text only if smth really changed if originalText != text: # Update document only if smth really has changed doc.startEditing() # Start edit transaction: doc.removeText(originRange) # Remove the origin range doc.insertText(originRange.start(), text) # Insert modified text view.setCursorPosition(originRange.start( )) # Move cursor to the start of the origin range doc.endEditing() # End transaction
def closeTemplateTag(): """Close the last templatetag open""" django_utils_conf = kate.configuration.root.get('django_utils', {}) template_tags_close = django_utils_conf.get(_TEMPLATE_TAGS_CLOSE, DEFAULT_TEMPLATE_TAGS_CLOSE).split(",") template_tags_close = [tag.strip() for tag in template_tags_close] template_tags = '|'.join(template_tags_close) pattern_tag_open = re.compile("(.)*{%%%(espaces)s(%(tags)s)%(espaces)s(.)*%(espaces)s%%}(.)*" % {'espaces': str_blank, 'tags': template_tags}) pattern_tag_close = re.compile("(.)*{%%%(espaces)send(%(tags)s)%(espaces)s%(espaces)s%%}(.)*" % {'espaces': str_blank, 'tags': template_tags}) tag_closes = {} currentDocument = kate.activeDocument() view = currentDocument.activeView() currentPosition = view.cursorPosition() currentLine = currentPosition.line() tag = '' while currentLine >= 0: text = currentDocument.line(currentLine) match_open = pattern_tag_open.match(text) if match_open: tag_name = match_open.groups()[1] if tag_name in tag_closes: tag_closes[tag_name] -= 1 if tag_closes[tag_name] == 0: del tag_closes[tag_name] elif not tag_closes: tag = match_open.groups()[1] break else: match_close = pattern_tag_close.match(text) if match_close: tag_name = match_close.groups()[1] tag_closes[tag_name] = tag_closes.get(tag_name, 0) + 1 currentLine = currentLine - 1 insertText("{%% end%s %%}" % tag)
def checkPyflakes(currentDocument=None, refresh=True): """Check the pyflakes errors of the document""" if not canCheckDocument(currentDocument): return if refresh: checkAll.f(currentDocument, ['checkPyflakes'], exclude_all=not currentDocument) move_cursor = not currentDocument currentDocument = currentDocument or kate.activeDocument() path = currentDocument.url().path() mark_key = '%s-pyflakes' % path text = currentDocument.text() errors = pyflakes(text, path) errors_to_show = [] if len(errors) == 0: showOk(i18n("Pyflakes Ok")) return # Prepare errors found for painting for error in errors: error_to_show = { "message": error.message % error.message_args, "line": error.lineno, } if getattr(error, 'col', None) is not None: error_to_show['column'] = error.col + 1 errors_to_show.append(error_to_show) showErrors(i18n('Pyflakes Errors:'), errors_to_show, mark_key, currentDocument, move_cursor=move_cursor)
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.url().toLocalFile(), "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) self.historyWidget.resizeColumnsToContents()
def boostFormat(): document = kate.activeDocument() view = kate.activeView() try: r, nestedRanges, breakPositions = getRangeTopology(',') except LookupError as error: ui.popup("Failed to parse C++ expression", str(error), "face-sad") return if r.isEmpty(): # Is range empty? ui.popup( "Failed to parse C++ expression" , "Didn't found anything to format. Sorry" , "face-sad" ) return # Nothing interesting wasn't found... # Rescan the range w/ ';' as breaker added if current range is a `for` statement if document.line(r.start().line())[0:r.start().column() - 1].rstrip().endswith('for'): try: r, nestedRanges, breakPositions = getRangeTopology(',;') except LookupError as error: ui.popup("Failed to parse C++ expression", str(error), "face-sad") return # Going to unformat a text whithin a selected range text = boostUnformatText(r, breakPositions)
def toggleBlock(): document = kate.activeDocument() view = kate.activeView() # Make list of ranges of #if*/#endif blocks blocksList = buildIfEndifMap(document) # Locate a block where cursor currently positioned idx = locateBlock(view.cursorPosition().line(), blocksList, False) if idx != -1: # Get current value v = BLOCK_START_SEARCH_RE.search(str(document.line(blocksList[idx][0]))).group(1) # Toggle it! if v in ('0', 'false'): newValue = '1' elif v in ('1', 'true'): newValue = '0' else: return # Replace string document.startEditing() # Start edit transaction document.removeLine(blocksList[idx][0]) # TODO Do not lose formatting! document.insertLine(blocksList[idx][0], "#if " + newValue) document.endEditing() # End transaction else: ui.popup("Oops", "It seems cursor positioned out of any #if0/#if1 block", "face-sad")
def checkPyflakes(currentDocument=None, refresh=True): if not commons.canCheckDocument(currentDocument): return if refresh: checkAll(currentDocument, ['checkPyflakes'], exclude_all=not currentDocument) move_cursor = not currentDocument currentDocument = currentDocument or kate.activeDocument() path = unicode(currentDocument.url().path()) mark_key = '%s-pyflakes' % path text = unicode(currentDocument.text()) errors = pyflakes(text.encode('utf-8', 'ignore'), path) errors_to_show = [] if len(errors) == 0: commons.showOk("Pyflakes Ok") return # Prepare errors found for painting for error in errors: errors_to_show.append({ "filename": path, "message": error.message % error.message_args, "line": error.lineno, }) commons.showErrors('Pyflakes Errors:', errors_to_show, mark_key, currentDocument, move_cursor=move_cursor)
def comment_block(): '''Wrap selected text (or current line) into a #if0/#endif block''' view = kate.activeView() # This operation have no sense for partly selected lines common.extendSelectionToWholeLine(view) start = -1 end = -1 if view.selection(): sr = view.selectionRange() start = sr.start().line() end = sr.end().line() + 1 else: start = view.cursorPosition().line() end = start + 2 # Do it! document = kate.activeDocument() if start != -1 and end != -1: document.startEditing() # Start edit transaction document.insertLine(start, '#if 0') document.insertLine(end, '#endif') view.removeSelection() document.endEditing() # End transaction
def boostFormatText(textRange, indent, breakPositions): document = kate.activeDocument() originalText = document.text(textRange) #kate.kDebug("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: #kate.kDebug("* prev pos: " + str(prevPos.line()) + ", " + str(prevPos.column())) #kate.kDebug("* current pos: " + str(b.line()) + ", " + str(b.column())) chunk = (document.text(KTextEditor.Range(prevPos, b))).strip() #kate.kDebug("* current chunk:\n'" + chunk + "'") t = ('\n ').join(chunk.splitlines()) #kate.kDebug("* 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 #kate.kDebug("Out text:\n'" + outText + "'") if outText != originalText: document.startEditing() document.replaceText(textRange, outText) document.endEditing()
def checkJslint(currentDocument=None, refresh=True): if not (not currentDocument or (is_mymetype_js(currentDocument) and not currentDocument.isModified())): return if refresh: checkAll.f(currentDocument, ['checkJslint'], exclude_all=not currentDocument) move_cursor = not currentDocument currentDocument = currentDocument or kate.activeDocument() path = unicode(currentDocument.url().path()) mark_key = '%s-jslint' % path text = unicode(currentDocument.text()) errors = check_JSLint(text.encode('utf-8', 'ignore')) errors_to_show = [] # Prepare errors found for painting for error in errors: matches = pattern.search(error) if matches: errors_to_show.append({ "filename": path, "message": matches.groups()[2], "line": int(matches.groups()[0]), "column": int(matches.groups()[1]) + 1, }) if len(errors_to_show) == 0: commons.showOk("JSLint Ok") return commons.showErrors('JSLint Errors:', errors_to_show, mark_key, currentDocument, move_cursor=move_cursor)
def updateColors(self, view=None): """Scan a document for #colors""" self.colors = list() # Clear previous colors if view: document = view.document() else: try: document = kate.activeDocument() except kate.NoActiveView: return # Do nothing if we can't get a current document # Iterate over document's lines trying to find #colors for l in range(0, document.lines()): line = document.line(l) # Get the current line start = 0 # Set initial position to 0 (line start) while start < len(line): # Repeat 'till the line end start = line.find( '#', start) # Try to find a '#' character (start of #color) if start == -1: # Did we found smth? break # No! Nothing to do... # Try to get a word right after the '#' char end = start + 1 for c in line[end:]: if not (c in string.hexdigits or c in string.ascii_letters): break end += 1 color_range = KTextEditor.Range(l, start, l, end) color_str = document.text(color_range) color = QColor(color_str) if color.isValid(): self.colors.append(ColorRangePair(color, color_range)) print('PALETTE VIEW: Found %s' % color_str) start = end
def _wrapRange(rangeToWrap, openCh, closeCh, doc = None): if not doc: doc = kate.activeDocument() doc.startEditing() # Start atomic UnDo operation doc.replaceText(rangeToWrap, openCh + doc.text(rangeToWrap) + closeCh) doc.endEditing() # Done editing
def checkAll(doc=None, excludes=None, exclude_all=False): from pyte_plugins.check_plugins.parse_plugins import parseCode if not doc or not doc.isModified(): excludes = excludes or [] currentDoc = doc or kate.activeDocument() mark_iface = currentDoc.markInterface() clearMarksOfError(currentDoc, mark_iface) hideOldPopUps() if not exclude_all: if not 'parseCode' in excludes: parseCode.f(currentDoc, refresh=False) if not 'checkPyflakes' in excludes: try: from pyte_plugins.check_plugins.pyflakes_plugins import checkPyflakes checkPyflakes.f(currentDoc, refresh=False) except ImportError: pass if not 'checkPep8' in excludes: try: from pyte_plugins.check_plugins.pep8_plugins import checkPep8 checkPep8.f(currentDoc, refresh=False) except ImportError: pass if not 'checkJslint' in excludes: try: from jste_plugins.jslint_plugins import checkJslint checkJslint.f(currentDoc, refresh=False) except ImportError: pass if not doc and currentDoc.isModified() and not excludes: kate.gui.popup('You must save the file first', 3, icon='dialog-warning', minTextWidth=200)
def prettyXMLFormat(): """Pretty format of a XML code""" # TODO Use decorators to apply constraints document = kate.activeDocument() view = document.activeView() try: encoding = 'utf-8' source = view.selectionText() m = encoding_pattern.match(source) if m: encoding = m.groups()[0] target = minidom.parseString(source.encode(encoding)) unicode_escape = codecs.getdecoder('unicode_escape') indent = unicode_escape( kate.configuration.get(_INDENT_CFG, DEFAULT_INDENT))[0] newl = unicode_escape(kate.configuration.get(_NEWL_CFG, DEFAULT_NEWL))[0] xml_pretty = target.toprettyxml( indent=indent, newl=newl, encoding=encoding).decode(encoding) xml_pretty = newl.join([ line for line in xml_pretty.split(newl) if line.replace(' ', '').replace(indent, '') ]) document.replaceText(view.selectionRange(), xml_pretty) except (ExpatError, LookupError) as e: showError( i18nc('@info:tooltip', 'The selected text is not valid XML: %1', str(e)))
def checkAll(doc=None, excludes=None, exclude_all=False): """Check the syntax, pep8 and pyflakes errors of the document""" python_utils_conf = kate.configuration.root.get('python_utils', {}) if not (not doc or (is_mymetype_python(doc) and not doc.isModified())): return is_called = not bool(doc) from python_checkers.parse_checker import parseCode excludes = excludes or [] currentDoc = doc or kate.activeDocument() mark_iface = currentDoc.markInterface() clearMarksOfError(currentDoc, mark_iface) if not exclude_all: if not 'parseCode' in excludes and (is_called or python_utils_conf.get(_PARSECODE_CHECK_WHEN_SAVE, DEFAULT_PARSECODE_CHECK_WHEN_SAVE)): parseCode.f(currentDoc, refresh=False) if not 'checkPyflakes' in excludes and (is_called or python_utils_conf.get(_PYFLAKES_CHECK_WHEN_SAVE, DEFAULT_CHECK_PYFLAKES_WHEN_SAVE)): try: from python_checkers.pyflakes_checker import checkPyflakes checkPyflakes.f(currentDoc, refresh=False) except ImportError: pass if not 'checkPep8' in excludes and (is_called or python_utils_conf.get(_PEP8_CHECK_WHEN_SAVE, DEFAULT_CHECK_PEP8_WHEN_SAVE)): from python_checkers.pep8_checker import checkPep8 checkPep8.f(currentDoc, refresh=False) if not doc and currentDoc.isModified() and not excludes: showError(i18n('You must save the file first'))
def processLine(line, commentCh): result = [] column = kate.configuration[COMMENT_START_POS] # Split line before and after a comment (before, comment, after) = line.partition(commentCh) before_s = before.rstrip() # Is there a comment on a line? if bool(comment): # Is there is any text before inline comment position? if bool(before_s): # Yes! Is text before not longer than desired comment position if len(before_s) < (kate.configuration[COMMENT_START_POS] + 1): # Yep, just reformat the line... result.append(before_s + (' ' * (kate.configuration[COMMENT_START_POS] - len(before_s))) + commentCh + after.rstrip()) else: # Move comment to the line above column = len(before) - len(before.lstrip()) # NOTE Try to fix Doxygen comment on the fly: '///<' or '//!<' --> '///' if after[1] == '<' and (after[0] == '!' or after[0] == '/'): after = '/' + after[2:] result.append(' ' * column + commentCh + after.rstrip()) result.append(before_s) else: # No! The line contains only whitespaces... # Is comment after or 'close before' to inline comment position? if len(before) > (kate.configuration[COMMENT_START_POS] / 6): # Align comment to desired position... result.append(' ' * kate.configuration[COMMENT_START_POS] + commentCh + after.rstrip()) else: # TODO Align comment to closest to div 4 position... result.append(line.rstrip()) else: # There is no comments... What about any text? if bool(before_s): # Is it longer that inline comment position? if len(before_s) > (kate.configuration[COMMENT_START_POS]): column = len(before) - len(before.lstrip()) result.append(' ' * column + commentCh + ' ') result.append(before_s) else: result.append(before_s + ' ' * (kate.configuration[COMMENT_START_POS] - len(before_s)) + commentCh + ' ') # Check for preprocessor directives #else/#endif and try to append # corresponding #if condition as a comment for current line if bool(BLOCK_ELSE_ENDIF_MATCH_RE.search(before_s)): document = kate.activeDocument() view = kate.activeView() # Make list of ranges of #if*/#endif blocks blocksList = buildIfEndifMap(document) # Locate an index of a block where cursor currently positioned (check commented block too) idx = locateBlock(view.cursorPosition().line(), blocksList, True) # Get #if condition (if block located) if idx != -1: # TODO Need to strip possible comment! matchObj = BLOCK_START_GET_COND_RE.search(document.line(blocksList[idx][0])) if bool(matchObj): result[-1] += matchObj.group(4) else: # No text! Just add a comment... result.append(' ' * kate.configuration[COMMENT_START_POS] + commentCh + ' ') return (result, column + len(commentCh) + 1)
def importUrls(): """Insert the typical code of the urls.py file""" currentDocument = kate.activeDocument() path = unicode(currentDocument.url().directory()) path_split = path.split('/') application = path_split[len(path_split) - 1] or TEXT_TO_CHANGE insertText(TEXT_URLS % {'app': application, 'change': TEXT_TO_CHANGE})
def closeTagAtCursor(): document = kate.activeDocument() view = document.activeView() currentPosition = view.cursorPosition() insertionPosition = view.cursorPosition() tag = openingTagBeforeCursor(document, insertionPosition) onPreviousLine = False tagLine = None if tag is None: insertionPosition.setLine(insertionPosition.line() - 1) if insertionPosition.isValid(): insertionPosition.setColumn(document.lineLength(insertionPosition.line())) if insertionPosition.isValid(): tag = openingTagBeforeCursor(document, insertionPosition) tagLine = unicode(document.line(insertionPosition.line())) onPreviousLine = True insertionPosition.setLine(currentPosition.line() + 1) insertionPosition.setColumn(0) if tag is None: kate.gui.popup('No opening tag found', 2, icon='dialog-warning', minTextWidth=200) return currentLine = unicode(document.line(currentPosition.line())) insertionText = u'</%s>' % tag if onPreviousLine: leadingSpacing = re.search('^\s*', tagLine).group(0) insertionText = '%s%s\n' % (leadingSpacing, insertionText) document.startEditing() document.insertText(insertionPosition, insertionText) view.setCursorPosition(currentPosition) document.endEditing()
def commentBlock(): '''Wrap selected text (or current line) into a #if0/#endif block''' view = kate.activeView() # This operation have no sense for partly selected lines common.extendSelectionToWholeLine(view) start = -1 end = -1 if view.selection(): sr = view.selectionRange() start = sr.start().line() end = sr.end().line() + 1 else: start = view.cursorPosition().line() end = start + 2 # Do it! document = kate.activeDocument() if start != -1 and end != -1: document.startEditing() # Start edit transaction document.insertLine(start, "#if 0") document.insertLine(end, "#endif") view.removeSelection() document.endEditing() # End transaction
def boostUnformat(): '''Merge everything between '(' and ')' into a single line''' document = kate.activeDocument() view = kate.activeView() try: r, nestedRanges, breakPositions = getRangeTopology(',') except LookupError as error: ui.popup("Failed to parse C++ expression", str(error), "face-sad") return if r.isEmpty(): # Is range empty? ui.popup("Failed to parse C++ expression", "Didn't found anything to format. Sorry", "face-sad") return # Nothing interesting wasn't found... # Rescan the range w/ ';' as breaker added if current range is a `for` statement if document.line(r.start().line())[0:r.start().column() - 1].rstrip().endswith('for'): try: r, nestedRanges, breakPositions = getRangeTopology(',;') except LookupError as error: ui.popup("Failed to parse C++ expression", str(error), "face-sad") return # Going to unformat a text whithin a selected range text = boostUnformatText(r, breakPositions)
def insertIntoCurrentDocument(self, item, column): if item is not None and column == 0: view = kate.activeView() document = kate.activeDocument() document.startEditing() document.insertText(view.cursorPosition(), item.text(0)) document.endEditing()
def togglePrettyJsonFormat(): """Pretty format of a XML code""" currentDocument = kate.activeDocument() view = currentDocument.activeView() source = unicode(view.selectionText()).encode('utf-8', 'ignore') if not source: kate.gui.popup('Select a xml text', 2, icon='dialog-warning', minTextWidth=200) else: try: target = minidom.parseString(source) view.removeSelectionText() xml_pretty = target.toprettyxml() xml_pretty = '\n'.join([ line for line in xml_pretty.split("\n") if line.replace(' ', '').replace('\t', '') ]) text.insertText(xml_pretty) except ExpatError: kate.gui.popup('This text is not a valid xml text', 2, icon='dialog-warning', minTextWidth=200)
def insertHelpItemIntoCurrentDocument(self,item, column): if item is not None and item.type() == cmake_help_parser.help_category.HELP_ITEM and column == 0: view = kate.activeView() document = kate.activeDocument() document.startEditing() document.insertText(view.cursorPosition(), item.text(0)) document.endEditing()
def closeTemplateTag(): """Close the last templatetag open""" template_tags = '|'.join(TEMPLATE_TAGS_CLOSE) pattern_tag_open = re.compile("(.)*{%%%(espaces)s(%(tags)s)%(espaces)s(.)*%(espaces)s%%}(.)*" % {'espaces': str_blank, 'tags': template_tags}) pattern_tag_close = re.compile("(.)*{%%%(espaces)send(%(tags)s)%(espaces)s%(espaces)s%%}(.)*" % {'espaces': str_blank, 'tags': template_tags}) tag_closes = {} currentDocument = kate.activeDocument() view = currentDocument.activeView() currentPosition = view.cursorPosition() currentLine = currentPosition.line() tag = '' while currentLine >= 0: text = unicode(currentDocument.line(currentLine)) match_open = pattern_tag_open.match(text) if match_open: tag_name = match_open.groups()[1] if tag_name in tag_closes: tag_closes[tag_name] -= 1 if tag_closes[tag_name] == 0: del tag_closes[tag_name] elif not tag_closes: tag = match_open.groups()[1] break else: match_close = pattern_tag_close.match(text) if match_close: tag_name = match_close.groups()[1] tag_closes[tag_name] = tag_closes.get(tag_name, 0) + 1 currentLine = currentLine - 1 insertText("{%% end%s %%}" % tag)
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 _wrapRange(rangeToWrap, openCh, closeCh, doc=None): if not doc: doc = kate.activeDocument() doc.startEditing() # Start atomic UnDo operation doc.replaceText(rangeToWrap, openCh + doc.text(rangeToWrap) + closeCh) doc.endEditing() # Done editing
def test(): doc = kate.activeDocument() view = kate.activeView() ui.popup( text="Current document MIME type: <b>" + doc.mimeType() + "</b><br/>hl: <b>" + doc.highlightingMode() + "</b>" , caption="Some document info: file type" , iconName="face-wink" )
def expandAtCursor(): document = kate.activeDocument() view = document.activeView() try: word_range, argument_range = wordAndArgumentAtCursorRanges(document, view.cursorPosition()) except ParseError, e: kate.popup('Parse error:', e) return
def changeParagraphWidth(step): view = kate.activeView() doc = kate.activeDocument() pos = view.cursorPosition() originRange, isBlock = getParagraphRange(doc, pos) if originRange.isEmpty(): ui.popup("Sorry", "can't detect commented paragraph at cursor...", "face-sad") return # Dunno what to do on empty range! indent = getCurrentLineIndentation(view) # detect current align # Processing: # 0) split text into left stripped lines originalText = view.document().text(originRange) lines = [line.lstrip() for line in originalText.split('\n')] # 1) detect comment style comment = [c.strip() for c in lines[0].split(' ')][0] # 2) strip leading comments (and possible left spaces) from each line lines = [line[len(comment):].lstrip() for line in lines] # 3) get a desired width of the current paragraph if step == -1: # 3.1) For shrink it is really simple: we just want to fit last word # to the next line, and it is enough to specify max(line size) - 1 newSize = len(max(lines, key=len)) - 1 elif step == 1: # 3.2) To extend paragraph we just want to append a first word from the next # after longest line. currentMax = 0 prevLineWasLongest = False delta = 0 for line in lines: # 3.2.1) if current maximum was changed on prevoius iteration, # get length of a first word on a line if prevLineWasLongest: # NOTE +1 for one space delta = len([word.strip() for word in line.split(' ')][0]) + 1 # 3.2.2) is current line longer than we've seen before? lineSize = len(line) prevLineWasLongest = bool(currentMax < lineSize) if prevLineWasLongest: currentMax = lineSize newSize = currentMax + delta else: assert(not "Incorrect step specified") # 4) wrap the text res = textwrap.wrap(' '.join(lines), newSize, break_long_words=False) # 5) form a text from the result list align = ' ' * indent + comment + ' ' text = align + ('\n' + align).join(res) + '\n' # Return text only if smth really changed if originalText != text: # Update document only if smth really has changed doc.startEditing() # Start edit transaction: doc.removeText(originRange) # Remove the origin range doc.insertText(originRange.start(), text) # Insert modified text view.setCursorPosition(originRange.start()) # Move cursor to the start of the origin range doc.endEditing() # End transaction
def expandAtCursor(): document = kate.activeDocument() view = document.activeView() try: word_range, argument_range = wordAndArgumentAtCursorRanges( document, view.cursorPosition()) except ParseError, e: kate.popup('Parse error:', e) return
def checker(*args, **kw): document = kate.activeDocument() # TODO Why this shit^W`if` doesn't work? WTF?! #if not hasattr(action, 'constraints') or reduce(lambda i, j: i(document) and j(document), action.constraints)(): if hasattr(action, 'constraints'): for c in action.constraints: if not c(document): return return action(*args, **kw)
def create_frame(pattern_str='', title='', name_field=''): currentDocument = kate.activeDocument() view = kate.activeView() class_name, ok = QtGui.QInputDialog.getText(view, title, name_field) if ok: class_model = class_name.replace('Form', '') text = pattern_str % {'class_name': class_name, 'class_model': class_model} currentDocument.insertText(view.cursorPosition(), text)
def boostFormat(): '''Format function's/template's parameters list (or `for`'s) in a boost-like style I.e. when 2nd and the rest parameters has leading comma/semicolon and closing ')' or '>' on a separate line. THIS IS REALLY BETTER TO HAVE SUCH STYLE WHEN U HAVE A LONG PARAMETERS LIST! ''' document = kate.activeDocument() view = kate.activeView() try: r, nestedRanges, breakPositions = getRangeTopology(',') except LookupError as error: kate.ui.popup( i18nc('@title:window', 'Alert') , i18nc( '@info:tooltip' , 'Failed to parse C++ expression:<nl/><message>%1</message>', error ) , 'dialog-information' ) return if r.isEmpty(): # Is range empty? kate.ui.popup( i18nc('@title:window', 'Alert') , i18nc( '@info:tooltip' , 'Failed to parse C++ expression:<nl/><message>%1</message>' , i18nc('@info:tooltip', "Did not find anything to format") ) , 'dialog-information' ) return # Nothing interesting wasn't found... # Rescan the range w/ ';' as breaker added if current range is a `for` statement if document.line(r.start().line())[0:r.start().column() - 1].rstrip().endswith('for'): try: r, nestedRanges, breakPositions = getRangeTopology(',;') except LookupError as error: kate.ui.popup( i18nc('@title:window', 'Alert') , i18nc( '@info:tooltip' , 'Failed to parse C++ expression:<nl/><message>%1</message>', error ) , 'dialog-information' ) return # Going to format a text whithin a selected range lineStr = document.line(r.start().line()) lineStrStripped = lineStr.lstrip() indent = len(lineStr) - len(lineStrStripped) if lineStrStripped.startswith(', '): indent += 2 text = boostFormatText(r, indent, breakPositions)
def commentar(): ''' Append or align an inlined comment at position 60 for the current line or the selection. Move cursor to the start of a comment, if nothing has changed. If there wasn't any comment aside of #else/#endif put corresponding #if condition as default comment text ''' document = kate.activeDocument() view = kate.activeView() pos = view.cursorPosition() commentCh = common.getCommentStyleForDoc(document) if view.selection(): # If selected smth on a single line... common.extendSelectionToWholeLine(view) selectedText = view.selectionText().split('\n') if not bool(selectedText[-1]): selectedText = selectedText[0:-1] insertionText = [] firstColumn = -1 for textLine in selectedText: (currentLine, column) = processLine(textLine, commentCh) if firstColumn == -1: firstColumn = column insertionText += currentLine # Modify current document if bool(insertionText): document.startEditing() document.removeText(view.selectionRange()) pos = view.cursorPosition() document.insertText(pos, '\n'.join(insertionText) + '\n') pos.setColumn(firstColumn) view.setCursorPosition(pos) view.removeSelection() document.endEditing() else: (text, column) = processLine(document.line(pos.line()), commentCh) # Apply result (if smth really has changed) originalText = document.line(pos.line()) if bool(text) and (len(text) != 1 or originalText != text[0]): document.startEditing() # Start edit transaction: document.removeLine(pos.line()) # Remove current line # insert resulting text line by line... pos.setColumn(0) document.insertText(pos, '\n'.join(text) + '\n') document.endEditing() # End transaction # Move cursor to desired position pos.setColumn(column) view.setCursorPosition(pos)
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 createBlock(): currentDocument = kate.activeDocument() view = currentDocument.activeView() source = view.selectionText() try: block_type, block_source = source.split("#") except ValueError: block_type = 'block' block_source = source view.removeSelectionText() insertText("{%% %(block_type)s %(block_source)s %%}XXX{%% end%(block_type)s %%}" % {'block_type': block_type, 'block_source': block_source})
def create_frame(pattern_str='', title='', name_field=''): currentDocument = kate.activeDocument() view = kate.activeView() class_name, ok = QtGui.QInputDialog.getText(view, title, name_field) if ok: class_name = unicode(class_name) class_model = class_name.replace('Form', '') text = pattern_str % { 'class_name': class_name, 'class_model': class_model } currentDocument.insertText(view.cursorPosition(), text)
def onViewChanged(self): try: doc = sip.cast(kate.activeDocument(), KateDocument) except kate.api.NoActiveView: return self.act.blockSignals(True) if doc.property('AutoReload'): self.act.setChecked(True) else: self.act.setChecked(False) self.act.blockSignals(False)
def lookup(): global searchBar if show(): if kate.activeView().selection(): selectedText = kate.activeView().selectionText() else: selectedText = wordAtCursor(kate.activeDocument(), kate.activeView()) searchBar.token.insertItem(0, selectedText) searchBar.token.setCurrentIndex(1) searchBar.token.setEditText(selectedText) return searchBar.literalSearch() return None
def createBlock(): """Insert the tag block/endblock. The name of the block will be the text selected""" currentDocument = kate.activeDocument() view = currentDocument.activeView() source = view.selectionText() try: block_type, block_source = source.split("#") except ValueError: block_type = 'block' block_source = source view.removeSelectionText() insertText("{%% %(block_type)s %(block_source)s %%}XXX{%% end%(block_type)s %%}" % {'block_type': block_type, 'block_source': block_source})
def getPythonPath(cls, recalculeSession=False): global python_path if python_path and not recalculeSession: return python_path python_path = sys.path try: from pyte_plugins.autocomplete import autocomplete_path doc = kate.activeDocument() view = doc.activeView() python_path = autocomplete_path.path(recalculeSession, doc, view) + python_path except ImportError: pass return python_path
def get_prototype_of_current_func(): espaces = ' ' * PYTHON_SPACES number_espaces = PYTHON_SPACES * 2 parentheses = 0 class_name = TEXT_TO_CHANGE function_name = TEXT_TO_CHANGE params = ['self', '*args', '**kwargs'] text_def = '' find_finish_def = False view = kate.activeView() currentDocument = kate.activeDocument() currentPosition = view.cursorPosition() currentLine = currentPosition.line() func_def_espaces = None while currentLine >= 0: text = unicode(currentDocument.line(currentLine)) if find_finish_def: text_def = '%s\n%s' % (text, text_def) else: text_def = text if function_name == TEXT_TO_CHANGE: match_finish = pattern_def_finish.match(text_def) match_init = pattern_def_init.match(text_def) if match_finish and match_init: match = pattern_def.match(text_def) number_espaces = get_number_espaces(currentDocument, currentPosition.line()) if not number_espaces: number_espaces = len(match.groups()[0]) + 1 func_def_espaces = match.groups()[0] espaces = ' ' * number_espaces function_name = match.groups()[1] params = match.groups()[2].split(',') params = [ change_kwargs(param.strip(' \t')) for param in params ] elif match_finish: find_finish_def = True parentheses += text_def.count(")") - text_def.count("(") if find_finish_def and parentheses <= 0: parentheses += text_def.count(")") - text_def.count("(") find_finish_def = False match = pattern_class.match(text) if match: if func_def_espaces: current_spaces = len(text) - len(text.lstrip()) if current_spaces < func_def_espaces: class_name = match.groups()[0] break currentLine = currentLine - 1 return (espaces, class_name, function_name, params)
def boostUnformatText(textRange, breakPositions): document = kate.activeDocument() originalText = document.text(textRange) #print("Original text:\n'" + originalText + "'") # Join text within a selected range prevPos = textRange.start() outText = ''.join([line.strip() for line in originalText.splitlines()]) #print("Out text:\n'" + outText + "'") if outText != originalText: document.startEditing() document.replaceText(textRange, outText) document.endEditing()
def insertInit(): class_name = TEXT_TO_CHANGE currentDocument = kate.activeDocument() view = currentDocument.activeView() currentPosition = view.cursorPosition() currentLine = currentPosition.line() while currentLine >= 0: text = unicode(currentDocument.line(currentLine)) match = pattern_class.match(text) if match: class_name = match.groups()[0] break currentLine = currentLine - 1 insertText(TEXT_INIT % class_name)
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