Commit 33a79527 authored by jkobus's avatar jkobus Committed by Jarek Kobus
Browse files

Implement syntax highlighting in diff editor



All Qt Creator's main highlighters are used in the first place,
for other mimetypes generic highlighter is used as a fallback.

Task-number: QTCREATORBUG-9580

Change-Id: I863b9085520e5bdda142ce88f2074afeacee0531
Reviewed-by: Orgad Shaneh's avatarOrgad Shaneh <orgads@gmail.com>
Reviewed-by: default avatarPetar Perisin <petar.perisin@gmail.com>
Reviewed-by: default avatarJarek Kobus <jaroslaw.kobus@digia.com>
parent a06da47d
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "cmakehighlighterfactory.h"
#include "cmakeprojectconstants.h"
#include "cmakehighlighter.h"
using namespace CMakeProjectManager::Internal;
CMakeHighlighterFactory::CMakeHighlighterFactory()
{
setId(CMakeProjectManager::Constants::CMAKE_EDITOR_ID);
addMimeType(CMakeProjectManager::Constants::CMAKEMIMETYPE);
}
TextEditor::SyntaxHighlighter *CMakeHighlighterFactory::createHighlighter() const
{
return new CMakeHighlighter;
}
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CMAKEHIGHLIGHTERFACTORY_H
#define CMAKEHIGHLIGHTERFACTORY_H
#include <texteditor/ihighlighterfactory.h>
namespace CMakeProjectManager {
namespace Internal {
class CMakeHighlighterFactory : public TextEditor::IHighlighterFactory
{
Q_OBJECT
public:
CMakeHighlighterFactory();
virtual TextEditor::SyntaxHighlighter *createHighlighter() const;
};
} // namespace Internal
} // namespace CMakeProjectManager
#endif // CMAKEHIGHLIGHTERFACTORY_H
......@@ -12,6 +12,7 @@ HEADERS = cmakeproject.h \
cmakeeditorfactory.h \
cmakeeditor.h \
cmakehighlighter.h \
cmakehighlighterfactory.h \
cmakelocatorfilter.h \
cmakefilecompletionassist.h \
cmakevalidator.h \
......@@ -28,6 +29,7 @@ SOURCES = cmakeproject.cpp \
cmakeeditorfactory.cpp \
cmakeeditor.cpp \
cmakehighlighter.cpp \
cmakehighlighterfactory.cpp \
cmakelocatorfilter.cpp \
cmakefilecompletionassist.cpp \
cmakevalidator.cpp \
......
......@@ -30,6 +30,8 @@ QtcPlugin {
"cmakefilecompletionassist.h",
"cmakehighlighter.cpp",
"cmakehighlighter.h",
"cmakehighlighterfactory.cpp",
"cmakehighlighterfactory.h",
"cmakelocatorfilter.cpp",
"cmakelocatorfilter.h",
"cmakeopenprojectwizard.cpp",
......
......@@ -36,6 +36,7 @@
#include "cmakeprojectconstants.h"
#include "cmakelocatorfilter.h"
#include "cmakefilecompletionassist.h"
#include "cmakehighlighterfactory.h"
#include <coreplugin/featureprovider.h>
#include <coreplugin/icore.h>
......@@ -82,6 +83,7 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
addAutoReleasedObject(new CMakeLocatorFilter);
addAutoReleasedObject(new CMakeFileCompletionAssistProvider(cmp));
addAutoReleasedObject(new CMakeFeatureProvider);
addAutoReleasedObject(new CMakeHighlighterFactory);
return true;
}
......
......@@ -11,6 +11,7 @@ HEADERS += cppeditorplugin.h \
cppfilewizard.h \
cppfunctiondecldeflink.h \
cpphighlighter.h \
cpphighlighterfactory.h \
cpphoverhandler.h \
cppoutline.h \
cppquickfixassistant.h \
......@@ -27,6 +28,7 @@ SOURCES += cppeditorplugin.cpp \
cppfilewizard.cpp \
cppfunctiondecldeflink.cpp \
cpphighlighter.cpp \
cpphighlighterfactory.cpp \
cpphoverhandler.cpp \
cppoutline.cpp \
cppquickfixassistant.cpp \
......
......@@ -37,6 +37,8 @@ QtcPlugin {
"cppfunctiondecldeflink.h",
"cpphighlighter.cpp",
"cpphighlighter.h",
"cpphighlighterfactory.cpp",
"cpphighlighterfactory.h",
"cpphoverhandler.cpp",
"cpphoverhandler.h",
"cppoutline.cpp",
......
......@@ -39,6 +39,7 @@
#include "cppsnippetprovider.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
#include "cpphighlighterfactory.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
......@@ -160,6 +161,7 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err
addAutoReleasedObject(new CppOutlineWidgetFactory);
addAutoReleasedObject(new CppTypeHierarchyFactory);
addAutoReleasedObject(new CppSnippetProvider);
addAutoReleasedObject(new CppHighlighterFactory);
m_quickFixProvider = new CppQuickFixAssistProvider;
addAutoReleasedObject(m_quickFixProvider);
......
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "cpphighlighterfactory.h"
#include "cppeditorconstants.h"
#include "cpphighlighter.h"
using namespace CppEditor::Internal;
CppHighlighterFactory::CppHighlighterFactory()
{
setId(CppEditor::Constants::CPPEDITOR_ID);
addMimeType(CppEditor::Constants::C_SOURCE_MIMETYPE);
addMimeType(CppEditor::Constants::C_HEADER_MIMETYPE);
addMimeType(CppEditor::Constants::CPP_SOURCE_MIMETYPE);
addMimeType(CppEditor::Constants::CPP_HEADER_MIMETYPE);
}
TextEditor::SyntaxHighlighter *CppHighlighterFactory::createHighlighter() const
{
return new CppHighlighter;
}
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPHIGHLIGHTERFACTORY_H
#define CPPHIGHLIGHTERFACTORY_H
#include <texteditor/ihighlighterfactory.h>
namespace CppEditor {
namespace Internal {
class CppHighlighterFactory : public TextEditor::IHighlighterFactory
{
Q_OBJECT
public:
CppHighlighterFactory();
virtual TextEditor::SyntaxHighlighter *createHighlighter() const;
};
} // namespace Internal
} // namespace CppEditor
#endif // CPPHIGHLIGHTERFACTORY_H
......@@ -38,15 +38,20 @@
#include <QToolButton>
#include <texteditor/basetexteditor.h>
#include <texteditor/snippets/snippeteditor.h>
#include <texteditor/basetextdocumentlayout.h>
#include <texteditor/ihighlighterfactory.h>
#include <texteditor/syntaxhighlighter.h>
#include <texteditor/basetextdocument.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <texteditor/displaysettings.h>
#include <texteditor/generichighlighter/highlighter.h>
#include <coreplugin/icore.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/mimedatabase.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/tooltip/tipcontents.h>
#include <utils/tooltip/tooltip.h>
......@@ -55,6 +60,7 @@ static const int BASE_LEVEL = 0;
static const int FILE_LEVEL = 1;
static const int CHUNK_LEVEL = 2;
using namespace Core;
using namespace TextEditor;
namespace DiffEditor {
......@@ -103,7 +109,7 @@ struct FileData {
class DiffViewEditorEditable : public BaseTextEditor
{
Q_OBJECT
Q_OBJECT
public:
DiffViewEditorEditable(BaseTextEditorWidget *editorWidget)
: BaseTextEditor(editorWidget)
......@@ -119,27 +125,50 @@ private slots:
};
class MultiHighlighter : public SyntaxHighlighter
{
Q_OBJECT
public:
MultiHighlighter(DiffViewEditorWidget *editor, QTextDocument *document = 0);
~MultiHighlighter();
virtual void setFontSettings(const TextEditor::FontSettings &fontSettings);
void setDocuments(const QList<QPair<DiffEditorWidget::DiffFileInfo, QString> > &documents);
protected:
virtual void highlightBlock(const QString &text);
private:
DiffViewEditorWidget *m_editor;
QMap<QString, IHighlighterFactory *> m_mimeTypeToHighlighterFactory;
QList<SyntaxHighlighter *> m_highlighters;
QList<QTextDocument *> m_documents;
};
////////////////////////
class DiffViewEditorWidget : public SnippetEditorWidget
class DiffViewEditorWidget : public BaseTextEditorWidget
{
Q_OBJECT
public:
struct ExtendedFileInfo
{
DiffEditorWidget::DiffFileInfo fileInfo;
TextEditor::SyntaxHighlighter *highlighter;
};
DiffViewEditorWidget(QWidget *parent = 0);
void setSyntaxHighlighter(SyntaxHighlighter *sh) {
baseTextDocument()->setSyntaxHighlighter(sh);
}
// TODO: remove me, codec should be taken from somewhere else
QTextCodec *codec() const {
return const_cast<QTextCodec *>(baseTextDocument()->codec());
}
QMap<int, int> skippedLines() const { return m_skippedLines; }
// block number, file info
QMap<int, DiffEditorWidget::DiffFileInfo> fileInfo() const { return m_fileInfo; }
void setLineNumber(int blockNumber, int lineNumber);
void setFileInfo(int blockNumber, const DiffEditorWidget::DiffFileInfo &fileInfo) { m_fileInfo[blockNumber] = fileInfo; setSeparator(blockNumber, true); }
void setFileInfo(int blockNumber, const DiffEditorWidget::DiffFileInfo &fileInfo);
void setSkippedLines(int blockNumber, int skippedLines) { m_skippedLines[blockNumber] = skippedLines; setSeparator(blockNumber, true); }
void setSeparator(int blockNumber, bool separator) { m_separators[blockNumber] = separator; }
bool isFileLine(int blockNumber) const { return m_fileInfo.contains(blockNumber); }
......@@ -149,7 +178,8 @@ public:
void clearAll();
void clearAll(const QString &message);
void clearAllData();
QTextBlock firstVisibleBlock() const { return SnippetEditorWidget::firstVisibleBlock(); }
QTextBlock firstVisibleBlock() const { return BaseTextEditorWidget::firstVisibleBlock(); }
void setDocuments(const QList<QPair<DiffEditorWidget::DiffFileInfo, QString> > &documents);
public slots:
void setDisplaySettings(const DisplaySettings &ds);
......@@ -183,20 +213,108 @@ private:
const QTextBlock &block, int top);
void jumpToOriginalFile(const QTextCursor &cursor);
// block number, visual line number.
QMap<int, int> m_lineNumbers;
int m_lineNumberDigits;
// block number, fileInfo
// block number, fileInfo. Set for file lines only.
QMap<int, DiffEditorWidget::DiffFileInfo> m_fileInfo;
// block number, skipped lines
// block number, skipped lines. Set for chunk lines only.
QMap<int, int> m_skippedLines;
// block number, separator. Separator used as lines alignment and inside skipped lines
// block number, separator. Set for file, chunk or span line.
QMap<int, bool> m_separators;
bool m_inPaintEvent;
QColor m_fileLineForeground;
QColor m_chunkLineForeground;
QColor m_textForeground;
MultiHighlighter *m_highlighter;
};
MultiHighlighter::MultiHighlighter(DiffViewEditorWidget *editor, QTextDocument *document)
: SyntaxHighlighter(document),
m_editor(editor)
{
const QList<IHighlighterFactory *> &factories =
ExtensionSystem::PluginManager::getObjects<TextEditor::IHighlighterFactory>();
foreach (IHighlighterFactory *factory, factories) {
QStringList mimeTypes = factory->mimeTypes();
foreach (const QString &mimeType, mimeTypes)
m_mimeTypeToHighlighterFactory.insert(mimeType, factory);
}
}
MultiHighlighter::~MultiHighlighter()
{
setDocuments(QList<QPair<DiffEditorWidget::DiffFileInfo, QString> >());
}
void MultiHighlighter::setFontSettings(const TextEditor::FontSettings &fontSettings)
{
foreach (SyntaxHighlighter *highlighter, m_highlighters) {
if (highlighter) {
highlighter->setFontSettings(fontSettings);
highlighter->rehighlight();
}
}
}
void MultiHighlighter::setDocuments(const QList<QPair<DiffEditorWidget::DiffFileInfo, QString> > &documents)
{
// clear old documents
qDeleteAll(m_documents);
m_documents.clear();
qDeleteAll(m_highlighters);
m_highlighters.clear();
const MimeDatabase *mimeDatabase = ICore::mimeDatabase();
// create new documents
for (int i = 0; i < documents.count(); i++) {
DiffEditorWidget::DiffFileInfo fileInfo = documents.at(i).first;
const QString contents = documents.at(i).second;
QTextDocument *document = new QTextDocument(contents);
const MimeType mimeType = mimeDatabase->findByFile(QFileInfo(fileInfo.fileName));
SyntaxHighlighter *highlighter = 0;
if (const IHighlighterFactory *factory = m_mimeTypeToHighlighterFactory.value(mimeType.type())) {
highlighter = factory->createHighlighter();
if (highlighter)
highlighter->setDocument(document);
}
if (!highlighter) {
TextEditor::Highlighter *h = new TextEditor::Highlighter();
highlighter = h;
h->setMimeType(mimeType);
highlighter->setDocument(document);
}
m_documents.append(document);
m_highlighters.append(highlighter);
}
}
void MultiHighlighter::highlightBlock(const QString &text)
{
Q_UNUSED(text)
QTextBlock block = currentBlock();
const int fileIndex = m_editor->fileIndexForBlockNumber(block.blockNumber());
if (fileIndex < 0)
return;
SyntaxHighlighter *currentHighlighter = m_highlighters.at(fileIndex);
if (!currentHighlighter)
return;
// find block in document
QTextDocument *currentDocument = m_documents.at(fileIndex);
if (!currentDocument)
return;
QTextBlock documentBlock = currentDocument->findBlockByNumber(
block.blockNumber() - m_editor->blockNumberForFileIndex(fileIndex));
QList<QTextLayout::FormatRange> formats = documentBlock.layout()->additionalFormats();
setExtraAdditionalFormats(block, formats);
}
void DiffViewEditorEditable::slotTooltipRequested(TextEditor::ITextEditor *editor, const QPoint &globalPoint, int position)
{
DiffViewEditorWidget *ew = qobject_cast<DiffViewEditorWidget *>(editorWidget());
......@@ -216,7 +334,7 @@ void DiffViewEditorEditable::slotTooltipRequested(TextEditor::ITextEditor *edito
}
DiffViewEditorWidget::DiffViewEditorWidget(QWidget *parent)
: SnippetEditorWidget(parent), m_lineNumberDigits(1), m_inPaintEvent(false)
: BaseTextEditorWidget(parent), m_lineNumberDigits(1), m_inPaintEvent(false)
{
DisplaySettings settings = displaySettings();
settings.m_textWrapping = false;
......@@ -225,22 +343,25 @@ DiffViewEditorWidget::DiffViewEditorWidget(QWidget *parent)
settings.m_displayFoldingMarkers = true;
settings.m_markTextChanges = false;
settings.m_highlightBlocks = false;
SnippetEditorWidget::setDisplaySettings(settings);
BaseTextEditorWidget::setDisplaySettings(settings);
setCodeFoldingSupported(true);
setFrameStyle(QFrame::NoFrame);
m_highlighter = new MultiHighlighter(this, baseTextDocument()->document());
baseTextDocument()->setSyntaxHighlighter(m_highlighter);
}
void DiffViewEditorWidget::setDisplaySettings(const DisplaySettings &ds)
{
DisplaySettings settings = displaySettings();
settings.m_visualizeWhitespace = ds.m_visualizeWhitespace;
SnippetEditorWidget::setDisplaySettings(settings);
BaseTextEditorWidget::setDisplaySettings(settings);
}
void DiffViewEditorWidget::setFontSettings(const TextEditor::FontSettings &fs)
{
SnippetEditorWidget::setFontSettings(fs);
BaseTextEditorWidget::setFontSettings(fs);
m_fileLineForeground = fs.formatFor(C_DIFF_FILE_LINE).foreground();
m_chunkLineForeground = fs.formatFor(C_DIFF_CONTEXT_LINE).foreground();
m_textForeground = fs.toTextCharFormat(C_TEXT).foreground().color();
......@@ -318,6 +439,12 @@ void DiffViewEditorWidget::setLineNumber(int blockNumber, int lineNumber)
m_lineNumberDigits = qMax(m_lineNumberDigits, lineNumberString.count());
}
void DiffViewEditorWidget::setFileInfo(int blockNumber, const DiffEditorWidget::DiffFileInfo &fileInfo)
{
m_fileInfo[blockNumber] = fileInfo;
setSeparator(blockNumber, true);
}
int DiffViewEditorWidget::blockNumberForFileIndex(int fileIndex) const
{
if (fileIndex < 0 || fileIndex >= m_fileInfo.count())
......@@ -359,6 +486,7 @@ void DiffViewEditorWidget::clearAll(const QString &message)
clear();
clearAllData();
setPlainText(message);
m_highlighter->setDocuments(QList<QPair<DiffEditorWidget::DiffFileInfo, QString> >());
}
void DiffViewEditorWidget::clearAllData()
......@@ -370,9 +498,14 @@ void DiffViewEditorWidget::clearAllData()
m_separators.clear();
}
void DiffViewEditorWidget::setDocuments(const QList<QPair<DiffEditorWidget::DiffFileInfo, QString> > &documents)
{
m_highlighter->setDocuments(documents);
}
void DiffViewEditorWidget::scrollContentsBy(int dx, int dy)
{
SnippetEditorWidget::scrollContentsBy(dx, dy);
BaseTextEditorWidget::scrollContentsBy(dx, dy);
// TODO: update only chunk lines
viewport()->update();
}
......@@ -423,7 +556,7 @@ void DiffViewEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
e->accept();
return;
}
SnippetEditorWidget::mouseDoubleClickEvent(e);
BaseTextEditorWidget::mouseDoubleClickEvent(e);
}
void DiffViewEditorWidget::jumpToOriginalFile(const QTextCursor &cursor)
......@@ -444,7 +577,7 @@ void DiffViewEditorWidget::jumpToOriginalFile(const QTextCursor &cursor)
void DiffViewEditorWidget::paintEvent(QPaintEvent *e)
{
m_inPaintEvent = true;
SnippetEditorWidget::paintEvent(e);
BaseTextEditorWidget::paintEvent(e);
m_inPaintEvent = false;
QPainter painter(viewport());
......@@ -760,12 +893,12 @@ QTextCodec *DiffEditorWidget::codec() const
return const_cast<QTextCodec *>(m_leftEditor->codec());
}
SnippetEditorWidget *DiffEditorWidget::leftEditor() const
BaseTextEditorWidget *DiffEditorWidget::leftEditor() const
{
return m_leftEditor;
}
SnippetEditorWidget *DiffEditorWidget::rightEditor() const