Example #1
0
def defaultJob(document, preview):
    """Returns a default job for the document."""
    filename, mode, includepath = documentinfo.info(document).jobinfo(True)
    includepath.extend(documentinfo.info(document).includepath())
    i = info(document)
    j = job.Job()
    
    command = [i.command]
    s = QSettings()
    s.beginGroup("lilypond_settings")
    if s.value("delete_intermediate_files", True) not in (False, "false"):
        command.append('-ddelete-intermediate-files')
    else:
        command.append('-dno-delete-intermediate-files')
    command.append('-dpoint-and-click' if preview else '-dno-point-and-click')
    command.append('--pdf')
    command.extend('-I' + path for path in includepath)
    j.directory = os.path.dirname(filename)
    command.append(filename)
    j.command = command
    if s.value("no_translation", False) in (True, "true"):
        j.environment['LANG'] = 'C'
    j.setTitle("{0} {1} [{2}]".format(
        os.path.basename(i.command), i.versionString(), document.documentName()))
    return j
Example #2
0
def getTransposer(document, mainwindow):
    """Show a dialog and return the desired transposer.
    
    Returns None if the dialog was cancelled.
    
    """
    language = documentinfo.info(document).pitchLanguage() or 'nederlands'
    
    def readpitches(text):
        """Reads pitches from text."""
        result = []
        for pitch, octave in re.findall(r"([a-z]+)([,']*)", text):
            r = ly.pitch.pitchReader(language)(pitch)
            if r:
                result.append(ly.pitch.Pitch(*r, octave=ly.pitch.octaveToNum(octave)))
        return result
    
    def validate(text):
        """Returns whether the text contains exactly two pitches."""
        return len(readpitches(text)) == 2
    
    text = inputdialog.getText(mainwindow, _("Transpose"), _(
        "Please enter two absolute pitches, separated by a space, "
        "using the pitch name language \"{language}\"."
        ).format(language=language), icon = icons.get('tools-transpose'),
        help = transpose_help, validate = validate)
    
    if text:
        return ly.pitch.Transposer(*readpitches(text))
Example #3
0
def include_markup_commands(cursor):
    """Harvest markup command definitions from included files."""
    includeargs = ly.parse.includeargs(itertools.chain.from_iterable(tokens(cursor)))
    dinfo = documentinfo.info(cursor.document())
    fname = cursor.document().url().toLocalFile()
    files = fileinfo.includefiles(fname, dinfo.includepath(), includeargs)
    return itertools.chain.from_iterable(fileinfo.FileInfo.info(f).markup_commands() for f in files)
def open_file_at_cursor(cursor, mainwin):
    """Opens the filename mentioned at the text cursor."""
    # take either the selection or the include-args found by ly.parse
    if cursor.hasSelection():
        fnames = [cursor.selection().toPlainText()]
    else:
        fnames = list(ly.parse.includeargs(iter(tokeniter.tokens(cursor.block()))))
    
    # detemine search path: doc dir and other include path names
    filename = cursor.document().url().toLocalFile()
    if filename:
        path = [os.path.dirname(filename)]
    else:
        path = []
    path.extend(documentinfo.info(cursor.document()).includepath())
    
    # load all docs, trying all include paths
    d = None
    for f in fnames:
        for p in path:
            name = os.path.normpath(os.path.join(p, f))
            if os.access(name, os.R_OK):
                d = mainwin.openUrl(QUrl.fromLocalFile(name))
                break
    if d:
        mainwin.setCurrentDocument(d, True)
Example #5
0
 def setLanguageMenu(self):
     """Called when the menu is shown; selects the correct language."""
     import documentinfo
     doc = self.mainwindow().currentDocument()
     lang = documentinfo.info(doc).pitchLanguage() or 'nederlands'
     for a in self.language_group.actions():
         if a.objectName() == lang:
             a.setChecked(True)
             break
Example #6
0
 def setDocument(self, doc):
     v = documentinfo.info(doc).versionString()
     if v:
         self.fromVersion.setText(v)
         self.reason.setText(_("(set in document)"))
     else:
         self.reason.clear()
     self._text = doc.toPlainText()
     self._encoding = doc.encoding() or "UTF-8"
     self.setConvertedText()
