Ejemplo n.º 1
0
def cut_assign(cursor):
    """Cuts selected text and assigns it to a LilyPond variable."""
    # ask the variable name
    name = inputdialog.getText(None, _("Cut and Assign"), _(
        "Please enter the name for the variable to assign the selected "
        "text to:"), regexp="[A-Za-z]+")
    if not name:
        return
    
    cursortools.strip_selection(cursor)
    
    # determine state at cursor
    block = cursortools.block(cursor)
    state = tokeniter.state(block)
    for t in tokeniter.partition(cursor).left:
        state.follow(t)
    
    mode = ""
    for p in state.parsers():
        if isinstance(p, ly.lex.lilypond.ParseInputMode):
            if isinstance(p, ly.lex.lilypond.ParseLyricMode):
                mode = " \\lyricmode"
            elif isinstance(p, ly.lex.lilypond.ParseChordMode):
                mode = " \\chordmode"
            elif isinstance(p, ly.lex.lilypond.ParseFigureMode):
                mode = " \\figuremode"
            elif isinstance(p, ly.lex.lilypond.ParseDrumMode):
                mode = " \\drummode"
            break

    # find insertion place:
    found = False
    while block.previous().isValid():
        block = block.previous()
        state = tokeniter.state(block)
        if isinstance(state.parser(), ly.lex.lilypond.ParseGlobal):
            found = True
            break
        tokens = tokeniter.tokens(block)
        for t in tokens:
            if isinstance(t, ly.lex.lilypond.Name):
                found = True
                break
            elif not isinstance(t, (ly.lex.Space, ly.lex.Comment)):
                break
        if found:
            break
    insert = QTextCursor(block)
    text = cursor.selection().toPlainText()
    space = '\n' if '\n' in text else ' '
    text = ''.join((name, ' =', mode, ' {', space, text, space, '}\n\n'))
    with cursortools.compress_undo(cursor):
        cursor.insertText('\\' + name)
        pos = insert.selectionStart()
        insert.insertText(text)
    if metainfo.info(cursor.document()).auto_indent:
        insert.setPosition(pos, QTextCursor.KeepAnchor)
        with cursortools.compress_undo(insert, True):
            indent.re_indent(insert)
Ejemplo n.º 2
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
Ejemplo n.º 3
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
     source = tokeniter.Source.from_cursor(cursor, True, -1)
     with cursortools.compress_undo(cursor):
         for p in music.music_items(source, tokens=source.tokens):
             c = source.cursor(p[-1], start=len(p[-1]))
             c.insertText('\\arpeggio')
             if name != lastused:
                 cursortools.strip_indent(c)
                 import indent
                 indent.insert_text(c, name + '\n')
             # just pick the first place
             return
Ejemplo n.º 4
0
def changeLanguage(cursor, language):
    """Changes the language of the pitch names."""
    selection = cursor.hasSelection()
    if selection:
        start = cursor.selectionStart()
        cursor.setPosition(cursor.selectionEnd())
        cursor.setPosition(0, QTextCursor.KeepAnchor)
        source = tokeniter.Source.selection(cursor)
    else:
        source = tokeniter.Source.document(cursor)
    
    pitches = PitchIterator(source)
    tokens = pitches.tokens()
    writer = ly.pitch.pitchWriter(language)
    
    if selection:
        # consume tokens before the selection, following the language
        source.consume(tokens, start)
    
    changed = False # track change of \language or \include language command
    with cursortools.compress_undo(cursor):
        try:
            with qutil.busyCursor():
                with cursortools.Editor() as e:
                    for t in tokens:
                        if isinstance(t, ly.lex.lilypond.Note):
                            # translate the pitch name
                            p = pitches.read(t)
                            if p:
                                n = writer(*p)
                                if n != t:
                                    e.insertText(source.cursor(t), n)
                        elif isinstance(t, LanguageName) and t != language:
                            # change the language name in a command
                            e.insertText(source.cursor(t), language)
                            changed = True
        except ly.pitch.PitchNameNotAvailable:
            QMessageBox.critical(None, app.caption(_("Pitch Name Language")), _(
                "Can't perform the requested translation.\n\n"
                "The music contains quarter-tone alterations, but "
                "those are not available in the pitch language \"{name}\"."
                ).format(name=language))
            return
        if changed:
            return
        if not selection:
            # there was no selection and no language command, so insert one
            insertLanguage(cursor.document(), language)
            return
    # there was a selection but no command, user must insert manually.
    QMessageBox.information(None, app.caption(_("Pitch Name Language")),
        '<p>{0}</p>'
        '<p><code>\\include "{1}.ly"</code> {2}</p>'
        '<p><code>\\language "{1}"</code> {3}</p>'.format(
            _("The pitch language of the selected text has been "
                "updated, but you need to manually add the following "
                "command to your document:"),
            language,
            _("(for LilyPond below 2.14), or"),
            _("(for LilyPond 2.14 and higher.)")))
