diff options
author | jkobus <jaroslaw.kobus@digia.com> | 2013-08-14 13:52:13 +0200 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@digia.com> | 2013-08-29 08:54:04 +0200 |
commit | 33a7952745571576fb955fd33bc96e86f0e456fd (patch) | |
tree | e9eae74813d85ce1bcb75fbe73d9d4916ce62531 /src/plugins/diffeditor/diffeditorwidget.cpp | |
parent | a06da47d5b74f9d680b2201e218c1df87f023faa (diff) | |
download | qt-creator-33a7952745571576fb955fd33bc96e86f0e456fd.tar.gz |
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 <orgads@gmail.com>
Reviewed-by: Petar Perisin <petar.perisin@gmail.com>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@digia.com>
Diffstat (limited to 'src/plugins/diffeditor/diffeditorwidget.cpp')
-rw-r--r-- | src/plugins/diffeditor/diffeditorwidget.cpp | 196 |
1 files changed, 169 insertions, 27 deletions
diff --git a/src/plugins/diffeditor/diffeditorwidget.cpp b/src/plugins/diffeditor/diffeditorwidget.cpp index aff227c8b5..3f19b6b991 100644 --- a/src/plugins/diffeditor/diffeditorwidget.cpp +++ b/src/plugins/diffeditor/diffeditorwidget.cpp @@ -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 +BaseTextEditorWidget *DiffEditorWidget::rightEditor() const { return m_rightEditor; } @@ -1150,18 +1283,20 @@ void DiffEditorWidget::showDiff() clear(); - QString leftText, rightText; + QList<QPair<DiffEditorWidget::DiffFileInfo, QString> > leftDocs, rightDocs; + QString leftTexts, rightTexts; int blockNumber = 0; QChar separator = QLatin1Char('\n'); for (int i = 0; i < m_contextFileData.count(); i++) { + QString leftText, rightText; const FileData &contextFileData = m_contextFileData.at(i); int leftLineNumber = 0; int rightLineNumber = 0; m_leftEditor->setFileInfo(blockNumber, contextFileData.leftFileInfo); m_rightEditor->setFileInfo(blockNumber, contextFileData.rightFileInfo); - leftText += separator; - rightText += separator; + leftText = separator; + rightText = separator; blockNumber++; for (int j = 0; j < contextFileData.chunks.count(); j++) { @@ -1199,13 +1334,20 @@ void DiffEditorWidget::showDiff() blockNumber++; } } + leftTexts += leftText; + rightTexts += rightText; + leftDocs.append(qMakePair(contextFileData.leftFileInfo, leftText)); + rightDocs.append(qMakePair(contextFileData.rightFileInfo, rightText)); } - if (leftText.isEmpty() && rightText.isEmpty()) + if (leftTexts.isEmpty() && rightTexts.isEmpty()) return; - m_leftEditor->setPlainText(leftText); - m_rightEditor->setPlainText(rightText); + m_leftEditor->setDocuments(leftDocs); + m_rightEditor->setDocuments(rightDocs); + + m_leftEditor->setPlainText(leftTexts); + m_rightEditor->setPlainText(rightTexts); colorDiff(m_contextFileData); |