Example #7
0
def defaultJob(document, args=None):
    """Return a default job for the document.

    The 'args' argument, if given, must be a list of commandline arguments
    that are given to LilyPond, and may enable specific preview modes.

    If args is not given, the Job will cause LilyPond to run in Publish mode,
    with point and click turned off.

    """
    filename, includepath = documentinfo.info(document).jobinfo(True)

    i = info(document)
    j = job.Job()

    command = [i.abscommand() or i.command]
    s = QSettings()
    s.beginGroup("lilypond_settings")
    if s.value("delete_intermediate_files", True, bool):
        command.append('-ddelete-intermediate-files')
    else:
        command.append('-dno-delete-intermediate-files')

    if args:
        command.extend(args)
    else:
        # publish mode
        command.append('-dno-point-and-click')

    if s.value("default_output_target", "pdf", str) == "svg":
        # engrave to SVG
        command.append('-dbackend=svg')
    else:
        # engrave to PDF
        if not args:
            # publish mode
            if s.value("embed_source_code", False,
                       bool) and i.version() >= (2, 19, 39):
                command.append('-dembed-source-code')
        command.append('--pdf')

    command.extend('-I' + path for path in includepath)
    j.directory = os.path.dirname(filename)
    command.append(filename)
    j.command = command
    j.environment['LD_LIBRARY_PATH'] = i.libdir()
    if s.value("no_translation", False, bool):
        j.environment['LANG'] = 'C'
        j.environment['LC_ALL'] = 'C'
    j.set_title("{0} {1} [{2}]".format(os.path.basename(i.command),
                                       i.versionString(),
                                       document.documentName()))
    return j
Example #8
0
def defaultJob(document, args=None):
    """Return a default job for the document.

    The 'args' argument, if given, must be a list of commandline arguments
    that are given to LilyPond, and may enable specific preview modes.

    If args is not given, the Job will cause LilyPond to run in Publish mode,
    with point and click turned off.

    """
    filename, includepath = documentinfo.info(document).jobinfo(True)

    i = info(document)
    j = job.Job()

    command = [i.abscommand() or i.command]
    s = QSettings()
    s.beginGroup("lilypond_settings")
    if s.value("delete_intermediate_files", True, bool):
        command.append('-ddelete-intermediate-files')
    else:
        command.append('-dno-delete-intermediate-files')

    if args:
        command.extend(args)
    else:
        # publish mode
        command.append('-dno-point-and-click')

    if s.value("default_output_target", "pdf", str) == "svg":
        # engrave to SVG
        command.append('-dbackend=svg')
    else:
        # engrave to PDF
        if not args:
            # publish mode
            if s.value("embed_source_code", False, bool) and i.version() >= (2, 19, 39):
                command.append('-dembed-source-code')
        command.append('--pdf')


    command.extend('-I' + path for path in includepath)
    j.directory = os.path.dirname(filename)
    command.append(filename)
    j.command = command
    j.environment['LD_LIBRARY_PATH'] = i.libdir()
    if s.value("no_translation", False, bool):
        j.environment['LANG'] = 'C'
        j.environment['LC_ALL'] = 'C'
    j.set_title("{0} {1} [{2}]".format(
        os.path.basename(i.command), i.versionString(), document.documentName()))
    return j
Example #9
0
 def currentDirectory(self):
     """Returns the directory the document resides in.
     
     Returns the temporary directory if that was used last and there is no master document set.
     
     """
     if documentinfo.info(self.document()).master():
         filename = self.document().url().toLocalFile()
     else:
         filename = self.jobfile()
     directory = os.path.dirname(filename)
     if os.path.isdir(directory):
         return directory
Example #10
0
 def getJob(self, document):
     """Returns a Job to start."""
     filename, mode, includepath = documentinfo.info(document).jobinfo(True)
     includepath.extend(documentinfo.info(document).includepath())
     i = self._infos[self.versionCombo.currentIndex()]
     cmd = []
     for t in self.commandLine.toPlainText().split():
         if t == '$lilypond':
             cmd.append(i.command)
         elif t == '$filename':
             cmd.append(filename)
         elif t == '$include':
             cmd.extend('-I' + path for path in includepath)
         else:
             cmd.append(t)
     j = job.Job()
     j.directory = os.path.dirname(filename)
     j.command = cmd
     if self.englishCheck.isChecked():
         j.environment['LANG'] = 'C'
     j.setTitle("{0} {1} [{2}]".format(
         os.path.basename(i.command), i.versionString(), document.documentName()))
     return j
Example #11
0
    def includenames(self, cursor, directory=None):
        """Finds files relative to the directory of the cursor's document.
        
        If the document has a local filename, looks in that directory,
        also in a subdirectory of it, if the directory argument is given.
        
        Then looks recursively in the user-set include paths, 
        and finally in LilyPond's own ly/ folder.
        
        """
        names = []
        # names in current dir
        path = self.document().url().toLocalFile()
        if path:
            basedir = os.path.dirname(path)
            if directory:
                basedir = os.path.join(basedir, directory)
                names.extend(
                    sorted(
                        os.path.join(directory, f)
                        for f in get_filenames(basedir, True)))
            else:
                names.extend(sorted(get_filenames(basedir, True)))

        # names in specified include paths
        import documentinfo
        for basedir in documentinfo.info(self.document()).includepath():

            # store dir relative to specified include path root
            reldir = directory if directory else ""
            # look for files in the current relative directory
            for f in sorted(get_filenames(os.path.join(basedir, reldir),
                                          True)):
                names.append(os.path.join(reldir, f))

        # names from LilyPond itself
        import engrave.command
        datadir = engrave.command.info(self.document()).datadir()
        if datadir:
            basedir = os.path.join(datadir, 'ly')
            # get the filenames but avoid the -init files here
            names.extend(
                sorted(f for f in get_filenames(basedir)
                       if not f.endswith('init.ly') and f.islower()))

        # forward slashes on Windows (issue #804)
        if os.name == "nt":
            names = [name.replace('\\', '/') for name in names]

        return listmodel.ListModel(names)
