cpptoolseditorsupport.h 9.37 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** 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.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30 31 32
#ifndef CPPTOOLSEDITORSUPPORT_H
#define CPPTOOLSEDITORSUPPORT_H

33
#include "builtineditordocumentparser.h"
34 35 36 37
#include "cpphighlightingsupport.h"
#include "cppmodelmanager.h"
#include "cppsemanticinfo.h"

38
#include <cplusplus/Control.h>
39 40 41
#include <cplusplus/CppDocument.h>

#include <QFuture>
42 43
#include <QObject>
#include <QPointer>
44
#include <QSharedPointer>
45
#include <QTimer>
con's avatar
con committed
46

47 48 49 50
namespace CPlusPlus {
class AST;
class DeclarationAST;
} // namespace CPlusPlus
Roberto Raggi's avatar
Roberto Raggi committed
51

con's avatar
con committed
52
namespace TextEditor {
53
class BaseTextEditor;
hjk's avatar
hjk committed
54
class TextMark;
55
} // namespace TextEditor
con's avatar
con committed
56 57 58

namespace CppTools {

59 60
class CppCompletionAssistProvider;

61 62 63 64 65
/**
 * \brief The CppEditorSupport class oversees the actions that happen when a C++ text editor updates
 *        its document.
 *
 * The following steps are taken:
66
 * 1. the text editor document fires a contentsChanged() signal that triggers updateDocument
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
 * 2. update document will start a timer, or reset the timer if it was already running. This way
 *    subsequent updates (e.g. keypresses) get bunched together instead of running the subsequent
 *    actions for every key press
 * 3. when the timer from step 2 fires, updateDocumentNow() is triggered. That tells the
 *    model-manager to update the CPlusPlus::Document by re-indexing it.
 * 4. when the model-manager finishes, it fires a documentUpdated(CPlusPlus::Document::Ptr) signal,
 *    that is connected to onDocumentUpdated(CPlusPlus::Document::Ptr), which does 4 things:
 *    a) updates the ifdeffed-out blocks in the EditorUpdate
 *    b) calls setExtraDiagnostics with the diagnostics from the parser, which in turn calls
 *       onDiagnosticsChanged on the UI thread, and that schedules an editor update timer. When this
 *       timer fires, updateEditorNow() is called, which will apply the updates to the editor.
 *    c) a semantic-info recalculation is started in a future
 *    d) the documentUpdated() signal is emitted, which can be used by a widget to do things
 * 5. semantic-info calculation from 4c is done by a future that calls recalculateSemanticInfoNow(),
 *    which emits semanticInfoUpdated() when it is finished. Editors can also listen in on this
 *    signal to do things like highlighting the local usages.
 * 6. the semanticInfoUpdated() is connected to the startHighlighting() slot, which will start
 *    another future for doing the semantic highlighting. The highlighterStarted signal is emitted,
 *    with the highlighting future as a parameter, so editors can hook it up to a QFutureWatcher
 *    and get notifications.
 *
 * Both the semantic info calculation and the highlighting calculation will cancel an already running
 * future. They will also check that the result of a previous step is not already outdated, meaning
 * that they check the revision of the editor document to see if a user changed the document while
 * the calculation was running.
 */
class CPPTOOLS_EXPORT CppEditorSupport: public QObject
con's avatar
con committed
94 95 96
{
    Q_OBJECT

97 98
    typedef TextEditor::BlockRange BlockRange;

con's avatar
con committed
99
public:
100
    CppEditorSupport(Internal::CppModelManager *modelManager, TextEditor::BaseTextEditor *textEditor);
con's avatar
con committed
101 102
    virtual ~CppEditorSupport();

103
    QString fileName() const;
con's avatar
con committed
104

105
    QByteArray contents() const;
106
    unsigned editorRevision() const;
con's avatar
con committed
107

108 109
    void setExtraDiagnostics(const QString &key,
                             const QList<CPlusPlus::Document::DiagnosticMessage> &messages);
110
    void setIfdefedOutBlocks(const QList<BlockRange> &ifdefedOutBlocks);
111

112 113 114 115
    /// True after the document was parsed/updated for the first time
    /// and the first semantic info calculation was started.
    bool initialized();

116
    /// Retrieve the semantic info, which will get recalculated on the current
117 118
    /// thread if it is outdate. Will not emit the semanticInfoUpdated() signal.
    SemanticInfo recalculateSemanticInfo();
119

120 121
    CPlusPlus::Document::Ptr lastSemanticInfoDocument() const;

122 123
    enum ForceReason {
        NoForce,
124
        ForceDueToInvalidSemanticInfo,
125 126 127
        ForceDueEditorRequest
    };

128 129 130
    /// Recalculates the semantic info in a future, and will emit the
    /// semanticInfoUpdated() signal when finished.
    /// Requires that initialized() is true.
131 132
    /// \param forceReason the reason to force, if any
    void recalculateSemanticInfoDetached(ForceReason forceReason);
133

134 135
    CppCompletionAssistProvider *completionAssistProvider() const;

136
    BuiltinEditorDocumentParser::Ptr documentParser();
137

138 139 140
    /// Checks whether the document is (re)parsed or about to be (re)parsed.
    bool isUpdatingDocument();

141 142 143 144
signals:
    void documentUpdated();
    void diagnosticsChanged();
    void semanticInfoUpdated(CppTools::SemanticInfo);
Eike Ziller's avatar
Eike Ziller committed
145
    void highlighterStarted(QFuture<TextEditor::HighlightingResult> *, unsigned revision);
146 147

private slots:
148 149
    void onMimeTypeChanged();

150 151 152
    void onAboutToReload();
    void onReloadFinished();

con's avatar
con committed
153 154 155
    void updateDocument();
    void updateDocumentNow();

156
    void onDocumentUpdated(CPlusPlus::Document::Ptr doc);
157
    void startHighlighting(ForceReason forceReason = NoForce);
158 159 160 161 162 163

    void onDiagnosticsChanged();

    void updateEditor();
    void updateEditorNow();

164 165 166
    void onCurrentEditorChanged();
    void releaseResources();

167 168 169 170 171 172 173 174 175 176 177 178
private:
    struct EditorUpdates {
        EditorUpdates()
            : revision(-1)
        {}
        int revision;
        QList<QTextEdit::ExtraSelection> selections;
        QList<BlockRange> ifdefedOutBlocks;
    };

    enum {
        UpdateDocumentDefaultInterval = 150,
179 180
        UpdateEditorInterval = 300,
        EditorHiddenGCTimeout = 2 * 60 * 1000 // 2 minutes
181 182 183
    };

private:
184 185 186 187 188 189 190 191 192 193
    class FuturizedTopLevelDeclarationProcessor: public CPlusPlus::TopLevelDeclarationProcessor
    {
    public:
        FuturizedTopLevelDeclarationProcessor(QFutureInterface<void> &future): m_future(future) {}
        bool processDeclaration(CPlusPlus::DeclarationAST *) { return !isCanceled(); }
        bool isCanceled() { return m_future.isCanceled(); }
    private:
        QFutureInterface<void> m_future;
    };

194
    SemanticInfo::Source currentSource(bool force);
195 196 197
    SemanticInfo recalculateSemanticInfoNow(const SemanticInfo::Source &source,
                                            bool emitSignalWhenFinished,
                                            FuturizedTopLevelDeclarationProcessor *processor = 0);
198 199 200
    void recalculateSemanticInfoDetached_helper(QFutureInterface<void> &future,
                                                SemanticInfo::Source source);

201 202 203 204
    bool isSemanticInfoValid() const;
    SemanticInfo semanticInfo() const;
    void setSemanticInfo(const SemanticInfo &semanticInfo, bool emitSignal = true);

205 206
    BuiltinEditorDocumentParser::Ptr documentParser_internal() const;
    void setDocumentParser_internal(const BuiltinEditorDocumentParser::Ptr &updater);
207

con's avatar
con committed
208
private:
209 210
    Internal::CppModelManager *m_modelManager;
    QPointer<TextEditor::BaseTextEditor> m_textEditor;
211
    TextEditor::BaseTextDocument *m_editorDocument;
212 213 214 215
    QTimer *m_updateDocumentTimer;
    int m_updateDocumentInterval;
    unsigned m_revision;

216 217 218
    QTimer *m_editorGCTimer;
    bool m_editorVisible;

219
    // content caching
220
    mutable QMutex m_cachedContentsLock;
221
    mutable QByteArray m_cachedContents;
222
    mutable int m_cachedContentsEditorRevision;
223
    bool m_fileIsBeingReloaded;
224 225 226 227 228 229 230 231 232 233 234 235

    QTimer *m_updateEditorTimer;
    EditorUpdates m_editorUpdates;

    QMutex m_diagnosticsMutex;
    QHash<QString, QList<CPlusPlus::Document::DiagnosticMessage> > m_allDiagnostics;

    // Semantic info:
    bool m_initialized;
    mutable QMutex m_lastSemanticInfoLock;
    SemanticInfo m_lastSemanticInfo;
    QFuture<void> m_futureSemanticInfo;
236
    mutable QMutex m_documentParserLock;
237
    BuiltinEditorDocumentParser::Ptr m_documentParser;
238
    QFuture<void> m_documentParserFuture;
239 240 241

    // Highlighting:
    unsigned m_lastHighlightRevision;
242
    bool m_lastHighlightOnCompleteSemanticInfo;
243 244
    QFuture<TextEditor::HighlightingResult> m_highlighter;
    QScopedPointer<CppTools::CppHighlightingSupport> m_highlightingSupport;
245 246

    // Completion:
247
    CppCompletionAssistProvider *m_completionAssistProvider;
con's avatar
con committed
248 249
};

hjk's avatar
hjk committed
250
} // namespace CppTools
con's avatar
con committed
251 252

#endif // CPPTOOLSEDITORSUPPORT_H