Ejemplo n.º 5
0
def insert_text(cursor, text):
    """Replaces selected text of a QTextCursor.
    
    This is done without erasing all the other QTextCursor instances that could
    exist in the selected range. It works by making a diff between the
    existing selection and the replacement text, and applying that diff.
    
    """
    if not cursor.hasSelection() or text == "":
        cursor.insertText(text)
        return
    
    start = cursor.selectionStart()
    new_pos = start + len(text)
    
    old = cursor.selection().toPlainText()
    diff = difflib.SequenceMatcher(None, old, text).get_opcodes()
    
    # make a list of edits
    edits = sorted(
        ((start + i1, start + i2, text[j1:j2])
         for tag, i1, i2, j1, j2 in diff
         if tag != 'equal'),
        reverse = True)
    
    # perform the edits
    with cursortools.compress_undo(cursor):
        for pos, end, text in edits:
            cursor.setPosition(pos)
            cursor.setPosition(end, cursor.KeepAnchor)
            cursor.insertText(text)
    cursor.setPosition(new_pos)
Ejemplo n.º 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()
     source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
     with cursortools.compress_undo(cursor):
         for p in ly.rhythm.music_tokens(source):
             c = source.cursor(p[-1], start=len(p[-1]))
             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
Ejemplo n.º 7
0
def change_indent(cursor, direction):
    """Changes the indent in the desired direction (-1 for left and +1 for right).
    
    Returns True if the indent operation was applied.
    The cursor may contain a selection.
    
    """
    # get some variables from the document
    indent_vars = indent_variables(cursor.document())
    
    blocks = list(cursortools.blocks(cursor))
    block = blocks[0]
    pos = cursor.selectionStart() - block.position()
    token = tokeniter.tokens(block)[0] if tokeniter.tokens(block) else None
    if cursor.hasSelection() or pos == 0 or (token and isinstance(token, ly.lex.Space) and token.end >= pos):
        # decrease the indent
        state = tokeniter.state(block)
        current_indent = get_indent(block)
        new_indent = current_indent + direction * indent_vars['indent-width']
        if state.mode() in ('lilypond', 'scheme'):
            computed_indent = compute_indent(block)
            if cmp(computed_indent, new_indent) == direction:
                new_indent = computed_indent
        diff = new_indent - current_indent
        with cursortools.compress_undo(cursor):
            for block in blocks:
                set_indent(block, get_indent(block) + diff)
        return True
Ejemplo n.º 8
0
 def slotAccepted(self):
     """Makes the score and puts it in the editor."""
     from . import build
     builder = build.Builder(self)
     cursor = self.parent().currentView().textCursor()
     with cursortools.compress_undo(cursor):
         cursortools.insert_select(cursor, builder.text())
         indent.re_indent(cursor)