Example #12
0
 def saveDocumentInfo(self):
     """Takes over some vital information from a DocumentInfo instance.
     
     The file a job is run on and the basenames expected to be created are saved.
     When the user saves a Document after a Job has run, this information is 'forgotten' again.
     
     Otherwise the results of a Job would not be seen if the user starts a Job and then
     saves the Document while the job is still running.  The Job uses the scratcharea if the
     document was modified but saving it would result in DocumentInfo.jobinfo()[0] pointing
     to the real document instead.
     
     """
     info = documentinfo.info(self.document())
     self._jobfile = info.jobinfo()[0]
     self._basenames = info.basenames()
Example #13
0
def include_identifiers(cursor):
    """Harvests identifier definitions from included files."""
    def tokens():
        end = cursor.block()
        block = cursor.document().firstBlock()
        while block < end:
            yield tokeniter.tokens(block)
            block = block.next()
    
    includeargs = ly.parse.includeargs(itertools.chain.from_iterable(tokens()))
    dinfo = documentinfo.info(cursor.document())
    fname = cursor.document().url().toLocalFile()
    files = fileinfo.includefiles(fname, dinfo.includepath(), includeargs)
    return itertools.chain.from_iterable(fileinfo.FileInfo.info(f).names()
                                         for f in files)
Example #14
0
 def saveDocumentInfo(self):
     """Takes over some vital information from a DocumentInfo instance.
     
     The file a job is run on and the basenames expected to be created are saved.
     When the user saves a Document after a Job has run, this information is 'forgotten' again.
     
     Otherwise the results of a Job would not be seen if the user starts a Job and then
     saves the Document while the job is still running.  The Job uses the scratcharea if the
     document was modified but saving it would result in DocumentInfo.jobinfo()[0] pointing
     to the real document instead.
     
     """
     info = documentinfo.info(self.document())
     self._jobfile = info.jobinfo()[0]
     self._basenames = info.basenames()
Example #15
0
 def includenames(self, cursor, directory=None):
     """Finds files relative to the directory of the cursor's document.
     
     If the document has a local filename, looks in that directory,
     also in a subdirectory of it, if the directory argument is given.
     
     Then looks recursively in the user-set include paths, 
     and finally in LilyPond's own ly/ folder.
     
     """
     names = []
     # names in current dir
     path = self.document().url().toLocalFile()
     if path:
         basedir = os.path.dirname(path)
         if directory:
             basedir = os.path.join(basedir, directory)
             names.extend(sorted(os.path.join(directory, f)
                 for f in get_filenames(basedir, True)))
         else:
             names.extend(sorted(get_filenames(basedir, True)))
     
     # names in specified include paths
     import documentinfo
     for basedir in documentinfo.info(self.document()).includepath():
         
         # store dir relative to specified include path root
         reldir = directory if directory else ""
         # look for files in the current relative directory
         for f in sorted(get_filenames(os.path.join(basedir, reldir), True)):
             names.append(os.path.join(reldir, f))
     
     # names from LilyPond itself
     import engrave.command
     datadir = engrave.command.info(self.document()).datadir()
     if datadir:
         basedir = os.path.join(datadir, 'ly')
         # get the filenames but avoid the -init files here
         names.extend(sorted(f for f in get_filenames(basedir)
             if not f.endswith('init.ly')
             and f.islower()))
     
     # forward slashes on Windows (issue #804)
     if os.name == "nt":
         names = [name.replace('\\', '/') for name in names]
     
     return listmodel.ListModel(names)
Example #16
0
def defaultJob(document, args=None):
    """Return a default job for the document.
    
    The 'args' argument, if given, must be a list of commandline arguments
    that are given to LilyPond, and may enable specific preview modes.
    
    If args is not given, the Job will cause LilyPond to run in Publish mode,
    with point and click turned off.
    
    """
    filename, includepath = documentinfo.info(document).jobinfo(True)

    i = info(document)
    j = job.Job()

    command = [i.abscommand() or i.command]
    s = QSettings()
    s.beginGroup("lilypond_settings")
    if s.value("delete_intermediate_files", True, bool):
        command.append("-ddelete-intermediate-files")
    else:
        command.append("-dno-delete-intermediate-files")

    if args:
        command.extend(args)
    else:
        command.append("-dno-point-and-click")

    if s.value("default_output_target", "pdf", type("")) == "svg":
        command.append("-dbackend=svg")
    else:
        command.append("--pdf")

    command.extend("-I" + path for path in includepath)
    j.directory = os.path.dirname(filename)
    command.append(filename)
    j.command = command
    if s.value("no_translation", False, bool):
        j.environment["LANG"] = "C"
    j.setTitle("{0} {1} [{2}]".format(os.path.basename(i.command), i.versionString(), document.documentName()))
    return j
