Beispiel #1
0
 def actionTriggered(self, name):
     # convert arpeggio_normal to arpeggioNormal, etc.
     name = _arpeggioTypes[name]
     cursor = self.mainwindow().textCursor()
     # which arpeggio type is last used?
     lastused = '\\arpeggioNormal'
     types = set(_arpeggioTypes.values())
     block = cursor.block()
     while block.isValid():
         s = types.intersection(tokeniter.tokens(block))
         if s:
             lastused = s.pop()
             break
         block = block.previous()
     # where to insert
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     with cursortools.compress_undo(cursor):
         for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE):
             c = QTextCursor(cursor.document())
             c.setPosition(item.end)
             c.insertText('\\arpeggio')
             if name != lastused:
                 cursortools.strip_indent(c)
                 indent = c.block().text()[:c.position()-c.block().position()]
                 c.insertText(name + '\n' + indent)
             # just pick the first place
             return
Beispiel #2
0
def spanner_positions(cursor):
    """Return a list with 0 to 2 QTextCursor instances.
    
    At the first cursor a starting spanner item can be inserted, at the
    second an ending item.
    
    """   
    c = lydocument.cursor(cursor)
    if cursor.hasSelection():
        partial = ly.document.INSIDE
    else:
        # just select until the end of the current line
        c.select_end_of_block()
        partial = ly.document.OUTSIDE
    
    items = list(ly.rhythm.music_items(c, partial=partial))
    if cursor.hasSelection():
        del items[1:-1]
    else:
        del items[2:]
    
    positions = []
    for i in items:
        c = QTextCursor(cursor.document())
        c.setPosition(i.end)
        positions.append(c)
    return positions
Beispiel #3
0
 def setLine(self, line):
     cursor = QTextCursor(self.document())
     cursor.movePosition(QTextCursor.End)
     cursor.setPosition(self.newPromptPos, QTextCursor.KeepAnchor)
     cursor.removeSelectedText()
     cursor.insertText(line)
     self.setTextCursor(cursor)
Beispiel #4
0
def articulation_positions(cursor):
    """Returns a list of positions where an articulation can be added.
    
    Every position is given as a QTextCursor instance.
    If the cursor has a selection, all positions in the selection are returned.
    
    """
    c = lydocument.cursor(cursor)
    if not cursor.hasSelection():
        # just select until the end of the current line
        c.select_end_of_block()
        rests = True
        partial = ly.document.OUTSIDE
    else:
        rests = False
        partial = ly.document.INSIDE
    
    positions = []
    for item in ly.rhythm.music_items(c, partial):
        if not rests and item.tokens and isinstance(item.tokens[0], ly.lex.lilypond.Rest):
            continue
        csr = QTextCursor(cursor.document())
        csr.setPosition(item.end)
        positions.append(csr)
        if not cursor.hasSelection():
            break # leave if first found, that's enough
    return positions
def show(cursor, pos=None, num_lines=6):
    """Displays a tooltip showing part of the cursor's Document.
    
    If the cursor has a selection, those blocks are displayed.
    Otherwise, num_lines lines are displayed.
    
    If pos is not given, the global mouse position is used.
    
    """
    block = cursor.document().findBlock(cursor.selectionStart())
    c2 = QTextCursor(block)
    if cursor.hasSelection():
        c2.setPosition(cursor.selectionEnd(), QTextCursor.KeepAnchor)
        c2.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
    else:
        c2.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor, num_lines)
    
    data = textformats.formatData('editor')
    
    doc = QTextDocument()
    font = QFont(data.font)
    font.setPointSizeF(font.pointSizeF() * .8)
    doc.setDefaultFont(font)
    doc.setPlainText(c2.selection().toPlainText())
    if metainfo.info(cursor.document()).highlighting:
        highlighter.highlight(doc, state=tokeniter.state(block))
    size = doc.size().toSize() + QSize(8, -4)
    pix = QPixmap(size)
    pix.fill(data.baseColors['background'])
    doc.drawContents(QPainter(pix))
    label = QLabel()
    label.setPixmap(pix)
    label.setStyleSheet("QLabel { border: 1px solid #777; }")
    label.resize(size)
    widgets.customtooltip.show(label, pos)
Beispiel #6
0
 def actionTriggered(self, name):
     # convert arpeggio_normal to arpeggioNormal, etc.
     name = _arpeggioTypes[name]
     cursor = self.mainwindow().textCursor()
     # which arpeggio type is last used?
     lastused = '\\arpeggioNormal'
     types = set(_arpeggioTypes.values())
     block = cursor.block()
     while block.isValid():
         s = types.intersection(tokeniter.tokens(block))
         if s:
             lastused = s.pop()
             break
         block = block.previous()
     # where to insert
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     with cursortools.compress_undo(cursor):
         for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE):
             c = QTextCursor(cursor.document())
             c.setPosition(item.end)
             c.insertText('\\arpeggio')
             if name != lastused:
                 cursortools.strip_indent(c)
                 indent = c.block().text()[:c.position() -
                                           c.block().position()]
                 c.insertText(name + '\n' + indent)
             # just pick the first place
             return
Beispiel #7
0
def spanner_positions(cursor):
    """Return a list with 0 to 2 QTextCursor instances.
    
    At the first cursor a starting spanner item can be inserted, at the
    second an ending item.
    
    """
    c = lydocument.cursor(cursor)
    if cursor.hasSelection():
        partial = ly.document.INSIDE
    else:
        # just select until the end of the current line
        c.select_end_of_block()
        partial = ly.document.OUTSIDE

    items = list(ly.rhythm.music_items(c, partial=partial))
    if cursor.hasSelection():
        del items[1:-1]
    else:
        del items[2:]

    positions = []
    for i in items:
        c = QTextCursor(cursor.document())
        c.setPosition(i.end)
        positions.append(c)
    return positions
