1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2011 - 2014 by Wilbert Berendsen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.
"""
Completions data harvested from a Document.
"""
import itertools
import os
import listmodel
import plugin
import ly.words
import ly.data
from . import completiondata
from . import harvest
from . import util
def doc(document):
"""Returns the DocumentDataSource for the specified Document."""
return DocumentDataSource.instance(document)
class DocumentDataSource(plugin.DocumentPlugin):
@util.keep
def words(self):
"""Returns the list of words in comments, markup etc."""
return listmodel.ListModel(
sorted(set(harvest.words(self.document()))))
@util.keep
def schemewords(self):
"""Scheme names, including those harvested from document."""
schemewords = set(itertools.chain(
ly.data.all_scheme_words(),
(str(t)
for t in harvest.schemewords(self.document())
if len(t) > 2),
))
return listmodel.ListModel(sorted(schemewords))
@util.keep
def markup(self, cursor):
"""Completes markup commands and normal text from the document."""
return listmodel.ListModel(
['\\' + w for w in sorted(ly.words.markupcommands)]
+ [ '\\' + w for w in sorted(set(itertools.chain(
harvest.markup_commands(cursor),
harvest.include_markup_commands(cursor))))]
+ sorted(set(harvest.words(self.document()))))
@util.keep
def scorecommands(self, cursor):
"""Stuff inside \\score { }. """
return listmodel.ListModel(sorted(set(itertools.chain(
completiondata.score,
harvest.include_identifiers(cursor),
harvest.names(cursor)))), display = util.command)
@util.keep
def bookpartcommands(self, cursor):
"""Stuff inside \\bookpart { }. """
return listmodel.ListModel(sorted(set(itertools.chain(
completiondata.bookpart,
harvest.include_identifiers(cursor),
harvest.names(cursor)))), display = util.command)
@util.keep
def bookcommands(self, cursor):
"""Stuff inside \\book { }. """
return listmodel.ListModel(sorted(set(itertools.chain(
completiondata.book,
harvest.include_identifiers(cursor),
harvest.names(cursor)))), display = util.command)
@util.keep
def musiccommands(self, cursor):
return listmodel.ListModel(sorted(set(itertools.chain(
ly.words.lilypond_keywords,
ly.words.lilypond_music_commands,
ly.words.articulations,
ly.words.ornaments,
ly.words.fermatas,
ly.words.instrument_scripts,
ly.words.repeat_scripts,
harvest.include_identifiers(cursor),
harvest.names(cursor)))), display = util.command)
@util.keep
def lyriccommands(self, cursor):
return listmodel.ListModel(sorted(set(itertools.chain(
('set stanza = ', 'set', 'override', 'markup', 'notemode', 'repeat'),
harvest.include_identifiers(cursor),
harvest.names(cursor)))), display = util.command)
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)
def get_filenames(path, directories = False):
try:
for root, dirs, files in os.walk(path):
for f in files:
if f and f[0] not in '.~':
name, ext = os.path.splitext(f)
if ext.lower() in ('.ly', '.lyi', '.ily'):
yield f
if directories:
for f in dirs:
if f and not f.startswith('.'):
yield f + os.sep
return
except UnicodeDecodeError:
# this only happens when there are filenames in the wrong encoding,
# but never ever bug the user about this while typing :)
pass
|