1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "clangformatplugin.h"
27 
28 #include "clangformatconfigwidget.h"
29 #include "clangformatconstants.h"
30 #include "clangformatindenter.h"
31 #include "clangformatutils.h"
32 
33 #include <utils/qtcassert.h>
34 
35 #include <coreplugin/actionmanager/actioncontainer.h>
36 #include <coreplugin/actionmanager/actionmanager.h>
37 #include <coreplugin/actionmanager/command.h>
38 #include <coreplugin/coreconstants.h>
39 #include <coreplugin/editormanager/editormanager.h>
40 #include <coreplugin/editormanager/ieditor.h>
41 #include <coreplugin/icontext.h>
42 #include <coreplugin/icore.h>
43 #include <coreplugin/idocument.h>
44 
45 #include <cppeditor/cppeditorconstants.h>
46 
47 #include <cpptools/cppcodestylepreferencesfactory.h>
48 #include <cpptools/cpptoolsconstants.h>
49 #include <cpptools/cppmodelmanager.h>
50 
51 #include <projectexplorer/kitinformation.h>
52 #include <projectexplorer/project.h>
53 #include <projectexplorer/session.h>
54 #include <projectexplorer/target.h>
55 
56 #include <texteditor/icodestylepreferences.h>
57 #include <texteditor/texteditorsettings.h>
58 
59 #include <clang/Format/Format.h>
60 
61 #include <utils/algorithm.h>
62 #include <utils/infobar.h>
63 
64 #include <QAction>
65 #include <QDebug>
66 #include <QMainWindow>
67 #include <QMessageBox>
68 #include <QMenu>
69 
70 using namespace ProjectExplorer;
71 
72 namespace ClangFormat {
73 
74 class ClangFormatStyleFactory : public CppTools::CppCodeStylePreferencesFactory
75 {
76 public:
createCodeStyleEditor(TextEditor::ICodeStylePreferences * preferences,QWidget * parent=nullptr)77     TextEditor::CodeStyleEditorWidget *createCodeStyleEditor(
78         TextEditor::ICodeStylePreferences *preferences, QWidget *parent = nullptr) override
79     {
80         Q_UNUSED(preferences);
81         if (!parent)
82             return new ClangFormatConfigWidget;
83         return new ClangFormatConfigWidget(SessionManager::startupProject());
84     }
85 
createEditor(TextEditor::ICodeStylePreferences *,QWidget *) const86     QWidget *createEditor(TextEditor::ICodeStylePreferences *, QWidget *) const override
87     {
88         return nullptr;
89     }
90 
createIndenter(QTextDocument * doc) const91     TextEditor::Indenter *createIndenter(QTextDocument *doc) const override
92     {
93         return new ClangFormatIndenter(doc);
94     }
95 };
96 
replaceCppCodeStyle()97 static void replaceCppCodeStyle()
98 {
99     using namespace TextEditor;
100     TextEditorSettings::unregisterCodeStyleFactory(CppTools::Constants::CPP_SETTINGS_ID);
101     ICodeStylePreferencesFactory *factory = new ClangFormatStyleFactory();
102     TextEditorSettings::registerCodeStyleFactory(factory);
103 }
104 
initialize(const QStringList & arguments,QString * errorString)105 bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorString)
106 {
107     Q_UNUSED(arguments)
108     Q_UNUSED(errorString)
109     replaceCppCodeStyle();
110 
111     Core::ActionContainer *contextMenu = Core::ActionManager::actionContainer(
112         CppEditor::Constants::M_CONTEXT);
113     if (contextMenu) {
114         auto openClangFormatConfigAction
115             = new QAction(tr("Open Used .clang-format Configuration File"), this);
116         Core::Command *command
117             = Core::ActionManager::registerAction(openClangFormatConfigAction,
118                                                   Constants::OPEN_CURRENT_CONFIG_ID);
119         contextMenu->addSeparator();
120         contextMenu->addAction(command);
121 
122         if (Core::EditorManager::currentEditor()) {
123             const Core::IDocument *doc = Core::EditorManager::currentEditor()->document();
124             if (doc)
125                 openClangFormatConfigAction->setData(doc->filePath().toString());
126         }
127 
128         connect(openClangFormatConfigAction,
129                 &QAction::triggered,
130                 this,
131                 [openClangFormatConfigAction]() {
132                     const QString fileName = openClangFormatConfigAction->data().toString();
133                     if (!fileName.isEmpty()) {
134                         const QString clangFormatConfigPath = configForFile(
135                             Utils::FilePath::fromString(fileName));
136                         Core::EditorManager::openEditor(clangFormatConfigPath);
137                     }
138                 });
139 
140         connect(Core::EditorManager::instance(),
141                 &Core::EditorManager::currentEditorChanged,
142                 this,
143                 [openClangFormatConfigAction](Core::IEditor *editor) {
144                     if (!editor)
145                         return;
146 
147                     const Core::IDocument *doc = editor->document();
148                     if (doc)
149                         openClangFormatConfigAction->setData(doc->filePath().toString());
150                 });
151     }
152 #ifndef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
153 #ifdef _MSC_VER
154 #pragma message( \
155     "ClangFormat: building against unmodified Clang, see README.md for more info")
156 #else
157 #warning ClangFormat: building against unmodified Clang, see README.md for more info
158 #endif
159     static const char clangFormatFormatWarningKey[] = "ClangFormatFormatWarning";
160     if (!Core::ICore::infoBar()->canInfoBeAdded(clangFormatFormatWarningKey))
161         return true;
162     Utils::InfoBarEntry
163         info(clangFormatFormatWarningKey,
164              tr("The ClangFormat plugin has been built against an unmodified Clang. "
165                 "You might experience formatting glitches in certain circumstances. "
166                 "See https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/README.md for more "
167                  "information."),
168              Utils::InfoBarEntry::GlobalSuppression::Enabled);
169     Core::ICore::infoBar()->addInfo(info);
170 #endif
171     return true;
172 }
173 
174 } // namespace ClangFormat
175