Beispiel #8
0
 def cursor(self):
     """Return a QTextCursor with the same selection."""
     c = QTextCursor(self.document.document)
     c.movePosition(QTextCursor.End) if self.end is None else c.setPosition(
         self.end)
     c.setPosition(self.start, QTextCursor.KeepAnchor)
     return c
 def setLine(self, line):
     cursor = QTextCursor(self.document())
     cursor.movePosition(QTextCursor.End)
     cursor.setPosition(self.newPromptPos, QTextCursor.KeepAnchor)
     cursor.removeSelectedText()
     cursor.insertText(line)
     self.setTextCursor(cursor)
 def get_tooltip(self, pos):
   cursor_pos = self.document().documentLayout().hitTest(QtCore.QPointF(pos), Qt.Qt.ExactHit)
   
   if cursor_pos == -1:
     return "", QRect()
   
   cursor   = QTextCursor(self.document())
   cursor.setPosition(cursor_pos)
   col      = cursor.positionInBlock()
   line     = cursor.blockNumber()
   
   tooltip = ""
   rect    = QRect()
   
   if line >= len(self.highlighter.matches):
     return "", QRect()
   
   match_start = 0
   match_len   = 0
   
   matches     = 0
   
   #for word in self.highlighter.matches[line]:
     #if col >= word[1] and col < word[2]:
   for word in self.words_at_pos(line, col):
     keyword     = word[0]
     
     # Go for the smallest region possible so we can update
     # as soon as the mouse falls out of range of one of the words.
     if word[1] > match_start:
       match_start = word[1]
     
     if word[2] - word[1] < match_len:
       match_len = word[2] - word[1]
     
     if matches > 0:
       tooltip += u"\n"
     
     if not keyword.section == "":
       tooltip += u"【%s】 " % keyword.section
     
     tooltip += u"%s ― %s" % (keyword.word, keyword.meaning)
     
     matches += 1
   
   # Highlight our word, so we can get the rect.
   cursor.movePosition(QTextCursor.Start)
   
   for i in range(line):
     cursor.movePosition(QTextCursor.NextBlock)
   
   for i in range(match_start):
     cursor.movePosition(QTextCursor.NextCharacter)
   
   for i in range(match_len):
     cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor)
   
   rect = self.cursorRect(cursor)
   
   return tooltip, rect
Beispiel #11
0
    def cursors(self):
        """Cursors for rectangular selection.
        1 cursor for every line
        """
        cursors = []
        if self._start is not None:
            startLine, startVisibleCol = self._start
            currentLine, currentCol = self._qpart.cursorPosition
            if abs(startLine - currentLine) > self._MAX_SIZE or \
               abs(startVisibleCol - currentCol) > self._MAX_SIZE:
                # Too big rectangular selection freezes the GUI
                self._qpart.userWarning.emit('Rectangular selection area is too big')
                self._start = None
                return []

            currentBlockText = self._qpart.textCursor().block().text()
            currentVisibleCol = self._realToVisibleColumn(currentBlockText, currentCol)

            for lineNumber in range(min(startLine, currentLine),
                                    max(startLine, currentLine) + 1):
                block = self._qpart.document().findBlockByNumber(lineNumber)
                cursor = QTextCursor(block)
                realStartCol = self._visibleToRealColumn(block.text(), startVisibleCol)
                realCurrentCol = self._visibleToRealColumn(block.text(), currentVisibleCol)
                if realStartCol is None:
                    realStartCol = block.length()  # out of range value
                if realCurrentCol is None:
                    realCurrentCol = block.length()  # out of range value

                cursor.setPosition(cursor.block().position() + min(realStartCol, block.length() - 1))
                cursor.setPosition(cursor.block().position() + min(realCurrentCol, block.length() - 1),
                                   QTextCursor.KeepAnchor)
                cursors.append(cursor)

        return cursors
Beispiel #12
0
 def _makeQtExtraSelection(startAbsolutePosition, length):
     selection = QTextEdit.ExtraSelection()
     cursor = QTextCursor(self.document())
     cursor.setPosition(startAbsolutePosition)
     cursor.setPosition(startAbsolutePosition + length, QTextCursor.KeepAnchor)
     selection.cursor = cursor
     selection.format = self._userExtraSelectionFormat
     return selection
Beispiel #13
0
def goto_target(mainwindow, target):
    """Switch to the document and location where the node target is."""
    filename = target.document.filename
    doc = app.openUrl(QUrl.fromLocalFile(filename))
    cursor = QTextCursor(doc)
    cursor.setPosition(target.position)
    browseriface.get(mainwindow).setTextCursor(cursor)
    mainwindow.currentView().centerCursor()
Beispiel #14
0
def goto_target(mainwindow, target):
    """Switch to the document and location where the node target is."""
    filename = target.document.filename
    doc = app.openUrl(QUrl.fromLocalFile(filename))
    cursor = QTextCursor(doc)
    cursor.setPosition(target.position)
    browseriface.get(mainwindow).setTextCursor(cursor)
    mainwindow.currentView().centerCursor()
Beispiel #15
0
    def formatMatchedText(self, document, match):
        """Format the matched text in a document"""

        cursor = QTextCursor(document)
        cursor.setPosition(match.start())
        cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor,
                            match.end() - match.start())
        cursor.setCharFormat(self.matchFormat)
Beispiel #16
0
def main():
    """Main function."""
    options, files = parse_commandline()
    urls = list(map(url, files))
    
    if not app.qApp.isSessionRestored():
        if not options.new and remote.enabled():
            api = remote.get()
            if api:
                api.command_line(options, urls)
                api.close()
                sys.exit(0)
    
        if QSettings().value("splash_screen", True) not in ("false", False):
            import splashscreen
            splashscreen.show()

    QTimer.singleShot(0, remote.setup)  # Start listening for IPC
    
    import mainwindow       # contains MainWindow class
    import session          # Initialize QSessionManager support
    import sessions         # Initialize our own named session support
    import document         # contains Document class

    # boot Frescobaldi-specific stuff that should be running on startup
    import viewhighlighter  # highlight arbitrary ranges in text
    import matcher          # matches braces etc in active text window
    import progress         # creates progress bar in view space
    import autocomplete     # auto-complete input
    
    if app.qApp.isSessionRestored():
        # Restore session, we are started by the session manager
        session.restoreSession()
        return

    # load specified session
    doc = None
    if options.session and options.session != "none":
        doc = sessions.loadSession(options.session)
        
    # Just create one MainWindow
    win = mainwindow.MainWindow()
    win.show()
    
    if urls:
        for u in urls:
            doc = win.openUrl(u, options.encoding)
    elif not options.session:
        # no docs, load default session
        doc = sessions.loadDefaultSession()
    win.setCurrentDocument(doc or document.Document())
    if urls and options.line is not None:
        # set the last loaded document active and apply navigation if requested
        pos = doc.findBlockByNumber(options.line - 1).position() + options.column
        cursor = QTextCursor(doc)
        cursor.setPosition(pos)
        win.currentView().setTextCursor(cursor)
        win.currentView().centerCursor()