Ejemplo n.º 9
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()
Ejemplo n.º 10
0
def reformat(cursor):
    """Reformats the selection or the whole document, adjusting the whitespace."""
    def newlinebefore(t):
        editor.insertText(tokeniter.cursor(block, t, end=0), '\n')
    
    def newlineafter(t):
        editor.insertText(tokeniter.cursor(block, t, start=len(t)), '\n')
    
    indent_vars = indent.indent_variables(cursor.document())
    
    with cursortools.compress_undo(cursor):
        indent.re_indent(cursor)
        with cursortools.Editor() as editor:
            for block in get_blocks(cursor):
                
                denters = []
                tokens = tokeniter.tokens(block)
                
                nonspace_index = -1
                for i, t in enumerate(tokens):
                    if isinstance(t, ly.lex.Indent) and t in ('{', '<<'):
                        denters.append(i)
                    elif isinstance(t, ly.lex.Dedent) and t in ('}', '>>'):
                        if denters:
                            denters.pop()
                        elif nonspace_index != -1:
                            newlinebefore(t)
                    elif not isinstance(t, ly.lex.Space):
                        nonspace_index = i
                for i in denters:
                    if i < nonspace_index:
                        newlineafter(tokens[i])
                    
                # TODO: wrap long lines
        
        indent.re_indent(cursor)
        
        with cursortools.Editor() as editor:
            for block in get_blocks(cursor):
                tokens = tokeniter.tokens(block)
                if (len(tokens) == 2
                    and isinstance(tokens[0], ly.lex.Space)
                    and isinstance(tokens[1], (
                        ly.lex.lilypond.LineComment,
                        ly.lex.scheme.LineComment))
                    and len(tokens[1]) > 2
                    and len(set(tokens[1][:3])) == 1):
                    # move commented lines with more than 2 comment characters
                    # to column 0
                    editor.removeSelectedText(tokeniter.cursor(block, tokens[0]))
                else:
                    # remove trialing whitespace
                    for t in tokens[::-1]:
                        if isinstance(t, ly.lex.Space):
                            editor.removeSelectedText(tokeniter.cursor(block, t))
                        else:
                            break
Ejemplo n.º 11
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)
Ejemplo n.º 12
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)
Ejemplo n.º 13
0
 def slotAccepted(self):
     """Makes the score and puts it in the editor."""
     if self._createNewDocument:
         self.parent().setCurrentDocument(app.openUrl(QUrl()))
     from . import build
     builder = build.Builder(self)
     cursor = self.parent().currentView().textCursor()
     cursortools.insert_select(cursor, builder.text())
     with cursortools.compress_undo(cursor, True):
         indent.re_indent(cursor)
Ejemplo n.º 14
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)
Ejemplo n.º 15
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction() + 1]
        single = ''
        if name == "grace_grace":
            inner = ''
            outer = '\\grace { ', ' }'
            single = '\\grace '
        elif name == "grace_beam":
            inner = d + '[', ']'
            outer = '\\grace { ', ' }'
        elif name == "grace_accia":
            inner = ''
            outer = '\\acciaccatura { ', ' }'
            single = '\\acciaccatura '
        elif name == "grace_appog":
            inner = ''
            outer = '\\appoggiatura { ', ' }'
            single = '\\appoggiatura '
        elif name == "grace_slash":
            inner = d + '[', ']'
            outer = '\\slashedGrace { ', ' }'
        elif name == "grace_after":
            inner = d + '{ '
            outer = '\\afterGrace ', ' }'

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            if inner:
                for i, ci in zip(inner, spanner_positions(cursor)):
                    ci.insertText(i)
            if cursor.hasSelection():
                ins = self.mainwindow().textCursor()
                ins.setPosition(cursor.selectionStart())
                ins.insertText(outer[0])
                ins.setPosition(cursor.selectionEnd())
                ins.insertText(outer[1])
            else:
                if single:
                    cursor.insertText(single)
                else:
                    c = lydocument.cursor(cursor)
                    c.end = None
                    items = list(
                        ly.rhythm.music_items(c, partial=ly.document.OUTSIDE))
                    after = self.mainwindow().textCursor()
                    try:
                        i = items[2]
                        pos = i.pos + 1
                        end = (i.tokens or i.dur_tokens)[0].end
                        after.setPosition(pos)
                        after.setPosition(end, QTextCursor.KeepAnchor)
                    except IndexError:
                        after.movePosition(cursor.EndOfLine)
                    after.insertText(outer[1])
                    cursor.insertText(outer[0])