Example #17
0
def filenames_at_cursor(cursor, existing=True):
    """Return a list of filenames at the cursor.
    
    If existing is False, also names are returned that do not exist on disk.
    
    """
    # take either the selection or the include-args found by lydocinfo
    start = cursor.document().findBlock(cursor.selectionStart()).position()
    end = cursor.selectionEnd()
    if not cursor.hasSelection():
        end = start + len(cursor.block().text()) + 1
    dinfo = documentinfo.info(cursor.document())
    i = dinfo.lydocinfo().range(start, end)
    fnames = i.include_args() or i.scheme_load_args()
    if not fnames and cursor.hasSelection():
        text = cursor.selection().toPlainText()
        if '\n' not in text.strip():
            fnames = [text]

    # determine search path: doc dir and other include path names
    filename = cursor.document().url().toLocalFile()
    directory = os.path.dirname(filename)
    if filename:
        path = [directory]
    else:
        path = []
    path.extend(dinfo.includepath())

    # find all docs, trying all include paths
    filenames = []
    for f in fnames:
        for p in path:
            name = os.path.normpath(os.path.join(p, f))
            if os.access(name, os.R_OK):
                filenames.append(name)
                break
        else:
            if not existing:
                name = os.path.normpath(os.path.join(directory, f))
                filenames.append(name)
    return filenames
def filenames_at_cursor(cursor, existing=True):
    """Return a list of filenames at the cursor.

    If existing is False, also names are returned that do not exist on disk.

    """
    # take either the selection or the include-args found by lydocinfo
    start = cursor.document().findBlock(cursor.selectionStart()).position()
    end = cursor.selectionEnd()
    if not cursor.hasSelection():
        end = start + len(cursor.block().text()) + 1
    dinfo = documentinfo.info(cursor.document())
    i = dinfo.lydocinfo().range(start, end)
    fnames = i.include_args() or i.scheme_load_args() 
    if not fnames and cursor.hasSelection():
        text = cursor.selection().toPlainText()
        if '\n' not in text.strip():
            fnames = [text]

    # determine search path: doc dir and other include path names
    filename = cursor.document().url().toLocalFile()
    directory = os.path.dirname(filename)
    if filename:
        path = [directory]
    else:
        path = []
    path.extend(dinfo.includepath())

    # find all docs, trying all include paths
    filenames = []
    for f in fnames:
        for p in path:
            name = os.path.normpath(os.path.join(p, f))
            if os.access(name, os.R_OK):
                filenames.append(name)
                break
        else:
            if not existing:
                name = os.path.normpath(os.path.join(directory, f))
                filenames.append(name)
    return filenames
Example #19
0
def tree(urls=False):
    """Return the open documents as a tree structure.
    
    Returned is a ly.node.Node instance having the toplevel documents (documents
    that are not included by other open documents) as children. The children of
    the nodes are the documents that are included by the toplevel document.
    
    Every node has the Document in its document attribute.
    
    If urls == True, nodes will also be generated for urls that refer to
    documents that are not yet open. They will have the QUrl in their url
    attribute.
    
    It is not checked whether the referred to urls or files actually exist.
    
    """
    root = ly.node.Node()
    nodes = {}
    for doc in app.documents:
        try:
            n = nodes[doc]
        except KeyError:
            n = nodes[doc] = DocumentNode(root)
            n.document = doc
        for u in documentinfo.info(doc).child_urls():
            d = app.findDocument(u)
            if d:
                try:
                    n.append(nodes[d])
                except KeyError:
                    n1 = nodes[d] = DocumentNode(n)
                    n1.document = d
            elif urls:
                try:
                    n.append(nodes[u.toString()])
                except KeyError:
                    n1 = nodes[u.toString()] = DocumentNode(n)
                    n1.url = u
    return root
Example #20
0
 def getJob(self, document):
     """Returns a Job to start."""
     filename, includepath = documentinfo.info(document).jobinfo(True)
     i = self.lilyChooser.lilyPondInfo()
     cmd = []
     for t in self.commandLine.toPlainText().split():
         if t == "$lilypond":
             cmd.append(i.abscommand() or i.command)
         elif t == "$filename":
             cmd.append(filename)
         elif t == "$include":
             cmd.extend("-I" + path for path in includepath)
         else:
             cmd.append(t)
     j = job.Job()
     j.directory = os.path.dirname(filename)
     j.command = cmd
     if self.englishCheck.isChecked():
         j.environment["LANG"] = "C"
         j.environment["LC_ALL"] = "C"
     j.set_title("{0} {1} [{2}]".format(os.path.basename(i.command), i.versionString(), document.documentName()))
     return j