Beispiel #17
0
 def _selectLines(self, startBlockNumber, endBlockNumber):
     """Select whole lines
     """
     startBlock = self.document().findBlockByNumber(startBlockNumber)
     endBlock = self.document().findBlockByNumber(endBlockNumber)
     cursor = QTextCursor(startBlock)
     cursor.setPosition(endBlock.position(), QTextCursor.KeepAnchor)
     cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
     self.setTextCursor(cursor)
Beispiel #18
0
 def _makeQtExtraSelection(startAbsolutePosition, length):
     selection = QTextEdit.ExtraSelection()
     cursor = QTextCursor(self.document())
     cursor.setPosition(startAbsolutePosition)
     cursor.setPosition(startAbsolutePosition + length,
                        QTextCursor.KeepAnchor)
     selection.cursor = cursor
     selection.format = self._userExtraSelectionFormat
     return selection
Beispiel #19
0
 def _selectLines(self, startBlockNumber, endBlockNumber):
     """Select whole lines
     """
     startBlock = self.document().findBlockByNumber(startBlockNumber)
     endBlock = self.document().findBlockByNumber(endBlockNumber)
     cursor = QTextCursor(startBlock)
     cursor.setPosition(endBlock.position(), QTextCursor.KeepAnchor)
     cursor.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
     self.setTextCursor(cursor)
Beispiel #20
0
 def decorator(cursor):
     remove = list(func(cursor))
     if remove:
         c = QTextCursor(cursor)
         with cursortools.compress_undo(c):
             for start, end in sorted(remove, reverse=True):
                 c.setPosition(start)
                 c.setPosition(end, QTextCursor.KeepAnchor)
                 c.removeSelectedText()
Beispiel #21
0
	def select_range(self, s, e):
		cursor = QTextCursor(self)

		spos = self.findBlockByLineNumber(s[0] - 1).position() + s[1]
		epos = self.findBlockByLineNumber(e[0] - 1).position() + e[1]
		cursor.setPosition(spos, QTextCursor.MoveAnchor)
		cursor.setPosition(epos, QTextCursor.KeepAnchor)

		return cursor
Beispiel #22
0
def insert_python(text, cursor, name, view):
    """Regards the text as Python code, and exec it.
    
    name and view are given in case an exception occurs.
    
    The following variables are available:
    
    - text: contains selection or '', set it to insert new text
    - state: contains simplestate for the cursor position
    - cursor: the QTextCursor

    After the insert, the cursor points to the end of the inserted snippet.
    
    """
    namespace = {
        'cursor': QTextCursor(cursor),
        'state': state(cursor),
        'text': cursor.selection().toPlainText(),
        'view': view,
        'ANCHOR': 1,
        'CURSOR': 2,
    }
    try:
        code = compile(text, "<snippet>", "exec")
        if sys.version_info < (3, 0):
            exec("exec code in namespace")
        else:
            exec(code, namespace)
        if 'main' in namespace:
            return namespace['main']()
    except Exception:
        handle_exception(name, view)
    else:
        text = namespace.get('text', '')
        if isinstance(text, (tuple, list)):
            ANCHOR = namespace.get('ANCHOR', 1)
            CURSOR = namespace.get('CURSOR', 2)
            a, c = -1, -1
            for t in text:
                if t == ANCHOR:
                    a = cursor.selectionStart()
                elif t == CURSOR:
                    c = cursor.selectionStart()
                else:
                    cursor.insertText(t)
            if (a, c) != (-1, -1):
                new = QTextCursor(cursor)
                if a != -1:
                    new.setPosition(a)
                if c != -1:
                    new.setPosition(
                        c, QTextCursor.KeepAnchor
                        if a != -1 else QTextCursor.MoveAnchor)
                return new
        else:
            cursor.insertText(namespace['text'])
Beispiel #23
0
def startmain():
    import optparse
    optparse._ = _ # let optparse use our translations
    parser = optparse.OptionParser(
        usage = _("{appname} [options] file ...").format(appname=info.name),
        version = "{0} {1}".format(info.appname, info.version),
        description = _("A LilyPond Music Editor"))
    parser.add_option('-e', '--encoding', metavar=_("ENC"),
        help=_("Encoding to use"))
    parser.add_option('-l', '--line', type="int", metavar=_("NUM"),
        help=_("Line number to go to, starting at 1"))
    parser.add_option('-c', '--column', type="int", metavar=_("NUM"),
        help=_("Column to go to, starting at 0"), default=0)
    parser.add_option('--start', metavar=_("NAME"),
        help=_("Session to start ('{none}' for empty session)").format(none="none"),
        dest="session")

    args = QApplication.arguments()
    if os.name == 'nt' and args and 'python' in os.path.basename(args[0]).lower():
        args = args[2:]
    else:
        args = args[1:]
    options, files = parser.parse_args(args)

    # load specified session
    doc = None
    if options.session and options.session != "none":
        doc = sessions.loadSession(options.session)
        
    # Just create one MainWindow
    win = mainwindow.MainWindow()
    win.show()
    
    if files:
        # make urls
        for arg in files:
            if re.match(r'^(https?|s?ftp)://', arg):
                url = QUrl(arg)
            elif arg.startswith('file://'):
                url = QUrl.fromLocalFile(arg[7:])
            elif arg.startswith('file:'):
                url = QUrl.fromLocalFile(os.path.abspath(arg[5:]))
            else:
                url = QUrl.fromLocalFile(os.path.abspath(arg))
            doc = win.openUrl(url, options.encoding)
    elif not options.session:
        # no docs, load default session
        doc = sessions.loadDefaultSession()
    win.setCurrentDocument(doc or document.Document())
    if files and options.line is not None:
        # set the last loaded document active and apply navigation if requested
        pos = doc.findBlockByNumber(options.line - 1).position() + options.column
        cursor = QTextCursor(doc)
        cursor.setPosition(pos)
        win.currentView().setTextCursor(cursor)
        win.currentView().centerCursor()