Ejemplo n.º 16
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction()+1]
        single = ''
        if name == "grace_grace":
            inner = ''
            outer = '\\grace { ', ' }'
            single = '\\grace '
        elif name == "grace_beam":
            inner = d + '[', ']'
            outer = '\\grace { ', ' }'
        elif name == "grace_accia":
            inner = ''
            outer = '\\acciaccatura { ', ' }'
            single = '\\acciaccatura '
        elif name == "grace_appog":
            inner = ''
            outer = '\\appoggiatura { ', ' }'
            single = '\\appoggiatura '
        elif name == "grace_slash":
            inner = d + '[', ']'
            outer = '\\slashedGrace { ', ' }'
        elif name == "grace_after":
            inner = d + '{ '
            outer = '\\afterGrace ', ' }'

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            if inner:
                for i, ci in zip(inner, spanner_positions(cursor)):
                    ci.insertText(i)
            if cursor.hasSelection():
                ins = self.mainwindow().textCursor()
                ins.setPosition(cursor.selectionStart())
                ins.insertText(outer[0])
                ins.setPosition(cursor.selectionEnd())
                ins.insertText(outer[1])
            else:
                if single:
                    cursor.insertText(single)
                else:
                    c = lydocument.cursor(cursor)
                    c.end = None
                    items = list(ly.rhythm.music_items(c, partial=ly.document.OUTSIDE))
                    after = self.mainwindow().textCursor()
                    try:
                        i = items[2]
                        pos = i.pos + 1
                        end = (i.tokens or i.dur_tokens)[0].end
                        after.setPosition(pos)
                        after.setPosition(end, QTextCursor.KeepAnchor)
                    except IndexError:
                        after.movePosition(cursor.EndOfLine)
                    after.insertText(outer[1])
                    cursor.insertText(outer[0])
Ejemplo n.º 17
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)
Ejemplo n.º 18
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction()+1]
        single = ''
        if name == "grace_grace":
            inner = ''
            outer = '\\grace { ', ' }'
            single = '\\grace '
        elif name == "grace_beam":
            inner = d + '[', ']'
            outer = '\\grace { ', ' }'
        elif name == "grace_accia":
            inner = ''
            outer = '\\acciaccatura { ', ' }'
            single = '\\acciaccatura '
        elif name == "grace_appog":
            inner = ''
            outer = '\\appoggiatura { ', ' }'
            single = '\\appoggiatura '
        elif name == "grace_slash":
            inner = d + '[', ']'
            outer = '\\slashedGrace { ', ' }'
        elif name == "grace_after":
            inner = d + '{ '
            outer = '\\afterGrace ', ' }'               

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            if inner:     
                for i, ci in zip(inner, spanner_positions(cursor)):
                    ci.insertText(i)
            if cursor.hasSelection():
                ins = self.mainwindow().textCursor()      
                ins.setPosition(cursor.selectionStart())
                ins.insertText(outer[0])
                ins.setPosition(cursor.selectionEnd())
                ins.insertText(outer[1])
            else:
                if single:
                    cursor.insertText(single)
                else:
                    c = lydocument.cursor(cursor)
                    c.end = None
                    source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
                    music_list = list(ly.rhythm.music_tokens(source))
                    try:
                        m = music_list[2][0]
                        after = source.cursor(m, 1)
                    except IndexError:                      
                        after = self.mainwindow().textCursor()
                        after.movePosition(cursor.EndOfLine)        
                    after.insertText(outer[1])
                    cursor.insertText(outer[0])
Ejemplo n.º 19
0
 def slotReplaceAll(self):
     view = self.currentView()
     if view:
         replaced = False
         cursors = self._positions
         if view.textCursor().hasSelection():
             cursors = [cursor for cursor in cursors if cursortools.contains(view.textCursor(), cursor)]
         with cursortools.compress_undo(view.textCursor()):
             for cursor in cursors:
                 if self.doReplace(cursor):
                     replaced = True
         if replaced:
             self.highlightingOn()
Ejemplo n.º 20
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)
Ejemplo n.º 21
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)
Ejemplo n.º 22
0
 def slotReplaceAll(self):
     """Called when the user clicks Replace All."""
     view = self.currentView()
     if view:
         replaced = False
         cursors = self._positions
         if view.textCursor().hasSelection():
             cursors = [cursor for cursor in cursors if cursortools.contains(view.textCursor(), cursor)]
         with cursortools.compress_undo(view.textCursor()):
             for cursor in cursors:
                 if self.doReplace(cursor):
                     replaced = True
         if replaced:
             self.highlightingOn()
