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
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)
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 source = tokeniter.Source.fromCursor(cursor, True, -1) for p in music.music_items(source): cursor = source.cursor(p[-1], start=len(p[-1])) break cursor.insertText(direction + dynamic) self.mainwindow().currentView().setTextCursor(cursor) else: source = tokeniter.Source.selection(cursor, True) cursors = [source.cursor(p[-1], start=len(p[-1])) for p in music.music_items(source)] 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.editBlock(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)
def rhythm_halve(cursor): with cursortools.Editor() as e: for b, d in duration_items(cursor, ly.lex.lilypond.Length): for t in d: try: i = durations.index(t) except ValueError: continue if i < len(durations) - 1: e.insertText(tokeniter.cursor(b, t), durations[i + 1])
def set_indent(block, indent): """Sets the indent of block to tabs/spaces of length indent. Does not change the document if the indent does not need a change. Returns True if the indent was changed. """ # get some variables from the document indent_vars = indent_variables(block.document()) space = make_indent(indent, indent_vars['tab-width'], indent_vars['indent-tabs']) tokens = tokeniter.tokens(block) if tokens and isinstance(tokens[0], ly.lex.Space): changed = tokens[0] != space cursor = tokeniter.cursor(block, tokens[0]) else: changed = indent != 0 cursor = QTextCursor(block) if changed: cursor.insertText(space) return changed
def newlineafter(t): editor.insertText(tokeniter.cursor(block, t, start=len(t)), '\n')
def newlinebefore(t): editor.insertText(tokeniter.cursor(block, t, end=0), '\n')
def rhythm_undot(cursor): with cursortools.Editor() as e: for b, d in duration_items(cursor, ly.lex.lilypond.Dot): if d: e.removeSelectedText(tokeniter.cursor(b, d[0]))
def rhythm_dot(cursor): with cursortools.Editor() as e: for b, d in duration_items(cursor, ly.lex.lilypond.Length): for t in d: e.insertText(tokeniter.cursor(b, t, start=len(t)), ".")
def cursors(cursor, *classes): """Returns a list of cursors for the duration_items() with same args.""" return [tokeniter.cursor(b, t) for b, d in duration_items(cursor, *classes) for t in d]