Beispiel #24
0
 def save(self):
     """Called to perform the edits in the document."""
     cursor = QTextCursor(self._range)
     start = cursor.selectionStart()
     # use cursordiff; don't destroy point and click positions
     cursordiff.insert_text(cursor, self.view.toPlainText())
     cursor.setPosition(start, QTextCursor.KeepAnchor)
     with cursortools.compress_undo(cursor, True):
         # re-indent the inserted line(s)
         indent.re_indent(cursor)
Beispiel #25
0
 def save(self):
     """Called to perform the edits in the document."""
     cursor = QTextCursor(self._range)
     start = cursor.selectionStart()
     # use cursordiff; don't destroy point and click positions
     cursordiff.insert_text(cursor, self.view.toPlainText())
     cursor.setPosition(start, QTextCursor.KeepAnchor)
     with cursortools.compress_undo(cursor, True):
         # re-indent the inserted line(s)
         indent.re_indent(cursor)
Beispiel #26
0
    def formatMatchedText(self, document, match):
        """Format the matched text in a document"""

        cursor = QTextCursor(document)
        cursor.setPosition(match.start())
        cursor.movePosition(
            QTextCursor.NextCharacter,
            QTextCursor.KeepAnchor,
            match.end() - match.start())
        cursor.setCharFormat(self.matchFormat)
Beispiel #27
0
 def actionTriggered(self, name):
     name = name[8:]
     direction = ['_', '', '^'][self.direction() + 1]
     isSpanner = name not in dynamic_marks
     if isSpanner:
         dynamic = dynamic_spanners[name]
     else:
         dynamic = '\\' + name
     cursor = self.mainwindow().textCursor()
     if not cursor.hasSelection():
         # dynamic right before the cursor?
         left = tokeniter.partition(cursor).left
         if not left or not isinstance(left[-1], ly.lex.lilypond.Dynamic):
             # no, find the first pitch
             c = lydocument.cursor(cursor)
             c.end = None
             for item in ly.rhythm.music_items(c,
                                               partial=ly.document.OUTSIDE):
                 cursor.setPosition(item.end)
                 break
         cursor.insertText(direction + dynamic)
         self.mainwindow().currentView().setTextCursor(cursor)
     else:
         c = lydocument.cursor(cursor)
         cursors = []
         for item in ly.rhythm.music_items(c):
             csr = QTextCursor(cursor.document())
             csr.setPosition(item.end)
             cursors.append(csr)
         if not cursors:
             return
         c1, c2 = cursors[0], cursors[-1]
         # are there dynamics at the cursor? then skip them
         d1 = dynamics(c1)
         if d1:
             c1 = tokeniter.cursor(c1.block(), d1[-1], start=len(d1[-1]))
         with cursortools.compress_undo(cursor):
             if len(cursors) > 1:
                 # dynamics after the end cursor?
                 d2 = dynamics(c2)
                 if isSpanner and not d2:
                     # don't terminate the spanner if there's a dynamic there
                     c2.insertText('\\!')
                 elif set(d1).intersection(dynamic_spanners.values()):
                     # write the dynamic at the end if there's a spanner at start
                     # remove ending \! if there
                     terminator = tokeniter.find("\\!", d2)
                     if terminator:
                         c2 = tokeniter.cursor(c2.block(), terminator)
                     if direction in d1:
                         c2.insertText(dynamic)
                     else:
                         c2.insertText(direction + dynamic)
                     return
             c1.insertText(direction + dynamic)
Beispiel #28
0
def insert_python(text, cursor, name, view):
    """Regards the text as Python code, and exec it.
    
    name and view are given in case an exception occurs.
    
    The following variables are available:
    
    - text: contains selection or '', set it to insert new text
    - state: contains simplestate for the cursor position
    - cursor: the QTextCursor

    After the insert, the cursor points to the end of the inserted snippet.
    
    """
    namespace = {
        'cursor': QTextCursor(cursor),
        'state': state(cursor),
        'text': cursor.selection().toPlainText(),
        'view': view,
        'ANCHOR': 1,
        'CURSOR': 2,
    }
    try:
        code = compile(text, "<snippet>", "exec")
        if sys.version_info < (3, 0):
            exec("exec code in namespace")
        else:
            exec(code, namespace)
        if 'main' in namespace:
            return namespace['main']()
    except Exception:
        handle_exception(name, view)
    else:
        text = namespace.get('text', '')
        if isinstance(text, (tuple, list)):
            ANCHOR = namespace.get('ANCHOR', 1)
            CURSOR = namespace.get('CURSOR', 2)
            a, c = -1, -1
            for t in text:
                if t == ANCHOR:
                    a = cursor.selectionStart()
                elif t == CURSOR:
                    c = cursor.selectionStart()
                else:
                    cursor.insertText(t)
            if (a, c) != (-1, -1):
                new = QTextCursor(cursor)
                if a != -1:
                    new.setPosition(a)
                if c != -1:
                    new.setPosition(c, QTextCursor.KeepAnchor if a != -1 else QTextCursor.MoveAnchor)
                return new
        else:
            cursor.insertText(namespace['text'])
Beispiel #29
0
 def cursorForItem(self, item):
     """Returns a cursor for the specified item.
     
     This method (as all others) assume that the item refers to the current
     Document.
     
     """
     doc = self.parent().mainwindow().currentDocument()
     cursor = QTextCursor(doc)
     cursor.setPosition(item.position)
     return cursor
Beispiel #30
0
 def cursorForItem(self, item):
     """Returns a cursor for the specified item.
     
     This method (as all others) assume that the item refers to the current
     Document.
     
     """
     doc = self.parent().mainwindow().currentDocument()
     cursor = QTextCursor(doc)
     cursor.setPosition(item.position)
     return cursor