Ejemplo n.º 23
0
def insert_text(cursor, text):
    """Inserts text and indents it if there are newlines in it."""
    if '\n' not in text:
        cursor.insertText(text)
        return
    line = cursor.document().findBlock(cursor.selectionStart()).blockNumber()
    with cursortools.compress_undo(cursor):
        cursor.insertText(text)
        block = cursor.document().findBlockByNumber(line)
        last = cursor.block()
        tokeniter.update(block) # tokenize inserted lines
        while last != block:
            block = block.next()
            if set_indent(block, compute_indent(block)):
                tokeniter.update(block)
Ejemplo n.º 24
0
def re_indent(cursor):
    """Re-indents the selected region or the whole document."""
    if cursor.hasSelection():
        blocks = cursortools.blocks(cursor)
    else:
        blocks = cursortools.all_blocks(cursor.document())
    with cursortools.compress_undo(cursor):
        for block in blocks:
            tokeniter.update(block)
            if tokeniter.state(block).mode() in ('lilypond', 'scheme'):
                indent = compute_indent(block)
            else:
                indent = get_indent(block)
            if set_indent(block, indent):
                tokeniter.update(block) # force token update if changed
Ejemplo n.º 25
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction()+1]
        if name == "spanner_slur":
            spanner = d + '(', ')'
        elif name == "spanner_phrasingslur":
            spanner = d + '\\(', '\\)'
        elif name == "spanner_beam16":
            spanner = d + '[', ']'
        elif name == "spanner_trill":
            spanner = '\\startTrillSpan', '\\stopTrillSpan'

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            for s, c in zip(spanner, spanner_positions(cursor)):
                c.insertText(s)
Ejemplo n.º 26
0
 def actionTriggered(self, name):
     if self.tool().shorthands.isChecked() and name in shorthands:
         text = '_-^'[self.direction()+1] + shorthands[name]
     else:
         text = ('_', '', '^')[self.direction()+1] + '\\' + name
     cursor = self.mainwindow().textCursor()
     selection = cursor.hasSelection()
     cursors = articulation_positions(cursor)
     if cursors:
         with cursortools.compress_undo(cursor):
             for c in cursors:
                 c.insertText(text)
         if not selection:
             self.mainwindow().currentView().setTextCursor(c)
     elif not selection:
         cursor.insertText(text)
Ejemplo n.º 27
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction() + 1]
        if name == "spanner_slur":
            spanner = d + '(', ')'
        elif name == "spanner_phrasingslur":
            spanner = d + '\\(', '\\)'
        elif name == "spanner_beam16":
            spanner = d + '[', ']'
        elif name == "spanner_trill":
            spanner = '\\startTrillSpan', '\\stopTrillSpan'
        elif name == "spanner_melisma":
            spanner = '\\melisma', '\\melismaEnd'

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            for s, c in zip(spanner, spanner_positions(cursor)):
                c.insertText(s)
Ejemplo n.º 28
0
 def keyPressEvent(self, ev):
     if homekey.handle(self, ev):
         return
     super(View, self).keyPressEvent(ev)
     
     if metainfo.info(self.document()).auto_indent:
         # run the indenter on Return or when the user entered a dedent token.
         import indent
         cursor = self.textCursor()
         if ev.text() == '\r' or (ev.text() in ('}', '#', '>') and indent.indentable(cursor)):
             with cursortools.compress_undo(cursor, True):
                 indent.auto_indent_block(cursor.block())
             # keep the cursor at the indent position on vertical move
             cursor = self.textCursor()
             pos = cursor.position()
             cursor.setPosition(cursor.block().position()) # move horizontal
             cursor.setPosition(pos) # move back to position
             self.setTextCursor(cursor)