Example #21
0
    def __init__(self, doc, args=None, title=""):
        """Create a LilyPond job by first retrieving some context
        from the document and feeding this into job.Job's __init__()."""
        if isinstance(doc, QUrl):
            doc = document.Document(doc)
        self.document = doc
        self.document_info = docinfo = documentinfo.info(doc)
        self.lilypond_info = docinfo.lilypondinfo()
        self._d_options = {}
        self._backend_args = []
        input, self.includepath = docinfo.jobinfo(True)
        directory = os.path.dirname(input)

        super(LilyPondJob, self).__init__(
                encoding='utf-8',
                args=args,
                input=input,
                decode_errors='replace',
                directory=directory,
                environment={
                    'LD_LIBRARY_PATH': self.lilypond_info.libdir()
                },
                title=title,
                priority=2)

        # Set default values from Preferences
        s = QSettings()
        s.beginGroup("lilypond_settings")
        self.set_d_option('delete-intermediate-files',
            s.value("delete_intermediate_files", True, bool))
        self.default_output_target = s.value(
            "default_output_target", "pdf", str)
        self.embed_source_code = s.value("embed_source_code", False, bool)
        if s.value("no_translation", False, bool):
            self.environment['LANG'] = 'C'
            self.environment['LC_ALL'] = 'C'
        self.set_title("{0} {1} [{2}]".format(
            os.path.basename(self.lilypond_info.command),
            self.lilypond_info.versionString(), doc.documentName()))
Example #22
0
def tree(urls=False):
    """Return the open documents as a tree structure.

    Returned is a ly.node.Node instance having the toplevel documents (documents
    that are not included by other open documents) as children. The children of
    the nodes are the documents that are included by the toplevel document.

    Every node has the Document in its document attribute.

    If urls == True, nodes will also be generated for urls that refer to
    documents that are not yet open. They will have the QUrl in their url
    attribute.

    It is not checked whether the referred to urls or files actually exist.

    """
    root = ly.node.Node()
    nodes = {}
    for doc in app.documents:
        try:
            n = nodes[doc]
        except KeyError:
            n = nodes[doc] = DocumentNode(root)
            n.document = doc
        for u in documentinfo.info(doc).child_urls():
            d = app.findDocument(u)
            if d:
                try:
                    n.append(nodes[d])
                except KeyError:
                    n1 = nodes[d] = DocumentNode(n)
                    n1.document = d
            elif urls:
                try:
                    n.append(nodes[u.toString()])
                except KeyError:
                    n1 = nodes[u.toString()] = DocumentNode(n)
                    n1.url = u
    return root
Example #23
0
def includeTarget(cursor):
    """Given a cursor determine an absolute path to an include file present below the cursor.
    Return path or empty string if no valid file is found.

    Note that there is still functionality related to opening all targets in the current block.
    Once it has decided that we only want to open *one* target at a time we should change
    from a list back to a single string (here and in view.py).
    """

    block = cursor.block()
    cursor_pos = cursor.position() - block.position()
    fnames = []

    m = incl_regex.search(block.text())
    while m:
        start = m.span()[0] + len(m.group(1))
        if start <= cursor_pos <= m.span()[1] - 1:
            fnames.append(m.group(2))
            break
        m = incl_regex.search(block.text(), m.span()[1])

    if not fnames:
        return ""

    # determine search path: doc dir and other include path names
    filename = cursor.document().url().toLocalFile()
    path = [os.path.dirname(filename)] if filename else []
    dinfo = documentinfo.info(cursor.document())
    path.extend(dinfo.includepath())

    targets = []
    # iterating over the search paths, find the first combination pointing to an existing file
    for f in fnames:
        for p in path:
            name = os.path.normpath(os.path.join(p, f))
            if os.path.exists(name) and not os.path.isdir(name):
                targets.append(name)
                continue
    return targets
def includeTarget(cursor):
    """Given a cursor determine an absolute path to an include file present below the cursor.
    Return path or empty string if no valid file is found.

    Note that there is still functionality related to opening all targets in the current block.
    Once it has decided that we only want to open *one* target at a time we should change
    from a list back to a single string (here and in view.py).
    """

    block = cursor.block()
    cursor_pos = cursor.position() - block.position()
    fnames = []

    m = incl_regex.search(block.text())
    while m:
        start = m.span()[0] + len(m.group(1))
        if start <= cursor_pos <= m.span()[1] - 1:
            fnames.append(m.group(2))
            break
        m = incl_regex.search(block.text(), m.span()[1])

    if not fnames:
        return ""

    # determine search path: doc dir and other include path names
    filename = cursor.document().url().toLocalFile()
    path = [os.path.dirname(filename)] if filename else []
    dinfo = documentinfo.info(cursor.document())
    path.extend(dinfo.includepath())

    targets = []
    # iterating over the search paths, find the first combination pointing to an existing file
    for f in fnames:
        for p in path:
            name = os.path.normpath(os.path.join(p, f))
            if os.path.exists(name) and not os.path.isdir(name):
                targets.append(name)
                continue
    return targets