Beispiel #31
0
 def actionTriggered(self, name):
     name = name[8:]
     direction = ['_', '', '^'][self.direction() + 1]
     isSpanner = name not in dynamic_marks
     if isSpanner:
         dynamic = dynamic_spanners[name]
     else:
         dynamic = '\\' + name
     cursor = self.mainwindow().textCursor()
     if not cursor.hasSelection():
         # dynamic right before the cursor?
         left = tokeniter.partition(cursor).left
         if not left or not isinstance(left[-1], ly.lex.lilypond.Dynamic):
             # no, find the first pitch
             c = lydocument.cursor(cursor)
             c.end = None
             for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE):
                 cursor.setPosition(item.end)
                 break
         cursor.insertText(direction + dynamic)
         self.mainwindow().currentView().setTextCursor(cursor)
     else:
         c = lydocument.cursor(cursor)
         cursors = []
         for item in ly.rhythm.music_items(c):
             csr = QTextCursor(cursor.document())
             csr.setPosition(item.end)
             cursors.append(csr)
         if not cursors:
             return
         c1, c2 = cursors[0], cursors[-1]
         # are there dynamics at the cursor? then skip them
         d1 = dynamics(c1)
         if d1:
             c1 = tokeniter.cursor(c1.block(), d1[-1], start=len(d1[-1]))
         with cursortools.compress_undo(cursor):
             if len(cursors) > 1:
                 # dynamics after the end cursor?
                 d2 = dynamics(c2)
                 if isSpanner and not d2:
                     # don't terminate the spanner if there's a dynamic there
                     c2.insertText('\\!')
                 elif set(d1).intersection(dynamic_spanners.values()):
                     # write the dynamic at the end if there's a spanner at start
                     # remove ending \! if there
                     terminator = tokeniter.find("\\!", d2)
                     if terminator:
                         c2 = tokeniter.cursor(c2.block(), terminator)
                     if direction in d1:
                         c2.insertText(dynamic)
                     else:
                         c2.insertText(direction + dynamic)
                     return
             c1.insertText(direction + dynamic)
Beispiel #32
0
 def __highlight(self, positions, color=None, cancel=False):
     cursor = QTextCursor(self.document())
     for position in positions:
         if position > self.get_position('eof'):
             return
         cursor.setPosition(position)
         cursor.movePosition(QTextCursor.NextCharacter,
                             QTextCursor.KeepAnchor)
         charformat = cursor.charFormat()
         pen = QPen(Qt.NoPen) if cancel else QPen(color)
         charformat.setTextOutline(pen)
         cursor.setCharFormat(charformat)
Beispiel #33
0
 def setTextCursor(self, cursor):
     """Reimplemented to show n surrounding lines."""
     numlines = QSettings().value("view_preferences/context_lines", 3, int)
     if numlines > 0:
         c = QTextCursor(cursor)
         c.setPosition(cursor.selectionEnd())
         c.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor, numlines)
         super(View, self).setTextCursor(c)
         c.setPosition(cursor.selectionStart())
         c.movePosition(QTextCursor.Up, QTextCursor.MoveAnchor, numlines)
         super(View, self).setTextCursor(c)
     super(View, self).setTextCursor(cursor)
Beispiel #34
0
def goto_target(mainwindow, target):
    """Switch to the document and location where the node target is."""
    lydoc = target.document
    try:
        # this succeeds if this is a document that is currently open
        doc = lydoc.document
    except AttributeError:
        # it is an included file, just load it
        filename = target.document.filename
        doc = app.openUrl(QUrl.fromLocalFile(filename))
    cursor = QTextCursor(doc)
    cursor.setPosition(target.position)
    browseriface.get(mainwindow).setTextCursor(cursor)
    mainwindow.currentView().centerCursor()
Beispiel #35
0
 def actionTriggered(self, name):
     cursor = self.mainwindow().textCursor()
     style = _glissandoStyles[name]
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE):
         c = QTextCursor(cursor.document())
         c.setPosition(item.end)
         if style:
             text = "-\\tweak #'style #'{0} \\glissando".format(style)
         else:
             text = '\\glissando'
         c.insertText(text)
         return
Beispiel #36
0
 def actionTriggered(self, name):
     cursor = self.mainwindow().textCursor()
     style = _glissandoStyles[name]
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     for item in ly.rhythm.music_items(c, partial=ly.document.OUTSIDE):
         c = QTextCursor(cursor.document())
         c.setPosition(item.end)
         if style:
             text = "-\\tweak #'style #'{0} \\glissando".format(style)
         else:
             text = '\\glissando'
         c.insertText(text)
         return
Beispiel #37
0
    def selectedPosition(self, pos):
        anchorPos, cursorPos = pos
        anchorLine, anchorCol = anchorPos
        cursorLine, cursorCol = cursorPos

        anchorCursor = QTextCursor(self.document().findBlockByNumber(anchorLine))
        anchorCursor.setPositionInBlock(anchorCol)

        # just get absolute position
        cursor = QTextCursor(self.document().findBlockByNumber(cursorLine))
        cursor.setPositionInBlock(cursorCol)

        anchorCursor.setPosition(cursor.position(), QTextCursor.KeepAnchor)
        self.setTextCursor(anchorCursor)
Beispiel #38
0
    def selectedPosition(self, pos):
        anchorPos, cursorPos = pos
        anchorLine, anchorCol = anchorPos
        cursorLine, cursorCol = cursorPos

        anchorCursor = QTextCursor(
            self.document().findBlockByNumber(anchorLine))
        setPositionInBlock(anchorCursor, anchorCol)

        # just get absolute position
        cursor = QTextCursor(self.document().findBlockByNumber(cursorLine))
        setPositionInBlock(cursor, cursorCol)

        anchorCursor.setPosition(cursor.position(), QTextCursor.KeepAnchor)
        self.setTextCursor(anchorCursor)
Beispiel #39
0
 def cursor(self, start=0, end=None):
     """Returns a QTextCursor for the last token.
     
     If start is given the cursor will start at position start in the token
     (from the beginning of the token). Start defaults to 0.
     If end is given, the cursor will end at that position in the token (from
     the beginning of the token). End defaults to the length of the token.
     
     """
     if end is None:
         end = len(self.token())
     c = QTextCursor(self.document.document)
     c.setPosition(self.position() + start)
     c.setPosition(self.position() + end, QTextCursor.KeepAnchor)
     return c
Beispiel #40
0
 def apply_changes(self):
     """Apply the changes and update the tokens."""
     c = QTextCursor(self._d)
     # record a sensible position for undo
     c.setPosition(self._changes_list[-1][0])
     c.joinPreviousEditBlock() if self.combine_undo else c.beginEditBlock()
     try:
         for start, end, text in self._changes_list:
             c.movePosition(QTextCursor.End) if end is None else c.setPosition(end)
             c.setPosition(start, QTextCursor.KeepAnchor)
             c.insertText(text)
     finally:
         c.endEditBlock()
         if self.combine_undo is None:
             self.combine_undo = True
Beispiel #41
0
def cursor(block, token, start=0, end=None):
    """Returns a QTextCursor for the given token in the given block.
    
    If start is given the cursor will start at position start in the token
    (from the beginning of the token). Start defaults to 0.
    If end is given, the cursor will end at that position in the token (from
    the beginning of the token). End defaults to the length of the token.
    
    """
    if end is None:
        end = len(token)
    cursor = QTextCursor(block)
    cursor.setPosition(block.position() + token.pos + start)
    cursor.setPosition(block.position() + token.pos + end, QTextCursor.KeepAnchor)
    return cursor
Beispiel #42
0
 def cursor(self, start=0, end=None):
     """Returns a QTextCursor for the last token.
     
     If start is given the cursor will start at position start in the token
     (from the beginning of the token). Start defaults to 0.
     If end is given, the cursor will end at that position in the token (from
     the beginning of the token). End defaults to the length of the token.
     
     """
     if end is None:
         end = len(self.token())
     c = QTextCursor(self.document.document)
     c.setPosition(self.position() + start)
     c.setPosition(self.position() + end, QTextCursor.KeepAnchor)
     return c
Beispiel #43
0
def preceding(cursor):
    """Returns a preceding duration before the cursor, or an empty list."""
    c = QTextCursor(cursor)
    c.setPosition(cursor.selectionStart())
    for tokens in back(c):
        for t in tokens:
            if isinstance(t, ly.lex.lilypond.Duration):
                l = [t]
                for t in tokens:
                    if isinstance(t, ly.lex.lilypond.Duration):
                        l.append(t)
                    elif not isinstance(t, ly.lex.Space):
                        break
                l.reverse()
                return l
    return []
Beispiel #44
0
def cursor(block, token, start=0, end=None):
    """Returns a QTextCursor for the given token in the given block.
    
    If start is given the cursor will start at position start in the token
    (from the beginning of the token). Start defaults to 0.
    If end is given, the cursor will end at that position in the token (from
    the beginning of the token). End defaults to the length of the token.
    
    """
    if end is None:
        end = len(token)
    cursor = QTextCursor(block)
    cursor.setPosition(block.position() + token.pos + start)
    cursor.setPosition(block.position() + token.pos + end,
                       QTextCursor.KeepAnchor)
    return cursor
Beispiel #45
0
 def apply_changes(self):
     """Apply the changes and update the tokens."""
     c = QTextCursor(self._d)
     # record a sensible position for undo
     c.setPosition(self._changes_list[-1][0])
     c.joinPreviousEditBlock() if self.combine_undo else c.beginEditBlock()
     try:
         for start, end, text in self._changes_list:
             c.movePosition(
                 QTextCursor.End) if end is None else c.setPosition(end)
             c.setPosition(start, QTextCursor.KeepAnchor)
             c.insertText(text)
     finally:
         c.endEditBlock()
         if self.combine_undo is None:
             self.combine_undo = True
Beispiel #46
0
    def notify(self, text, textHighlight=None):
        # highlightRange is range in passed text.
        length = len(self.notifyBox.toPlainText())
        self.notifyBox.append(text)
        self.notifyBox.verticalScrollBar().setValue(
            self.notifyBox.verticalScrollBar().maximum())

        if textHighlight != None:
            begin = length + text.find(textHighlight) + 1
            end = begin + len(textHighlight)
            fmt = QTextCharFormat()
            col = QColor(Qt.red)
            col.setAlpha(130)
            fmt.setBackground(col)
            cursor = QTextCursor(self.notifyBox.document())
            cursor.setPosition(begin)
            cursor.setPosition(end, QTextCursor.KeepAnchor)
            cursor.setCharFormat(fmt)
Beispiel #47
0
def insert_snippet(text, cursor, variables):
    """Inserts a normal text snippet.
    
    After the insert, the cursor points to the end of the inserted snippet.
    
    If this function returns a cursor it must be set as the cursor for the view
    after the snippet has been inserted.
    
    """
    exp_base = expand.Expander(cursor)
    
    evs = [] # make a list of events, either text or a constant
    for text, key in snippets.expand(text):
        if text:
            evs.append(text)
        if key == '$':
            evs.append('$')
        elif key:
            # basic variables
            func = getattr(exp_base, key, None)
            if func:
                evs.append(func())
    
    selectionUsed = expand.SELECTION in evs
    # do the padding if 'selection: strip;' is used
    if selectionUsed and 'strip' in variables.get('selection', ''):
        space = '\n' if '\n' in cursor.selection().toPlainText() else ' '
        # change whitespace in previous and next piece of text
        i = evs.index(expand.SELECTION)
        for j in range(i-1, -i, -1):
            if evs[j] not in expand.constants:
                evs[j] = evs[j].rstrip() + space
                break
        for j in range(i+1, len(evs)):
            if evs[j] not in expand.constants:
                evs[j] = space + evs[j].lstrip()
                break
    # now insert the text
    ins = QTextCursor(cursor)
    selectionUsed and ins.setPosition(cursor.selectionStart())
    a, c = -1, -1
    for e in evs:
        if e == expand.ANCHOR:
            a = ins.position()
        elif e == expand.CURSOR:
            c = ins.position()
        elif e == expand.SELECTION:
            ins.setPosition(cursor.selectionEnd())
        else:
            ins.insertText(e)
    cursor.setPosition(ins.position())
    # return a new cursor if requested
    if (a, c) != (-1, -1):
        new = QTextCursor(cursor)
        if a != -1:
            new.setPosition(a)
        if c != -1:
            new.setPosition(c, QTextCursor.KeepAnchor if a != -1 else QTextCursor.MoveAnchor)
        return new
