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