Example #25
0
    def __init__(self, doc, args=None, title=""):
        """Create a LilyPond job by first retrieving some context
        from the document and feeding this into job.Job's __init__()."""
        if isinstance(doc, QUrl):
            doc = document.Document(doc)
        self.document = doc
        self.document_info = docinfo = documentinfo.info(doc)
        self.lilypond_info = docinfo.lilypondinfo()
        self._d_options = {}
        self._backend_args = []
        input, self.includepath = docinfo.jobinfo(True)
        directory = os.path.dirname(input)

        super(LilyPondJob, self).__init__(
                encoding='utf-8',
                args=args,
                input=input,
                decode_errors='replace',
                directory=directory,
                environment={
                    'LD_LIBRARY_PATH': self.lilypond_info.libdir()
                },
                title=title,
                priority=2)

        # Set default values from Preferences
        s = QSettings()
        s.beginGroup("lilypond_settings")
        self.set_d_option('delete-intermediate-files',
            s.value("delete_intermediate_files", True, bool))
        self.default_output_target = s.value(
            "default_output_target", "pdf", str)
        self.embed_source_code = s.value("embed_source_code", False, bool)
        if s.value("no_translation", False, bool):
            self.environment['LANG'] = 'C'
            self.environment['LC_ALL'] = 'C'
        self.set_title("{0} {1} [{2}]".format(
            os.path.basename(self.lilypond_info.command),
            self.lilypond_info.versionString(), doc.documentName()))
Example #26
0
 def includenames(self, cursor, directory=None):
     """Finds files relative to the directory of the cursor's document.
     
     If the document has a local filename, looks in that directory,
     also in a subdirectory of it, if the directory argument is given.
     
     Then looks in the user-set include paths, and finally in LilyPond's
     own ly/ folder.
     
     """
     names = []
     # names in current dir
     path = self.document().url().toLocalFile()
     if path:
         basedir = os.path.dirname(path)
         if directory:
             basedir = os.path.join(basedir, directory)
             names.extend(sorted(os.path.join(directory, f)
                 for f in get_filenames(basedir, True)))
         else:
             names.extend(sorted(get_filenames(basedir, True)))
     
     # names in specified include paths
     import documentinfo
     for basedir in documentinfo.info(self.document()).includepath():
         names.extend(sorted(get_filenames(basedir)))
     
     # names from LilyPond itself
     import engrave.command
     datadir = engrave.command.info(self.document()).datadir()
     if datadir:
         basedir = os.path.join(datadir, 'ly')
         # get the filenames but avoid the -init files here
         names.extend(sorted(f for f in get_filenames(basedir)
             if not f.endswith('init.ly')
             and f.islower()))
     
     return listmodel.ListModel(names)
Example #27
0
def insertLanguage(document, language):
    """Inserts a language command in the document.
    
    The command is inserted at the top or just below the version line.
    If the document uses LilyPond < 2.13.38, the \\include command is used,
    otherwise the newer \\language command.
    
    """
    version = (documentinfo.info(document).version()
               or lilypondinfo.preferred().version())
    if version and version < (2, 13, 38):
        text = '\\include "{0}.ly"'
    else:
        text = '\\language "{0}"'
    # insert language command on top of file, but below version
    block = document.firstBlock()
    c = QTextCursor(block)
    if '\\version' in tokeniter.tokens(block):
        c.movePosition(QTextCursor.EndOfBlock)
        text = '\n' + text
    else:
        text += '\n'
    c.insertText(text.format(language))
Example #28
0
 def getJob(self, document):
     """Returns a Job to start."""
     filename, includepath = documentinfo.info(document).jobinfo(True)
     i = self.lilyChooser.lilyPondInfo()
     cmd = []
     for t in self.commandLine.toPlainText().split():
         if t == '$lilypond':
             cmd.append(i.abscommand() or i.command)
         elif t == '$filename':
             cmd.append(filename)
         elif t == '$include':
             cmd.extend('-I' + path for path in includepath)
         else:
             cmd.append(t)
     j = job.Job()
     j.directory = os.path.dirname(filename)
     j.command = cmd
     if self.englishCheck.isChecked():
         j.environment['LANG'] = 'C'
     j.setTitle("{0} {1} [{2}]".format(os.path.basename(i.command),
                                       i.versionString(),
                                       document.documentName()))
     return j
Example #29
0
def getModalTransposer(document, mainwindow):
    """Show a dialog and return the desired modal transposer.
    
    Returns None if the dialog was cancelled.
    
    """
    language = documentinfo.info(document).pitchLanguage() or 'nederlands'
    
    def readpitches(text):
        """Reads pitches from text."""
        result = []
        for pitch, octave in re.findall(r"([a-z]+)([,']*)", text):
            r = ly.pitch.pitchReader(language)(pitch)
            if r:
                result.append(ly.pitch.Pitch(*r, octave=ly.pitch.octaveToNum(octave)))
        return result
    
    def validate(text):
        """Returns whether the text is an integer followed by the name of a key."""
        words = text.split()
        if len(words) != 2:
            return False
        try:
            steps = int(words[0])
            keyIndex = ly.pitch.ModalTransposer.getKeyIndex(words[1])
            return True
        except ValueError:
            return False
    
    text = inputdialog.getText(mainwindow, _("Transpose"), _(
        "Please enter the number of steps to alter by, followed by a key signature. (i.e. \"5 F\")"
        ), icon = icons.get('tools-transpose'),
        help = transpose_help, validate = validate)
    if text:
        words = text.split()
        return ly.pitch.ModalTransposer(int(words[0]), ly.pitch.ModalTransposer.getKeyIndex(words[1]))