Beispiel #48
0
def insert_snippet(text, cursor, variables):
    """Inserts a normal text snippet.
    
    After the insert, the cursor points to the end of the inserted snippet.
    
    If this function returns a cursor it must be set as the cursor for the view
    after the snippet has been inserted.
    
    """
    exp_base = expand.Expander(cursor)
    
    evs = [] # make a list of events, either text or a constant
    for text, key in snippets.expand(text):
        if text:
            evs.append(text)
        if key == '$':
            evs.append('$')
        elif key:
            # basic variables
            func = getattr(exp_base, key, None)
            if func:
                evs.append(func())
    
    selectionUsed = expand.SELECTION in evs
    # do the padding if 'selection: strip;' is used
    if selectionUsed and 'strip' in variables.get('selection', ''):
        space = '\n' if '\n' in cursor.selection().toPlainText() else ' '
        # change whitespace in previous and next piece of text
        i = evs.index(expand.SELECTION)
        for j in range(i-1, -i, -1):
            if evs[j] not in expand.constants:
                evs[j] = evs[j].rstrip() + space
                break
        for j in range(i+1, len(evs)):
            if evs[j] not in expand.constants:
                evs[j] = space + evs[j].lstrip()
                break
    # now insert the text
    ins = QTextCursor(cursor)
    selectionUsed and ins.setPosition(cursor.selectionStart())
    a, c = -1, -1
    for e in evs:
        if e == expand.ANCHOR:
            a = ins.position()
        elif e == expand.CURSOR:
            c = ins.position()
        elif e == expand.SELECTION:
            ins.setPosition(cursor.selectionEnd())
        else:
            ins.insertText(e)
    cursor.setPosition(ins.position())
    # return a new cursor if requested
    if (a, c) != (-1, -1):
        new = QTextCursor(cursor)
        if a != -1:
            new.setPosition(a)
        if c != -1:
            new.setPosition(c, QTextCursor.KeepAnchor if a != -1 else QTextCursor.MoveAnchor)
        return new
Beispiel #49
0
 def gotoTextCursor(self, cursor, numlines=3):
     """Go to the specified cursor.
     
     If possible, at least numlines (default: 3) number of surrounding lines
     is shown. The number of surrounding lines can also be set in the
     preferences, under the key "view_preferences/context_lines". This
     setting takes precedence.
     
     """
     numlines = QSettings().value("view_preferences/context_lines", numlines, int)
     if numlines > 0:
         c = QTextCursor(cursor)
         c.setPosition(cursor.selectionEnd())
         c.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor, numlines)
         self.setTextCursor(c)
         c.setPosition(cursor.selectionStart())
         c.movePosition(QTextCursor.Up, QTextCursor.MoveAnchor, numlines)
         self.setTextCursor(c)
     self.setTextCursor(cursor)
Beispiel #50
0
 def keyPressEvent(self, event):
     #pqMsgs.printKeyEvent(event)
     kkey = int(int(event.modifiers()) & IMC.keypadDeModifier) | int(
         event.key())
     # add as little overhead as possible: if it isn't ours, pass it on.
     if kkey in IMC.keysOfInterest:  # we trust python to do this quickly
         event.accept()  # we handle this one
         if kkey in IMC.findKeys:
             # ^f, ^g, etc. -- just pass them straight to the Find panel
             self.emit(SIGNAL("editKeyPress"), kkey)
         elif kkey in IMC.zoomKeys:
             # n.b. the self.font and setFont methods inherit from QWidget
             # Point increment by which to change.
             n = (-1) if (kkey == IMC.ctl_minus) else 1
             # Actual point size currently in use, plus increment
             p = self.fontInfo().pointSize() + n
             if (p > 3) and (p < 65):  # don't let's get ridiculous, hmm?
                 # Simply calling self.font().setPointSize() had no effect,
                 # we have to actually call setFont() to make change happen.
                 f = self.font()  # so get our font,
                 f.setPointSize(p)  # change its point size +/-
                 self.setFont(f)  # and put the font back
                 IMC.fontSize = p  # and remember the size for shutdown time
         elif kkey in IMC.markKeys:  # ^1-9, jump to bookmark
             bkn = kkey - IMC.ctl_1  # make it 0-8
             if self.bookMarkList[
                     bkn] is not None:  # if that bookmark is set,
                 self.setTextCursor(self.bookMarkList[bkn])  # jump to it
         elif kkey in IMC.markShiftKeys:  # shift-ctl-1/9, select to mark
             # Make our document cursor's selection go from our current ANCHOR
             # to the POSITION from the bookmark cursor.
             mark_tc = self.bookMarkList[kkey - IMC.ctl_shft_1]
             if mark_tc is not None:
                 tc = QTextCursor(self.textCursor())
                 tc.setPosition(mark_tc.position(), QTextCursor.KeepAnchor)
                 self.setTextCursor(tc)
         elif kkey in IMC.markSetKeys:  # ctl-alt-1-9, set a bookmark
             bkn = kkey - IMC.ctl_alt_1  # make it 0-8
             self.bookMarkList[bkn] = QTextCursor(self.textCursor())
             IMC.needMetadataSave |= IMC.bookmarksChanged
     else:  # not in keysOfInterest, so pass it up to parent
         event.ignore()
         super(PPTextEditor, self).keyPressEvent(event)
Beispiel #51
0
 def centerCursor(self):
     tc = QTextCursor(
         self.textCursor())  # copy the working cursor with its selection
     top_point = tc.position()  # one end of selection, in character units
     bot_point = tc.anchor()  # ..and the other end
     if top_point > bot_point:  # often the position is > the anchor
         (top_point, bot_point) = (bot_point, top_point)
     tc.setPosition(top_point)  # cursor for the top of the selection
     selection_top = self.cursorRect(tc).top()  # ..get its top pixel
     line_height = self.cursorRect(
         tc).height()  # and save height of one line
     tc.setPosition(bot_point)  # cursor for the end of the selection
     selection_bot = self.cursorRect(
         tc).bottom()  # ..selection's bottom pixel
     selection_height = selection_bot - selection_top + 1  # selection height in pixels
     view_height = self.viewport().geometry().height(
     )  # scrolled area's height in px
     view_half = view_height >> 1  # int(view_height/2)
     pixel_adjustment = 0
     if selection_height < view_half:
         # selected text is less than half the window height: center the top of the
         # selection, i.e., make the cursor_top equal to view_half.
         pixel_adjustment = selection_top - view_half  # may be negative
     else:
         # selected text is taller than half the window, can we show it all?
         if selection_height < (view_height - line_height):
             # all selected text fits in the viewport (with a little free): center it.
             pixel_adjustment = (selection_top +
                                 (selection_height / 2)) - view_half
         else:
             # not all selected text fits the window, put text top near window top
             pixel_adjustment = selection_top - line_height
     # OK, convert the pixel adjustment to a line-adjustment based on the assumption
     # that a scrollbar pageStep is the height of the viewport in lines.
     adjust_fraction = pixel_adjustment / view_height
     vscroller = self.verticalScrollBar()
     page_step = vscroller.pageStep(
     )  # lines in a viewport page, actually less 1
     adjust_lines = int(page_step * adjust_fraction)
     target = vscroller.value() + adjust_lines
     if (target >= 0) and (target <= vscroller.maximum()):
         vscroller.setValue(target)
