C++: Automatic Doxygen comment blocks generation

This improves our completion support for documentation
comments. It's now possible to have a Doxygen block
generated when hitting enter after a /** or /*! comment
start. A couple other related options are also available.

Task-number: QTCREATORBUG-2752
Task-number: QTCREATORBUG-3165

Change-Id: I1c81c0b4b370eb1d409ef72a9c7f22c357f202f4
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@nokia.com>
Reviewed-by: Christian Kamm <christian.d.kamm@nokia.com>
This commit is contained in:
Leandro Melo
2011-12-07 15:05:02 +01:00
parent 24b4c12737
commit beede7d7cf
13 changed files with 723 additions and 15 deletions

View File

@@ -69,6 +69,8 @@
#include <cpptools/cppcodestylesettings.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/doxygengenerator.h>
#include <cpptools/cpptoolssettings.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -415,6 +417,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
, m_inRenameChanged(false)
, m_firstRenameChange(false)
, m_objcEnabled(false)
, m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings())
{
m_initialized = false;
qRegisterMetaType<CppEditor::Internal::SemanticInfo>("CppEditor::Internal::SemanticInfo");
@@ -451,6 +454,11 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
m_declDefLinkFinder = new FunctionDeclDefLinkFinder(this);
connect(m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
connect(CppTools::CppToolsSettings::instance(),
SIGNAL(commentsSettingsChanged(CppTools::CommentsSettings)),
this,
SLOT(onCommentsSettingsChanged(CppTools::CommentsSettings)));
}
CPPEditorWidget::~CPPEditorWidget()
@@ -1552,7 +1560,8 @@ void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
void CPPEditorWidget::keyPressEvent(QKeyEvent *e)
{
if (m_currentRenameSelection == NoCurrentRenameSelection) {
TextEditor::BaseTextEditorWidget::keyPressEvent(e);
if (!handleDocumentationComment(e))
TextEditor::BaseTextEditorWidget::keyPressEvent(e);
return;
}
@@ -2239,4 +2248,99 @@ void CPPEditorWidget::abortDeclDefLink()
m_declDefLink.clear();
}
bool CPPEditorWidget::handleDocumentationComment(QKeyEvent *e)
{
if (!m_commentsSettings.m_enableDoxygen
&& !m_commentsSettings.m_leadingAsterisks) {
return false;
}
if (e->key() == Qt::Key_Return
|| e->key() == Qt::Key_Enter) {
QTextCursor cursor = textCursor();
if (!autoCompleter()->isInComment(cursor))
return false;
// We are interested on two particular cases:
// 1) The cursor is right after a /** or /*! and the user pressed enter. If Doxygen
// is enabled we need to generate an entire comment block.
// 2) The cursor is already in the middle of a multi-line comment and the user pressed
// enter. If leading asterisk(s) is set we need to write a comment continuation
// with those.
if (m_commentsSettings.m_enableDoxygen
&& cursor.positionInBlock() >= 3) {
const int pos = cursor.position();
if (characterAt(pos - 3) == QChar('/')
&& characterAt(pos - 2) == QChar('*')
&& (characterAt(pos - 1) == QChar('*')
|| characterAt(pos - 1) == QChar('!'))) {
CppTools::DoxygenGenerator doxygen;
doxygen.setAddLeadingAsterisks(m_commentsSettings.m_leadingAsterisks);
doxygen.setGenerateBrief(m_commentsSettings.m_generateBrief);
doxygen.setStartComment(false);
if (characterAt(pos - 1) == QLatin1Char('!'))
doxygen.setStyle(CppTools::DoxygenGenerator::QtStyle);
else
doxygen.setStyle(CppTools::DoxygenGenerator::JavaStyle);
// Move until we reach any possibly meaningful content.
while (document()->characterAt(cursor.position()).isSpace())
cursor.movePosition(QTextCursor::NextCharacter);
const QString &comment = doxygen.generate(cursor);
if (!comment.isEmpty()) {
cursor.beginEditBlock();
cursor.setPosition(pos);
cursor.insertText(comment);
cursor.setPosition(pos - 3, QTextCursor::KeepAnchor);
indent(document(), cursor, QChar::Null);
cursor.endEditBlock();
e->accept();
return true;
}
cursor.setPosition(pos);
}
}
if (!m_commentsSettings.m_leadingAsterisks)
return false;
const QString &text = cursor.block().text();
const int length = text.length();
int offset = 0;
for (; offset < length; ++offset) {
const QChar &current = text.at(offset);
if (!current.isSpace())
break;
}
if (offset < length
&& (text.at(offset) == QLatin1Char('*')
|| (offset < length - 1
&& text.at(offset) == QLatin1Char('/')
&& text.at(offset + 1) == QLatin1Char('*')))) {
QString newLine(QLatin1Char('\n'));
newLine.append(QString(offset, QLatin1Char(' ')));
if (text.at(offset) == QLatin1Char('/')) {
newLine.append(QLatin1String(" *"));
} else {
int start = offset;
while (offset < length && text.at(offset) == QLatin1Char('*'))
++offset;
newLine.append(QString(offset - start, QLatin1Char('*')));
}
cursor.insertText(newLine);
e->accept();
return true;
}
}
return false;
}
void CPPEditorWidget::onCommentsSettingsChanged(const CppTools::CommentsSettings &settings)
{
m_commentsSettings = settings;
}
#include "cppeditor.moc"