Ejemplo n.º 29
0
 def hyphenate(self):
     """Hyphenates selected Lyrics text."""
     view = self.mainwindow().currentView()
     cursor = view.textCursor()
     found = []
     # find text to hyphenate
     if cursor.hasSelection():
         source = tokeniter.Source.selection(cursor)
     else:
         source = tokeniter.Source.document(cursor)
     for token in source:
         if isinstance(token, ly.lex.lilypond.LyricText):
             # a word found
             for m in _word_re.finditer(token):
                 found.append((source.cursor(token, m.start(), m.end()), m.group()))
     if not found and cursor.hasSelection():
         # no tokens were found, then tokenize the text again as if in lyricmode
         start = cursor.selectionStart()
         state = ly.lex.State(ly.lex.lilypond.ParseLyricMode)
         for token in state.tokens(cursor.selection().toPlainText()):
             if isinstance(token, ly.lex.lilypond.LyricText):
                 # a word found
                 for m in _word_re.finditer(token):
                     cur = QTextCursor(cursor)
                     cur.setPosition(start + token.pos + m.start())
                     cur.setPosition(start + token.pos + m.end(), QTextCursor.KeepAnchor)
                     found.append((cur, m.group()))
     if not found and cursor.hasSelection():
         # still not succeeded, then try flat text
         for m in _word_re.finditer(cursor.selection().toPlainText()):
             cur = QTextCursor(cursor)
             cur.setPosition(start + m.start())
             cur.setPosition(start + m.end(), QTextCursor.KeepAnchor)
             found.append((cur, m.group()))
     if found:
         import hyphendialog
         h = hyphendialog.HyphenDialog(self.mainwindow()).hyphenator()
         if h:
             with cursortools.compress_undo(cursor):
                 for cur, word in found:
                     hyph_word = h.inserted(word, ' -- ')
                     if word != hyph_word:
                         cur.insertText(hyph_word)
Ejemplo n.º 30
0
 def insertText(self, text, indent=True, blankline=False):
     """Insert text in the current document and focuses the document again.
     
     Besides the text, the following keyword arguments may be used:
     
     indent (default: True): The text will be indented if there are one or
         more newlines in it.
     blankline (default: False): A newline will be prepended to text if the
         cursor is currently not on a blank line.
     
     """
     cursor = self.mainwindow().textCursor()
     if blankline and not cursor.hasSelection() and not cursortools.isblank_before(cursor):
         text = '\n' + text
     pos = cursor.selectionStart()
     cursor.insertText(text)
     if indent and '\n' in text:
         cursor.setPosition(pos, cursor.KeepAnchor)
         import indent
         with cursortools.compress_undo(cursor, True):
             indent.re_indent(cursor)
Ejemplo n.º 31
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()
    line = cursor.document().findBlock(pos).blockNumber()
    with cursortools.compress_undo(cursor):
        
        # insert the snippet, might return a new cursor
        if 'python' in variables:
            new = insert_python(text, cursor, name, view)
        else:
            new = insert_snippet(text, cursor, variables)
        
        # QTextBlocks the snippet starts and ends
        block = cursor.document().findBlockByNumber(line)
        last = cursor.block()
        
        # re-indent if not explicitly suppressed by a 'indent: no' variable
        if last != block and 'no' not in variables.get('indent', ''):
            tokeniter.update(block) # tokenize inserted lines
            while True:
                block = block.next()
                if indent.set_indent(block, indent.compute_indent(block)):
                    tokeniter.update(block)
                if block == last:
                    break
    
    if not new and 'keep' in selection:
        end = cursor.position()
        cursor.setPosition(pos)
        cursor.setPosition(end, QTextCursor.KeepAnchor)
    view.setTextCursor(new or cursor)
Ejemplo n.º 32
0
 def actionTriggered(self, name):
     if self.tool().shorthands.isChecked() and name in shorthands:
         short = shorthands[name]
         # LilyPond >= 2.17.25 changed -| to -!
         if name == 'staccatissimo':
             version = documentinfo.docinfo(self.mainwindow().currentDocument()).version()
             if version >= (2, 17, 25):
                 short = '!'
         text = '_-^'[self.direction()+1] + short
     else:
         text = ('_', '', '^')[self.direction()+1] + '\\' + name
     cursor = self.mainwindow().textCursor()
     selection = cursor.hasSelection()
     cursors = articulation_positions(cursor)
     if cursors:
         with cursortools.compress_undo(cursor):
             for c in cursors:
                 c.insertText(text)
         if not selection:
             self.mainwindow().currentView().setTextCursor(c)
     elif not selection:
         cursor.insertText(text)
Ejemplo n.º 33
0
 def actionTriggered(self, name):
     if self.tool().shorthands.isChecked() and name in shorthands:
         short = shorthands[name]
         # LilyPond >= 2.17.25 changed -| to -!
         if name == "staccatissimo":
             version = documentinfo.docinfo(self.mainwindow().currentDocument()).version()
             if version >= (2, 17, 25):
                 short = "!"
         text = "_-^"[self.direction() + 1] + short
     else:
         text = ("_", "", "^")[self.direction() + 1] + "\\" + name
     cursor = self.mainwindow().textCursor()
     selection = cursor.hasSelection()
     cursors = articulation_positions(cursor)
     if cursors:
         with cursortools.compress_undo(cursor):
             for c in cursors:
                 c.insertText(text)
         if not selection:
             self.mainwindow().currentView().setTextCursor(c)
     elif not selection:
         cursor.insertText(text)