Beispiel #52
0
    def replaceText(self, pos, length, text):
        """Replace length symbols from ``pos`` with new text.

        If ``pos`` is an integer, it is interpreted as absolute position, if a tuple - as ``(line, column)``
        """
        if isinstance(pos, tuple):
            pos = self.mapToAbsPosition(*pos)

        endPos = pos + length

        if not self.document().findBlock(pos).isValid():
            raise IndexError('Invalid start position %d' % pos)

        if not self.document().findBlock(endPos).isValid():
            raise IndexError('Invalid end position %d' % endPos)

        cursor = QTextCursor(self.document())
        cursor.setPosition(pos)
        cursor.setPosition(endPos, QTextCursor.KeepAnchor)

        cursor.insertText(text)
Beispiel #53
0
 def toLowerCase(self):
     global reWord  # the regex \b\w+\b
     tc = QTextCursor(self.textCursor())
     if not tc.hasSelection():
         return  # no selection, nothing to do
     startpos = tc.selectionStart()
     endpos = tc.selectionEnd()
     qs = QString(tc.selectedText())  # copy of selected text
     i = reWord.indexIn(qs, 0)  # index of first word if any
     if i < 0: return  # no words in selection, exit
     while i >= 0:
         w = reWord.cap(0)  # found word as QString
         n = w.size()  # its length
         qs.replace(i, n, w.toLower())  # replace it with UC version
         i = reWord.indexIn(qs, i + n)  # find next word if any
     # we have changed at least one word, replace selection with altered text
     tc.insertText(qs)
     # that wiped the selection, so restore it by "dragging" left to right
     tc.setPosition(startpos, QTextCursor.MoveAnchor)  # click
     tc.setPosition(endpos, QTextCursor.KeepAnchor)  # drag
     self.setTextCursor(tc)
Beispiel #54
0
def keep_selection(cursor, edit=None):
    """Performs operations inside the selection and restore the selection afterwards.
    
    If edit is given, call setTextCursor(cursor) on the Q(Plain)TextEdit afterwards.
    
    """
    start, end, pos = cursor.selectionStart(), cursor.selectionEnd(
    ), cursor.position()
    cur2 = QTextCursor(cursor)
    cur2.setPosition(end)

    try:
        yield
    finally:
        if pos == start:
            cursor.setPosition(cur2.position())
            cursor.setPosition(start, QTextCursor.KeepAnchor)
        else:
            cursor.setPosition(start)
            cursor.setPosition(cur2.position(), QTextCursor.KeepAnchor)
        if edit:
            edit.setTextCursor(cursor)
Beispiel #55
0
 def insertMarkers(self):
     # Copy the text and if it is empty, complain and exit.
     qi = QString(self.insertText.text())
     if qi.isEmpty():
         pqMsgs.warningMsg("No insert text specified")
         return
     # See how many pages are involved: all the ones that aren't marked skip
     n = 0
     for i in range(IMC.pageTable.size()):
         if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip:
             n += 1
     if n == 0:  # page table empty or all rows marked skip
         pqMsgs.warningMsg("No pages to give folios to")
         return
     m = "Insert this string at the top of {0} pages?".format(n)
     b = pqMsgs.okCancelMsg(QString(m), pqMsgs.trunc(qi, 35))
     if b:
         # Convert any '\n' in the text to the QT line delimiter char
         # we do this in the copy so the lineEdit text doesn't change
         qi.replace(QString(u'\\n'), QString(IMC.QtLineDelim))
         # get a cursor on the edit document
         tc = QTextCursor(IMC.editWidget.textCursor())
         tc.beginEditBlock()  # start single undoable operation
         # Working from the end of the document backward, go to the
         # top of each page and insert the string
         for i in reversed(range(IMC.pageTable.size())):
             if IMC.pageTable.getAction(i) != IMC.FolioRuleSkip:
                 # Note the page's start position and set our work cursor to it
                 pos = IMC.pageTable.getCursor(i).position()
                 tc.setPosition(pos)
                 # Make a copy of the insert string replacing %f with this folio
                 f = IMC.pageTable.getDisplay(i)
                 qf = QString(qi)
                 qf.replace(QString(u'%f'), f, Qt.CaseInsensitive)
                 tc.insertText(qf)
                 # The insertion goes in ahead of the saved cursor position so now
                 # it points after the inserted string. Put it back where it was.
                 IMC.pageTable.setPosition(i, pos)
         tc.endEditBlock()  # wrap up the undo op
Beispiel #56
0
def insert(name, view):
    """Insert named snippet into the view."""
    text, variables = snippets.get(name)
    cursor = view.textCursor()

    selection = variables.get('selection', '')
    if 'yes' in selection and not cursor.hasSelection():
        return
    if 'strip' in selection:
        cursortools.strip_selection(cursor)

    pos = cursor.selectionStart()
    with cursortools.compress_undo(cursor):

        # insert the snippet, might return a new cursor
        if 'python' in variables:
            new = insert_python(text, cursor, name, view)
        elif 'macro' in variables:
            new = insert_macro(text, view)
        else:
            new = insert_snippet(text, cursor, variables)

    # QTextBlocks the snippet starts and ends
    block = cursor.document().findBlock(pos)
    last = cursor.block()

    # re-indent if not explicitly suppressed by a 'indent: no' variable
    if last != block and 'no' not in variables.get('indent', ''):
        c = QTextCursor(last)
        c.setPosition(block.position(), QTextCursor.KeepAnchor)
        with cursortools.compress_undo(c, True):
            indent.re_indent(c, True)

    if not new and 'keep' in selection:
        end = cursor.position()
        cursor.setPosition(pos)
        cursor.setPosition(end, QTextCursor.KeepAnchor)
    view.setTextCursor(new or cursor)