Example #30
0
 def jobfile(self):
     """Returns the file that is currently being, or will be, engraved."""
     if self._jobfile is None:
         return documentinfo.info(self.document()).jobinfo()[0]
     return self._jobfile
Example #31
0
def include_identifiers(cursor):
    """Harvests identifier definitions from included files."""
    dinfo = documentinfo.info(cursor.document())
    files = fileinfo.includefiles(get_docinfo(cursor), dinfo.includepath())
    return itertools.chain.from_iterable(
        fileinfo.docinfo(f).definitions() for f in files)
Example #32
0
def include_markup_commands(cursor):
    """Harvest markup command definitions from included files."""
    dinfo = documentinfo.info(cursor.document())
    files = fileinfo.includefiles(get_docinfo(cursor), dinfo.includepath())
    return itertools.chain.from_iterable(
        fileinfo.docinfo(f).markup_definitions() for f in files)
Example #33
0
def get_docinfo(cursor):
    """Return a ly DocInfo instance for the cursor's document up to its position."""
    dinfo = documentinfo.info(cursor.document())
    return dinfo.lydocinfo().range(0, cursor.position())
Example #34
0
def get_docinfo(cursor):
    """Return a ly DocInfo instance for the cursor's document up to its position."""
    dinfo = documentinfo.info(cursor.document())
    return dinfo.lydocinfo().range(0, cursor.position())
Example #35
0
 def basenames(self):
     """Returns the list of basenames the last or running Job is expected to create."""
     if self._basenames is None:
         return documentinfo.info(self.document()).basenames()
     return self._basenames
Example #36
0
 def jobfile(self):
     """Returns the file that is currently being, or will be, engraved."""
     if self._jobfile is None:
         return documentinfo.info(self.document()).jobinfo()[0]
     return self._jobfile
Example #37
0
def include_identifiers(cursor):
    """Harvests identifier definitions from included files."""
    dinfo = documentinfo.info(cursor.document())
    files = fileinfo.includefiles(get_docinfo(cursor), dinfo.includepath())
    return itertools.chain.from_iterable(fileinfo.docinfo(f).definitions()
                                         for f in files)
Example #38
0
def include_markup_commands(cursor):
    """Harvest markup command definitions from included files."""
    dinfo = documentinfo.info(cursor.document())
    files = fileinfo.includefiles(get_docinfo(cursor), dinfo.includepath())
    return itertools.chain.from_iterable(fileinfo.docinfo(f).markup_definitions()
                                         for f in files)
Example #39
0
def info(document):
    """Returns a LilyPondInfo instance that should be used by default to engrave the document."""
    version = documentinfo.info(document).version()
    if version and QSettings().value("lilypond_settings/autoversion", False) in (True, "true"):
        return lilypondinfo.suitable(version)
    return lilypondinfo.preferred()
Example #40
0
 def basenames(self):
     """Returns the list of basenames the last or running Job is expected to create."""
     if self._basenames is None:
         return documentinfo.info(self.document()).basenames()
     return self._basenames