Ejemplo n.º 34
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction()+1]
        single = ''
        if name == "grace_grace":
            inner = ''
            outer = '\\grace { ', ' }'
        elif name == "grace_beam":
            inner = d + '[', ']'
            outer = '\\grace { ', ' }'
        elif name == "grace_accia":
            inner = ''
            outer = '\\acciaccatura { ', ' }'
            single = '\\acciaccatura '
        elif name == "grace_appog":
            inner = ''
            outer = '\\appoggiatura { ', ' }'
            single = '\\appoggiatura '
        elif name == "grace_slash":
            inner = d + '[', ']'
            outer = '\\slashedGrace { ', ' }'
        elif name == "grace_after":
            inner = d + '{ '
            outer = '\\afterGrace ', ' }'        		

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            if inner:     
            	for i, ci in zip(inner, spanner_positions(cursor)):
                	ci.insertText(i)
            if cursor.hasSelection():
            	ins = self.mainwindow().textCursor()      
            	ins.setPosition(cursor.selectionStart())
            	ins.insertText(outer[0])
            	ins.setPosition(cursor.selectionEnd())
            	ins.insertText(outer[1])
            else:
            	cursor.insertText(single)
Ejemplo n.º 35
0
def rhythm_remove_scaling(cursor):
    with cursortools.compress_undo(cursor):
        for c in cursors(cursor, ly.lex.lilypond.Scaling):
            c.removeSelectedText()
Ejemplo n.º 36
0
def rhythm_remove(cursor):
    with cursortools.compress_undo(cursor):
        for c in cursors(cursor, ly.lex.lilypond.Duration):
            c.removeSelectedText()
Ejemplo n.º 37
0
def cut_assign(cursor):
    """Cuts selected text and assigns it to a LilyPond variable."""
    # ask the variable name
    name = inputdialog.getText(
        None,
        _("Cut and Assign"),
        _("Please enter the name for the variable to assign the selected "
          "text to:"),
        regexp="[A-Za-z]+")
    if not name:
        return

    cursortools.strip_selection(cursor)

    # determine state at cursor
    block = cursortools.block(cursor)
    state = tokeniter.state(block)
    for t in tokeniter.partition(cursor).left:
        state.follow(t)

    mode = ""
    for p in state.parsers():
        if isinstance(p, ly.lex.lilypond.ParseInputMode):
            if isinstance(p, ly.lex.lilypond.ParseLyricMode):
                mode = " \\lyricmode"
            elif isinstance(p, ly.lex.lilypond.ParseChordMode):
                mode = " \\chordmode"
            elif isinstance(p, ly.lex.lilypond.ParseFigureMode):
                mode = " \\figuremode"
            elif isinstance(p, ly.lex.lilypond.ParseDrumMode):
                mode = " \\drummode"
            break

    # find insertion place:
    found = False
    while block.previous().isValid():
        block = block.previous()
        state = tokeniter.state(block)
        if isinstance(state.parser(), ly.lex.lilypond.ParseGlobal):
            found = True
            break
        tokens = tokeniter.tokens(block)
        for t in tokens:
            if isinstance(t, ly.lex.lilypond.Name):
                found = True
                break
            elif not isinstance(t, (ly.lex.Space, ly.lex.Comment)):
                break
        if found:
            break
    insert = QTextCursor(block)
    text = cursor.selection().toPlainText()
    space = '\n' if '\n' in text else ' '
    text = ''.join((name, ' =', mode, ' {', space, text, space, '}\n\n'))
    with cursortools.compress_undo(cursor):
        cursor.insertText('\\' + name)
        pos = insert.selectionStart()
        insert.insertText(text)
    if metainfo.info(cursor.document()).auto_indent:
        insert.setPosition(pos, QTextCursor.KeepAnchor)
        with cursortools.compress_undo(insert, True):
            indent.re_indent(insert)