Commit b0b94018 authored by Lorenz Haas's avatar Lorenz Haas Committed by David Schulz

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: default avatarJochen Becher <jochen_becher@gmx.de>
Reviewed-by: default avatarDavid Schulz <david.schulz@theqtcompany.com>
parent a871e053
...@@ -46,11 +46,13 @@ ...@@ -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, ...@@ -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; if (TextEditorWidget *widget = TextEditorWidget::currentTextEditorWidget()) {
if (const TextDocument *doc = widget->textDocument()) {
const QString sourceData = widget->toPlainText(); const QString sourceData = (startPos < 0)
if (sourceData.isEmpty()) ? widget->toPlainText()
return; : Convenience::textAt(widget->textCursor(), startPos, (endPos - startPos));
if (sourceData.isEmpty())
QFutureWatcher<FormatTask> *watcher = new QFutureWatcher<FormatTask>; return;
connect(widget->textDocument(), &TextDocument::contentsChanged, const FormatTask task = FormatTask(widget, doc->filePath().toString(), sourceData,
watcher, &QFutureWatcher<FormatTask>::cancel); command, startPos, endPos);
connect(watcher, SIGNAL(finished()), m_asyncFormatMapper, SLOT(map()));
m_asyncFormatMapper->setMapping(watcher, watcher); QFutureWatcher<FormatTask> *watcher = new QFutureWatcher<FormatTask>;
const QString filePath = widget->textDocument()->filePath().toString(); connect(doc, &TextDocument::contentsChanged,
watcher->setFuture(QtConcurrent::run(&BeautifierPlugin::formatAsync, this, watcher, &QFutureWatcher<FormatTask>::cancel);
FormatTask(widget, filePath, sourceData, command))); connect(watcher, SIGNAL(finished()), m_asyncFormatMapper, SLOT(map()));
m_asyncFormatMapper->setMapping(watcher, watcher);
watcher->setFuture(QtConcurrent::run(&BeautifierPlugin::formatAsync, this, task));
}
}
} }
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) ...@@ -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) ...@@ -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; ...@@ -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: ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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() ...@@ -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() ...@@ -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() ...@@ -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 ...@@ -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 ...@@ -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: ...@@ -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 { ...@@ -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";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment