WingHexExplorer2/3rdparty/qcodeedit2/lib/qlanguagefactory.cpp

291 lines
8.3 KiB
C++

/****************************************************************************
**
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
**
** This file is part of the Edyuk project <http://edyuk.org>
**
** This file may be used under the terms of the GNU General Public License
** version 3 as published by the Free Software Foundation and appearing in the
** file GPL.txt included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "qlanguagefactory.h"
/*!
\file qlanguagefactory.cpp
\brief Implementation of QLanguageFactory
\see QLanguageFactory
*/
/*!
\ingroup language
@{
\class QLanguageFactory
\brief A class managing language definitions.
It stores language definitions, added programmatically or found in XML
files, in specified locations and only if generic components are built-in.
From these definitions, QLanguageFactory generates matchers, indenters and
highlighters for a text editor, according to a file name.
\see QLanguageDefinition
*/
#include <QDir>
#include <QFileInfo>
#include <QStringList>
#ifdef _QCODE_EDIT_DEBUG_
#include <QtDebug>
#endif
#include "qeditor.h"
#include "qformatscheme.h"
#include "qcodecompletionengine.h"
#include "qlanguagedefinition.h"
#ifdef QNFA_BUILD
#include "qnfadefinition.h"
#endif
/*!
\brief Empty constructor
*/
QLanguageFactory::QLanguageFactory(QFormatScheme *fmt, QObject *p)
: QObject(p), m_defaultFormatScheme(fmt) {}
/*!
\brief Empty destructor
*/
QLanguageFactory::~QLanguageFactory() {
foreach (QString l, m_languages) {
const LangData &d = m_data[l];
if (d.s != m_defaultFormatScheme)
delete d.s;
delete d.d;
// delete d.e;
}
}
/*!
\return a list of languages supported by this factory
*/
QStringList QLanguageFactory::languages() const { return m_languages; }
/*!
\return a list of file filters supported by this factory
\note This list is NEVER empty and the last item is always "All files
(*)"
*/
QStringList QLanguageFactory::fileFilters() const {
QStringList l;
foreach (QString lng, m_languages)
l << tr("%1 files (*.%2)").arg(lng, m_data[lng].extensions.join(" *."));
l << tr("All files (*)");
return l;
}
/*!
\param e target editor
\param file filename displayed by the editor
The \a file parameter may actuall be either a filename, an extension or
the name of the language, checked in that order.
If it is a filename, complete extension as higher priority than simple
extension (see QFileInfo suffix() and completeSuffix()).
Matches are first done case-sensitively.
If no matching language definition is found for all three possible
interpretations of the \a file parameter, the same search is done
case-insensitively.
If no matching language is found the previous language
definition/completion engine of the editor are removed, leaving it blank, and
the format scheme of the document is set to the defaultFormatScheme()
*/
void QLanguageFactory::setLanguage(QEditor *e, const QString &file) {
QString lang;
QFileInfo inf(file);
const QString ext = inf.suffix(), cext = inf.completeSuffix();
// qDebug("suff:%s; compSuff:%s", qPrintable(ext), qPrintable(cext));
QLanguageDefinition *oldLang = e->languageDefinition();
if (file.length()) {
QList<Qt::CaseSensitivity> lcs;
lcs << Qt::CaseSensitive << Qt::CaseInsensitive;
foreach (Qt::CaseSensitivity cs, lcs) {
int n = 0, idx = -1;
QStringList ext_langs, cext_langs, fcext_langs;
foreach (QString lang, m_languages) {
const QStringList &exts = m_data[lang].extensions;
// qDebug("%s in (%s) ?", qPrintable(ext),
// qPrintable(exts.join(" ")));
foreach (QString x, exts) {
if (!x.compare(ext, cs))
ext_langs << lang;
if (!x.compare(cext, cs))
cext_langs << lang;
if (!x.compare(file, cs))
fcext_langs << lang;
}
if (!lang.compare(file, cs))
idx = n;
++n;
}
if (cext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = cext_langs.first();
} else if (ext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = ext_langs.first();
} else if (fcext_langs.count()) {
// TODO : use MIME types to resolve ambiguity
lang = fcext_langs.first();
} else if (idx != -1) {
lang = m_languages.at(idx);
}
if (lang.length())
break;
}
}
if (lang.isEmpty()) {
// qDebug("no lang match for %s", qPrintable(file));
e->setLanguageDefinition(0);
e->setCompletionEngine(0);
e->document()->setFormatScheme(m_defaultFormatScheme);
if (oldLang)
e->highlight();
} else {
// qDebug("lang match for %s : %s", qPrintable(file), qPrintable(lang));
const LangData &data = m_data[lang];
e->setLanguageDefinition(data.d);
e->setCompletionEngine(data.e ? data.e->clone() : 0);
e->document()->setFormatScheme(data.s ? data.s : m_defaultFormatScheme);
if (oldLang != data.d)
e->highlight();
}
}
/*!
\brief Adds a language to the factory
\param d language data
\note The language data will overwrite any existing one for the same
language
*/
void QLanguageFactory::addLanguage(const QLanguageFactory::LangData &d) {
m_data[d.lang] = d;
if (!d.e) {
foreach (QCodeCompletionEngine *e, m_unusedEngines) {
if (e->language() == d.lang) {
m_data[d.lang].e = e;
break;
}
}
}
if (!m_languages.contains(d.lang))
m_languages << d.lang;
}
/*!
\brief Lookup language data for a matching language
The primary purpose of this function is to make it easy to create
configuration dialogs (mainly for format schemes). Beware though : some
language may use the default format scheme. It is recommended to check for
that before modifying a format scheme or users might be surprised...
\warning This function will lead to crashes if you pass it a language
name not contained in languages().
*/
const QLanguageFactory::LangData &
QLanguageFactory::languageData(const QString &lang) {
return m_data[lang];
}
/*!
\brief Registers a new completion engine
\note This engine will NOT be used if there are no language definition
for the language it supports...
*/
void QLanguageFactory::addCompletionEngine(QCodeCompletionEngine *e) {
foreach (QString l, m_languages) {
if (l == e->language()) {
m_data[l].e = e;
return;
}
}
m_unusedEngines << e;
}
/*!
\brief Fetches syntax definitions from files in \a path
*/
void QLanguageFactory::addDefinitionPath(const QString &path) {
QDir d(path);
foreach (QString f, d.entryList(QDir::Files | QDir::Readable)) {
#ifdef QNFA_BUILD
if (f.endsWith(".qnfa")) {
// qDebug("loading file %s", qPrintable(f));
QFileInfo info(d.filePath(f));
QString specificFormatScheme =
QDir(info.path()).filePath(info.baseName() + ".qxf");
QFormatScheme *scheme = m_defaultFormatScheme;
if (QFile::exists(specificFormatScheme)) {
scheme = new QFormatScheme(specificFormatScheme);
}
LangData data;
QNFADefinition::load(d.filePath(f), &data, scheme);
// qDebug("%s : (%s | %s)", qPrintable(data.lang),
// qPrintable(data.mime), qPrintable(data.extensions.join(", ")));
addLanguage(data);
// addLanguageDefinition(new QNFADefinition(d.filePath(f), this));
}
#endif
}
}
/*! @} */