Example #41
0
def transpose(cursor, mainwindow):
    """Transposes pitches."""
    language = documentinfo.info(cursor.document()).pitchLanguage() or 'nederlands'
    
    def readpitches(text):
        """Reads pitches from text."""
        result = []
        for pitch, octave in re.findall(r"([a-z]+)([,']*)", text):
            r = ly.pitch.pitchReader(language)(pitch)
            if r:
                result.append(ly.pitch.Pitch(*r, octave=ly.pitch.octaveToNum(octave)))
        return result
    
    def validate(text):
        """Returns whether the text contains exactly two pitches."""
        return len(readpitches(text)) == 2
    
    text = inputdialog.getText(mainwindow, _("Transpose"), _(
        "Please enter two absolute pitches, separated by a space, "
        "using the pitch name language \"{language}\"."
        ).format(language=language), icon = icons.get('tools-transpose'),
        help = transpose_help, validate = validate)
    if text == None:
        return
    
    transposer = ly.pitch.Transposer(*readpitches(text))
    
    selection = cursor.hasSelection()
    if selection:
        start = cursor.selectionStart()
        cursor.setPosition(cursor.selectionEnd())
        cursor.setPosition(0, QTextCursor.KeepAnchor)
        source = tokeniter.Source.selection(cursor, True)
    else:
        source = tokeniter.Source.document(cursor, True)
    
    pitches = PitchIterator(source)
    psource = pitches.pitches()
    
    class gen(object):
        def __init__(self):
            self.inSelection = not selection
        
        def __iter__(self):
            return self
        
        def __next__(self):
            while True:
                t = next(psource)
                if isinstance(t, (ly.lex.Space, ly.lex.Comment)):
                    continue
                elif not self.inSelection and pitches.position(t) >= start:
                    self.inSelection = True
                # Handle stuff that's the same in relative and absolute here
                if t == "\\relative":
                    relative()
                elif isinstance(t, ly.lex.lilypond.MarkupScore):
                    absolute(context())
                elif isinstance(t, ly.lex.lilypond.ChordMode):
                    chordmode()
                elif isinstance(t, ly.lex.lilypond.PitchCommand):
                    if t == "\\transposition":
                        next(psource) # skip pitch
                    elif t == "\\transpose":
                        for p in getpitches(context()):
                            transpose(p)
                    elif t == "\\key":
                        for p in getpitches(context()):
                            transpose(p, 0)
                    else:
                        return t
                else:
                    return t
        
        next = __next__
    
    tsource = gen()
    
    def context():
        """Consume tokens till the level drops (we exit a construct)."""
        depth = source.state.depth()
        for t in tsource:
            yield t
            if source.state.depth() < depth:
                return
    
    def consume():
        """Consume tokens from context() returning the last token, if any."""
        t = None
        for t in context():
            pass
        return t
        
    def transpose(p, resetOctave = None):
        """Transpose absolute pitch, using octave if given."""
        transposer.transpose(p)
        if resetOctave is not None:
            p.octave = resetOctave
        if tsource.inSelection:
            pitches.write(p, editor)

    def chordmode():
        """Called inside \\chordmode or \\chords."""
        for p in getpitches(context()):
            transpose(p, 0)
            
    def absolute(tokens):
        """Called when outside a possible \\relative environment."""
        for p in getpitches(tokens):
            transpose(p)
    
    def relative():
        """Called when \\relative is encountered."""
        def transposeRelative(p, lastPitch):
            """Transposes a relative pitch; returns the pitch in absolute form."""
            # absolute pitch determined from untransposed pitch of lastPitch
            p.makeAbsolute(lastPitch)
            if not tsource.inSelection:
                return p
            # we may change this pitch. Make it relative against the
            # transposed lastPitch.
            try:
                last = lastPitch.transposed
            except AttributeError:
                last = lastPitch
            # transpose a copy and store that in the transposed
            # attribute of lastPitch. Next time that is used for
            # making the next pitch relative correctly.
            newLastPitch = p.copy()
            transposer.transpose(p)
            newLastPitch.transposed = p.copy()
            if p.octaveCheck is not None:
                p.octaveCheck = p.octave
            p.makeRelative(last)
            if relPitch:
                # we are allowed to change the pitch after the
                # \relative command. lastPitch contains this pitch.
                lastPitch.octave += p.octave
                p.octave = 0
                pitches.write(lastPitch, editor)
                del relPitch[:]
            pitches.write(p, editor)
            return newLastPitch

        lastPitch = None
        relPitch = [] # we use a list so it can be changed from inside functions
        
        # find the pitch after the \relative command
        t = next(tsource)
        if isinstance(t, Pitch):
            lastPitch = t
            if tsource.inSelection:
                relPitch.append(lastPitch)
            t = next(tsource)
        else:
            lastPitch = Pitch.c1()
        
        while True:
            # eat stuff like \new Staff == "bla" \new Voice \notes etc.
            if isinstance(source.state.parser(), ly.lex.lilypond.ParseTranslator):
                t = consume()
            elif isinstance(t, ly.lex.lilypond.NoteMode):
                t = next(tsource)
            else:
                break
        
        # now transpose the relative expression
        if t in ('{', '<<'):
            # Handle full music expression { ... } or << ... >>
            for t in context():
                if t == '\\octaveCheck':
                    for p in getpitches(context()):
                        lastPitch = p.copy()
                        del relPitch[:]
                        if tsource.inSelection:
                            transposer.transpose(p)
                            lastPitch.transposed = p
                            pitches.write(p, editor)
                elif isinstance(t, ly.lex.lilypond.ChordStart):
                    chord = [lastPitch]
                    for p in getpitches(context()):
                        chord.append(transposeRelative(p, chord[-1]))
                    lastPitch = chord[:2][-1] # same or first
                elif isinstance(t, Pitch):
                    lastPitch = transposeRelative(t, lastPitch)
        elif isinstance(t, ly.lex.lilypond.ChordStart):
            # Handle just one chord
            for p in getpitches(context()):
                lastPitch = transposeRelative(p, lastPitch)
        elif isinstance(t, Pitch):
            # Handle just one pitch
            transposeRelative(token, lastPitch)

    # Do it!
    try:
        with qutil.busyCursor():
            with cursortools.Editor() as editor:
                absolute(tsource)
    except ly.pitch.PitchNameNotAvailable:
        QMessageBox.critical(mainwindow, app.caption(_("Transpose")), _(
            "Can't perform the requested transposition.\n\n"
            "The transposed music would contain quarter-tone alterations "
            "that are not available in the pitch language \"{language}\"."
            ).format(language = pitches.language))