forked from qt-creator/qt-creator
Beautifier: Support formatting specific lines of file with Uncrustify
It's now possible to format only a specific range of the current file. The used tool, however, needs to support the formatting of fragments like Uncrustify does with --frag. Change-Id: I486a350b6301e4a087619b1e225f2a5c553ff7df Reviewed-by: Jochen Becher <jochen_becher@gmx.de> Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
committed by
David Schulz
parent
a871e053b6
commit
b0b9401870
@@ -46,11 +46,13 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
#include <diffeditor/differ.h>
|
#include <diffeditor/differ.h>
|
||||||
|
#include <texteditor/convenience.h>
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
#include <texteditor/textdocumentlayout.h>
|
#include <texteditor/textdocumentlayout.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
#include <texteditor/texteditorconstants.h>
|
#include <texteditor/texteditorconstants.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/QtConcurrentTools>
|
#include <utils/QtConcurrentTools>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -219,24 +221,28 @@ QString BeautifierPlugin::format(const QString &text, const Command &command,
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeautifierPlugin::formatCurrentFile(const Command &command)
|
void BeautifierPlugin::formatCurrentFile(const Command &command, int startPos, int endPos)
|
||||||
{
|
{
|
||||||
TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget();
|
QTC_ASSERT(startPos <= endPos, return);
|
||||||
if (!widget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString sourceData = widget->toPlainText();
|
if (TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget()) {
|
||||||
if (sourceData.isEmpty())
|
if (const TextDocument *doc = widget->textDocument()) {
|
||||||
return;
|
const QString sourceData = (startPos < 0)
|
||||||
|
? widget->toPlainText()
|
||||||
|
: Convenience::textAt(widget->textCursor(), startPos, (endPos - startPos));
|
||||||
|
if (sourceData.isEmpty())
|
||||||
|
return;
|
||||||
|
const FormatTask task = FormatTask(widget, doc->filePath().toString(), sourceData,
|
||||||
|
command, startPos, endPos);
|
||||||
|
|
||||||
QFutureWatcher<FormatTask> *watcher = new QFutureWatcher<FormatTask>;
|
QFutureWatcher<FormatTask> *watcher = new QFutureWatcher<FormatTask>;
|
||||||
connect(widget->textDocument(), &TextDocument::contentsChanged,
|
connect(doc, &TextDocument::contentsChanged,
|
||||||
watcher, &QFutureWatcher<FormatTask>::cancel);
|
watcher, &QFutureWatcher<FormatTask>::cancel);
|
||||||
connect(watcher, SIGNAL(finished()), m_asyncFormatMapper, SLOT(map()));
|
connect(watcher, SIGNAL(finished()), m_asyncFormatMapper, SLOT(map()));
|
||||||
m_asyncFormatMapper->setMapping(watcher, watcher);
|
m_asyncFormatMapper->setMapping(watcher, watcher);
|
||||||
const QString filePath = widget->textDocument()->filePath().toString();
|
watcher->setFuture(QtConcurrent::run(&BeautifierPlugin::formatAsync, this, task));
|
||||||
watcher->setFuture(QtConcurrent::run(&BeautifierPlugin::formatAsync, this,
|
}
|
||||||
FormatTask(widget, filePath, sourceData, command)));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BeautifierPlugin::formatAsync(QFutureInterface<FormatTask> &future, FormatTask task)
|
void BeautifierPlugin::formatAsync(QFutureInterface<FormatTask> &future, FormatTask task)
|
||||||
@@ -268,6 +274,11 @@ void BeautifierPlugin::formatCurrentFileContinue(QObject *watcher)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task.formattedData.isEmpty()) {
|
||||||
|
showError(tr("Could not format file %1.").arg(task.filePath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QPlainTextEdit *textEditor = task.editor;
|
QPlainTextEdit *textEditor = task.editor;
|
||||||
if (!textEditor) {
|
if (!textEditor) {
|
||||||
showError(tr("File %1 was closed.").arg(task.filePath));
|
showError(tr("File %1 was closed.").arg(task.filePath));
|
||||||
@@ -275,10 +286,14 @@ void BeautifierPlugin::formatCurrentFileContinue(QObject *watcher)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QString sourceData = textEditor->toPlainText();
|
const QString sourceData = textEditor->toPlainText();
|
||||||
const QString formattedData = task.formattedData;
|
const QString formattedData = (task.startPos < 0)
|
||||||
if ((sourceData == formattedData) || formattedData.isEmpty())
|
? task.formattedData
|
||||||
|
: QString(sourceData).replace(task.startPos, (task.endPos - task.startPos),
|
||||||
|
task.formattedData);
|
||||||
|
if (sourceData == formattedData)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// Since QTextCursor does not work properly with folded blocks, all blocks must be unfolded.
|
// Since QTextCursor does not work properly with folded blocks, all blocks must be unfolded.
|
||||||
// To restore the current state at the end, keep track of which block is folded.
|
// To restore the current state at the end, keep track of which block is folded.
|
||||||
QList<int> foldedBlocks;
|
QList<int> foldedBlocks;
|
||||||
|
@@ -50,19 +50,23 @@ class BeautifierAbstractTool;
|
|||||||
struct FormatTask
|
struct FormatTask
|
||||||
{
|
{
|
||||||
FormatTask(QPlainTextEdit *_editor, const QString &_filePath, const QString &_sourceData,
|
FormatTask(QPlainTextEdit *_editor, const QString &_filePath, const QString &_sourceData,
|
||||||
const Command &_command) :
|
const Command &_command, int _startPos = -1, int _endPos = 0) :
|
||||||
editor(_editor),
|
editor(_editor),
|
||||||
filePath(_filePath),
|
filePath(_filePath),
|
||||||
sourceData(_sourceData),
|
sourceData(_sourceData),
|
||||||
command(_command),
|
command(_command),
|
||||||
|
startPos(_startPos),
|
||||||
|
endPos(_endPos),
|
||||||
timeout(false) {}
|
timeout(false) {}
|
||||||
|
|
||||||
QPointer<QPlainTextEdit> editor;
|
QPointer<QPlainTextEdit> editor;
|
||||||
QString filePath;
|
QString filePath;
|
||||||
QString sourceData;
|
QString sourceData;
|
||||||
Command command;
|
Command command;
|
||||||
QString formattedData;
|
int startPos;
|
||||||
|
int endPos;
|
||||||
bool timeout;
|
bool timeout;
|
||||||
|
QString formattedData;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BeautifierPlugin : public ExtensionSystem::IPlugin
|
class BeautifierPlugin : public ExtensionSystem::IPlugin
|
||||||
@@ -79,7 +83,7 @@ public:
|
|||||||
|
|
||||||
QString format(const QString &text, const Command &command, const QString &fileName,
|
QString format(const QString &text, const Command &command, const QString &fileName,
|
||||||
bool *timeout = 0);
|
bool *timeout = 0);
|
||||||
void formatCurrentFile(const Command &command);
|
void formatCurrentFile(const Command &command, int startPos = -1, int endPos = 0);
|
||||||
void formatAsync(QFutureInterface<FormatTask> &future, FormatTask task);
|
void formatAsync(QFutureInterface<FormatTask> &future, FormatTask task);
|
||||||
|
|
||||||
static QString msgCannotGetConfigurationFile(const QString &command);
|
static QString msgCannotGetConfigurationFile(const QString &command);
|
||||||
|
@@ -38,7 +38,6 @@
|
|||||||
|
|
||||||
#include "../beautifierconstants.h"
|
#include "../beautifierconstants.h"
|
||||||
#include "../beautifierplugin.h"
|
#include "../beautifierplugin.h"
|
||||||
#include "../command.h"
|
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
@@ -51,6 +50,7 @@
|
|||||||
#include <cppeditor/cppeditorconstants.h>
|
#include <cppeditor/cppeditorconstants.h>
|
||||||
#include <projectexplorer/projecttree.h>
|
#include <projectexplorer/projecttree.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
|
#include <texteditor/texteditor.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -63,6 +63,8 @@ namespace Uncrustify {
|
|||||||
Uncrustify::Uncrustify(BeautifierPlugin *parent) :
|
Uncrustify::Uncrustify(BeautifierPlugin *parent) :
|
||||||
BeautifierAbstractTool(parent),
|
BeautifierAbstractTool(parent),
|
||||||
m_beautifierPlugin(parent),
|
m_beautifierPlugin(parent),
|
||||||
|
m_formatFile(nullptr),
|
||||||
|
m_formatRange(nullptr),
|
||||||
m_settings(new UncrustifySettings)
|
m_settings(new UncrustifySettings)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -84,6 +86,12 @@ bool Uncrustify::initialize()
|
|||||||
menu->addAction(cmd);
|
menu->addAction(cmd);
|
||||||
connect(m_formatFile, &QAction::triggered, this, &Uncrustify::formatFile);
|
connect(m_formatFile, &QAction::triggered, this, &Uncrustify::formatFile);
|
||||||
|
|
||||||
|
m_formatRange = new QAction(BeautifierPlugin::msgFormatSelectedText(), this);
|
||||||
|
cmd = Core::ActionManager::registerAction(m_formatRange,
|
||||||
|
Constants::Uncrustify::ACTION_FORMATSELECTED);
|
||||||
|
menu->addAction(cmd);
|
||||||
|
connect(m_formatRange, &QAction::triggered, this, &Uncrustify::formatSelectedText);
|
||||||
|
|
||||||
Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu);
|
Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +99,9 @@ bool Uncrustify::initialize()
|
|||||||
|
|
||||||
void Uncrustify::updateActions(Core::IEditor *editor)
|
void Uncrustify::updateActions(Core::IEditor *editor)
|
||||||
{
|
{
|
||||||
m_formatFile->setEnabled(editor && editor->document()->id() == CppEditor::Constants::CPPEDITOR_ID);
|
const bool enabled = (editor && editor->document()->id() == CppEditor::Constants::CPPEDITOR_ID);
|
||||||
|
m_formatFile->setEnabled(enabled);
|
||||||
|
m_formatRange->setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QObject *> Uncrustify::autoReleaseObjects()
|
QList<QObject *> Uncrustify::autoReleaseObjects()
|
||||||
@@ -111,6 +121,32 @@ void Uncrustify::formatFile()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Uncrustify::formatSelectedText()
|
||||||
|
{
|
||||||
|
const QString cfgFileName = configurationFile();
|
||||||
|
if (cfgFileName.isEmpty()) {
|
||||||
|
BeautifierPlugin::showError(BeautifierPlugin::msgCannotGetConfigurationFile(
|
||||||
|
QLatin1String(Constants::Uncrustify::DISPLAY_NAME)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEditor::TextEditorWidget *widget = TextEditor::TextEditorWidget::currentTextEditorWidget();
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTextCursor tc = widget->textCursor();
|
||||||
|
if (tc.hasSelection()) {
|
||||||
|
// Extend selection to full lines
|
||||||
|
const int posSelectionEnd = tc.selectionEnd();
|
||||||
|
tc.movePosition(QTextCursor::StartOfLine);
|
||||||
|
const int startPos = tc.position();
|
||||||
|
tc.setPosition(posSelectionEnd);
|
||||||
|
tc.movePosition(QTextCursor::EndOfLine);
|
||||||
|
const int endPos = tc.position();
|
||||||
|
m_beautifierPlugin->formatCurrentFile(command(cfgFileName, true), startPos, endPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Uncrustify::configurationFile() const
|
QString Uncrustify::configurationFile() const
|
||||||
{
|
{
|
||||||
if (m_settings->useCustomStyle())
|
if (m_settings->useCustomStyle())
|
||||||
@@ -140,7 +176,7 @@ QString Uncrustify::configurationFile() const
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
Command Uncrustify::command(const QString &cfgFile) const
|
Command Uncrustify::command(const QString &cfgFile, bool fragment) const
|
||||||
{
|
{
|
||||||
Command command;
|
Command command;
|
||||||
command.setExecutable(m_settings->command());
|
command.setExecutable(m_settings->command());
|
||||||
@@ -149,6 +185,8 @@ Command Uncrustify::command(const QString &cfgFile) const
|
|||||||
command.addOption(QLatin1String("cpp"));
|
command.addOption(QLatin1String("cpp"));
|
||||||
command.addOption(QLatin1String("-L"));
|
command.addOption(QLatin1String("-L"));
|
||||||
command.addOption(QLatin1String("1-2"));
|
command.addOption(QLatin1String("1-2"));
|
||||||
|
if (fragment)
|
||||||
|
command.addOption(QLatin1String("--frag"));
|
||||||
command.addOption(QLatin1String("-c"));
|
command.addOption(QLatin1String("-c"));
|
||||||
command.addOption(cfgFile);
|
command.addOption(cfgFile);
|
||||||
return command;
|
return command;
|
||||||
|
@@ -58,13 +58,15 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void formatFile();
|
void formatFile();
|
||||||
|
void formatSelectedText();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BeautifierPlugin *m_beautifierPlugin;
|
BeautifierPlugin *m_beautifierPlugin;
|
||||||
QAction *m_formatFile;
|
QAction *m_formatFile;
|
||||||
|
QAction *m_formatRange;
|
||||||
UncrustifySettings *m_settings;
|
UncrustifySettings *m_settings;
|
||||||
QString configurationFile() const;
|
QString configurationFile() const;
|
||||||
Command command(const QString &cfgFile) const;
|
Command command(const QString &cfgFile, bool fragment = false) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Uncrustify
|
} // namespace Uncrustify
|
||||||
|
@@ -37,6 +37,7 @@ namespace Uncrustify {
|
|||||||
|
|
||||||
const char DISPLAY_NAME[] = "Uncrustify";
|
const char DISPLAY_NAME[] = "Uncrustify";
|
||||||
const char ACTION_FORMATFILE[] = "Uncrustify.FormatFile";
|
const char ACTION_FORMATFILE[] = "Uncrustify.FormatFile";
|
||||||
|
const char ACTION_FORMATSELECTED[] = "Uncrustify.FormatSelectedText";
|
||||||
const char MENU_ID[] = "Uncrustify.Menu";
|
const char MENU_ID[] = "Uncrustify.Menu";
|
||||||
const char OPTION_ID[] = "Uncrustify";
|
const char OPTION_ID[] = "Uncrustify";
|
||||||
const char SETTINGS_NAME[] = "uncrustify";
|
const char SETTINGS_NAME[] = "uncrustify";
|
||||||
|
Reference in New Issue
Block a user