Commit 65ca06e0 authored by Leandro Melo's avatar Leandro Melo
Browse files

Generalized Utils::unCommentSelection; Started implementing editor details...

Generalized Utils::unCommentSelection; Started implementing editor details (configuration by highlight definition, actions).
parent c8441462
......@@ -28,13 +28,92 @@
**************************************************************************/
#include "uncommentselection.h"
#include <QtCore/QtGlobal>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextCursor>
#include <QtGui/QTextBlock>
#include <QtGui/QTextDocument>
void Utils::unCommentSelection(QPlainTextEdit *edit)
using namespace Utils;
CommentDefinition::CommentDefinition() :
m_afterWhiteSpaces(false),
m_singleLine(QLatin1String("//")),
m_multiLineStart(QLatin1String("/*")),
m_multiLineEnd(QLatin1String("*/"))
{}
CommentDefinition &CommentDefinition::setAfterWhiteSpaces(const bool afterWhiteSpaces)
{
m_afterWhiteSpaces = afterWhiteSpaces;
return *this;
}
CommentDefinition &CommentDefinition::setSingleLine(const QString &singleLine)
{
m_singleLine = singleLine;
return *this;
}
CommentDefinition &CommentDefinition::setMultiLineStart(const QString &multiLineStart)
{
m_multiLineStart = multiLineStart;
return *this;
}
CommentDefinition &CommentDefinition::setMultiLineEnd(const QString &multiLineEnd)
{
m_multiLineEnd = multiLineEnd;
return *this;
}
bool CommentDefinition::isAfterWhiteSpaces() const
{ return m_afterWhiteSpaces; }
const QString &CommentDefinition::singleLine() const
{ return m_singleLine; }
const QString &CommentDefinition::multiLineStart() const
{ return m_multiLineStart; }
const QString &CommentDefinition::multiLineEnd() const
{ return m_multiLineEnd; }
bool CommentDefinition::hasSingleLineStyle() const
{ return !m_singleLine.isEmpty(); }
bool CommentDefinition::hasMultiLineStyle() const
{ return !m_multiLineStart.isEmpty() && !m_multiLineEnd.isEmpty(); }
namespace {
bool isComment(const QString &text,
int index,
const CommentDefinition &definition,
const QString & (CommentDefinition::* comment) () const)
{
const QString &commentType = ((definition).*(comment))();
const int length = commentType.length();
Q_ASSERT(text.length() - index >= length);
int i = 0;
while (i < length) {
if (text.at(index + i) != commentType.at(i))
return false;
++i;
}
return true;
}
} // namespace anynomous
void Utils::unCommentSelection(QPlainTextEdit *edit, const CommentDefinition &definition)
{
if (!definition.hasSingleLineStyle() && !definition.hasMultiLineStyle())
return;
QTextCursor cursor = edit->textCursor();
QTextDocument *doc = cursor.document();
cursor.beginEditBlock();
......@@ -53,78 +132,107 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
endBlock = endBlock.previous();
}
bool doCStyleUncomment = false;
bool doCStyleComment = false;
bool doCppStyleUncomment = false;
bool doMultiLineStyleUncomment = false;
bool doMultiLineStyleComment = false;
bool doSingleLineStyleUncomment = false;
bool hasSelection = cursor.hasSelection();
if (hasSelection) {
if (hasSelection && definition.hasMultiLineStyle()) {
QString startText = startBlock.text();
int startPos = start - startBlock.position();
const int multiLineStartLength = definition.multiLineStart().length();
bool hasLeadingCharacters = !startText.left(startPos).trimmed().isEmpty();
if ((startPos >= 2
&& startText.at(startPos-2) == QLatin1Char('/')
&& startText.at(startPos-1) == QLatin1Char('*'))) {
startPos -= 2;
start -= 2;
}
bool hasSelStart = (startPos < startText.length() - 1
&& startText.at(startPos) == QLatin1Char('/')
&& startText.at(startPos+1) == QLatin1Char('*'));
if (startPos >= multiLineStartLength
&& isComment(startText,
startPos - multiLineStartLength,
definition,
&CommentDefinition::multiLineStart)) {
startPos -= multiLineStartLength;
start -= multiLineStartLength;
}
bool hasSelStart = (startPos < startText.length() - multiLineStartLength
&& isComment(startText,
startPos,
definition,
&CommentDefinition::multiLineStart));
QString endText = endBlock.text();
int endPos = end - endBlock.position();
bool hasTrailingCharacters = !endText.left(endPos).remove(QLatin1String("//")).trimmed().isEmpty()
&& !endText.mid(endPos).trimmed().isEmpty();
if ((endPos <= endText.length() - 2
&& endText.at(endPos) == QLatin1Char('*')
&& endText.at(endPos+1) == QLatin1Char('/'))) {
endPos += 2;
end += 2;
const int multiLineEndLength = definition.multiLineEnd().length();
bool hasTrailingCharacters =
!endText.left(endPos).remove(definition.singleLine()).trimmed().isEmpty()
&& !endText.mid(endPos).trimmed().isEmpty();
if (endPos <= endText.length() - multiLineEndLength
&& isComment(endText, endPos, definition, &CommentDefinition::multiLineEnd)) {
endPos += multiLineEndLength;
end += multiLineEndLength;
}
bool hasSelEnd = (endPos >= 2
&& endText.at(endPos-2) == QLatin1Char('*')
&& endText.at(endPos-1) == QLatin1Char('/'));
bool hasSelEnd = (endPos >= multiLineEndLength
&& isComment(endText,
endPos - multiLineEndLength,
definition,
&CommentDefinition::multiLineEnd));
doCStyleUncomment = hasSelStart && hasSelEnd;
doCStyleComment = !doCStyleUncomment && (hasLeadingCharacters || hasTrailingCharacters);
doMultiLineStyleUncomment = hasSelStart && hasSelEnd;
doMultiLineStyleComment = !doMultiLineStyleUncomment
&& (hasLeadingCharacters
|| hasTrailingCharacters
|| !definition.hasSingleLineStyle());
} else if (!hasSelection && !definition.hasSingleLineStyle()) {
QString text = startBlock.text().trimmed();
doMultiLineStyleUncomment = text.startsWith(definition.multiLineStart())
&& text.endsWith(definition.multiLineEnd());
doMultiLineStyleComment = !doMultiLineStyleUncomment && !text.isEmpty();
start = startBlock.position();
end = endBlock.position() + endBlock.length() - 1;
}
if (doCStyleUncomment) {
if (doMultiLineStyleUncomment) {
cursor.setPosition(end);
cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2);
cursor.movePosition(QTextCursor::PreviousCharacter,
QTextCursor::KeepAnchor,
definition.multiLineEnd().length());
cursor.removeSelectedText();
cursor.setPosition(start);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
cursor.movePosition(QTextCursor::NextCharacter,
QTextCursor::KeepAnchor,
definition.multiLineStart().length());
cursor.removeSelectedText();
} else if (doCStyleComment) {
} else if (doMultiLineStyleComment) {
cursor.setPosition(end);
cursor.insertText(QLatin1String("*/"));
cursor.insertText(definition.multiLineEnd());
cursor.setPosition(start);
cursor.insertText(QLatin1String("/*"));
cursor.insertText(definition.multiLineStart());
} else {
endBlock = endBlock.next();
doCppStyleUncomment = true;
doSingleLineStyleUncomment = true;
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
QString text = block.text().trimmed();
if (!text.isEmpty() && !text.startsWith(QLatin1String("//"))) {
doCppStyleUncomment = false;
if (!text.isEmpty() && !text.startsWith(definition.singleLine())) {
doSingleLineStyleUncomment = false;
break;
}
}
const int singleLineLength = definition.singleLine().length();
for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
if (doCppStyleUncomment) {
if (doSingleLineStyleUncomment) {
QString text = block.text();
int i = 0;
while (i < text.size() - 1) {
if (text.at(i) == QLatin1Char('/')
&& text.at(i + 1) == QLatin1Char('/')) {
while (i <= text.size() - singleLineLength) {
if (isComment(text, i, definition, &CommentDefinition::singleLine)) {
cursor.setPosition(block.position() + i);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2);
cursor.movePosition(QTextCursor::NextCharacter,
QTextCursor::KeepAnchor,
singleLineLength);
cursor.removeSelectedText();
break;
}
......@@ -136,8 +244,11 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
QString text = block.text();
foreach(QChar c, text) {
if (!c.isSpace()) {
cursor.setPosition(block.position());
cursor.insertText(QLatin1String("//"));
if (definition.isAfterWhiteSpaces())
cursor.setPosition(block.position() + text.indexOf(c));
else
cursor.setPosition(block.position());
cursor.insertText(definition.singleLine());
break;
}
}
......@@ -146,10 +257,10 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
}
// adjust selection when commenting out
if (hasSelection && !doCStyleUncomment && !doCppStyleUncomment) {
if (hasSelection && !doMultiLineStyleUncomment && !doSingleLineStyleUncomment) {
cursor = edit->textCursor();
if (!doCStyleComment)
start = startBlock.position(); // move the double slashes into the selection
if (!doMultiLineStyleComment)
start = startBlock.position(); // move the comment into the selection
int lastSelPos = anchorIsStart ? cursor.position() : cursor.anchor();
if (anchorIsStart) {
cursor.setPosition(start);
......@@ -163,4 +274,3 @@ void Utils::unCommentSelection(QPlainTextEdit *edit)
cursor.endEditBlock();
}
......@@ -32,13 +32,42 @@
#include "utils_global.h"
#include <QtCore/QString>
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
QT_END_NAMESPACE
namespace Utils {
QTCREATOR_UTILS_EXPORT void unCommentSelection(QPlainTextEdit *edit);
class QTCREATOR_UTILS_EXPORT CommentDefinition
{
public:
CommentDefinition();
CommentDefinition &setAfterWhiteSpaces(const bool);
CommentDefinition &setSingleLine(const QString &singleLine);
CommentDefinition &setMultiLineStart(const QString &multiLineStart);
CommentDefinition &setMultiLineEnd(const QString &multiLineEnd);
bool isAfterWhiteSpaces() const;
const QString &singleLine() const;
const QString &multiLineStart() const;
const QString &multiLineEnd() const;
bool hasSingleLineStyle() const;
bool hasMultiLineStyle() const;
private:
bool m_afterWhiteSpaces;
QString m_singleLine;
QString m_multiLineStart;
QString m_multiLineEnd;
};
QTCREATOR_UTILS_EXPORT
void unCommentSelection(QPlainTextEdit *edit,
const CommentDefinition &definiton = CommentDefinition());
} // end of namespace Utils
......
......@@ -43,9 +43,50 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QFileInfo>
#include <QDebug>
using namespace GenericEditor;
using namespace Internal;
Editor::Editor(QWidget *parent) : TextEditor::BaseTextEditor(parent)
{
connect(file(), SIGNAL(changed()), this, SLOT(configure()));
}
void Editor::unCommentSelection()
{
Utils::unCommentSelection(this, m_commentDefinition);
}
TextEditor::BaseTextEditorEditable *Editor::createEditableInterface()
{
EditorEditable *editable = new EditorEditable(this);
return editable;
}
void Editor::configure()
{
const QString &mimeType = Core::ICore::instance()->mimeDatabase()->findByFile(
QFileInfo(file()->fileName())).type();
baseTextDocument()->setMimeType(mimeType);
try {
const QString &definitionId =
GenericEditorPlugin::instance()->definitionIdByMimeType(mimeType);
QSharedPointer<HighlightDefinition> definition =
GenericEditorPlugin::instance()->definition(definitionId);
baseTextDocument()->setSyntaxHighlighter(new Highlighter(definition->initialContext()));
m_commentDefinition.setAfterWhiteSpaces(definition->isCommentAfterWhiteSpaces());
m_commentDefinition.setSingleLine(definition->singleLineComment());
m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart());
m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd());
} catch (const HighlighterException &) {
// No highlighter will be set.
}
}
EditorEditable::EditorEditable(Editor *editor) :
TextEditor::BaseTextEditorEditable(editor)
{
......@@ -68,34 +109,7 @@ bool EditorEditable::duplicateSupported() const
Core::IEditor *EditorEditable::duplicate(QWidget *parent)
{
Editor *newEditor = new Editor(editor()->mimeType(), parent);
Editor *newEditor = new Editor(parent);
newEditor->duplicateFrom(editor());
return newEditor->editableInterface();
}
bool EditorEditable::open(const QString &fileName)
{
if (TextEditor::BaseTextEditorEditable::open(fileName)) {
editor()->setMimeType(
Core::ICore::instance()->mimeDatabase()->findByFile(QFileInfo(fileName)).type());
return true;
}
return false;
}
Editor::Editor(const QString &definitionId, QWidget *parent) : TextEditor::BaseTextEditor(parent)
{
try {
QSharedPointer<HighlightDefinition> definition =
GenericEditorPlugin::instance()->definition(definitionId);
baseTextDocument()->setSyntaxHighlighter(new Highlighter(definition->initialContext()));
} catch (const HighlighterException &) {
// No highlighter will be set.
}
}
TextEditor::BaseTextEditorEditable *Editor::createEditableInterface()
{
EditorEditable *editable = new EditorEditable(this);
return editable;
}
......@@ -31,6 +31,7 @@
#define GENERICEDITOR_H
#include <texteditor/basetexteditor.h>
#include <utils/uncommentselection.h>
#include <QtCore/QList>
......@@ -41,12 +42,27 @@ QT_END_NAMESPACE
namespace GenericEditor {
namespace Internal {
class Editor;
class Editor : public TextEditor::BaseTextEditor
{
Q_OBJECT
public:
Editor(QWidget *parent = 0);
virtual void unCommentSelection();
protected:
virtual TextEditor::BaseTextEditorEditable *createEditableInterface();
private slots:
void configure();
private:
Utils::CommentDefinition m_commentDefinition;
};
class EditorEditable : public TextEditor::BaseTextEditorEditable
{
Q_OBJECT
public:
EditorEditable(Editor *editor);
......@@ -56,22 +72,12 @@ protected:
virtual bool isTemporary() const;
virtual bool duplicateSupported() const;
virtual Core::IEditor *duplicate(QWidget *parent);
virtual bool open(const QString & fileName);
private:
QList<int> m_context;
};
class Editor : public TextEditor::BaseTextEditor
{
Q_OBJECT
public:
Editor(const QString &definitionId, QWidget *parent = 0);
protected:
virtual TextEditor::BaseTextEditorEditable *createEditableInterface();
};
} // namespace Internal
} // namespace GenericEditor
......
......@@ -30,22 +30,41 @@
#include "editorfactory.h"
#include "genericeditorconstants.h"
#include "editor.h"
#include "genericeditorplugin.h"
#include <coreplugin/editormanager/editormanager.h>
using namespace GenericEditor;
using namespace Internal;
EditorFactory::EditorFactory(QObject *parent) :
Core::IEditorFactory(parent)
{}
EditorFactory::EditorFactory(QObject *parent) : Core::IEditorFactory(parent)
{
// Note: This is temporary until it is definied how definition files should be "integrated".
m_mimeTypes << QLatin1String(GenericEditor::Constants::C_HEADER_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::C_SOURCE_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::CPP_HEADER_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::CPP_SOURCE_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::CSS_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::FORTRAN_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::HTML_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::JAVA_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::JAVASCRIPT_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::OBJECTIVEC_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::PERL_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::PHP_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::PYTHON_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::RUBY_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::SQL_MIMETYPE)
<< QLatin1String(GenericEditor::Constants::TCL_MIMETYPE);
}
EditorFactory::~EditorFactory()
{}
Core::IEditor *EditorFactory::createEditor(QWidget *parent)
{
Editor *genericEditor = createGenericEditor(parent);
Editor *genericEditor = new Editor(parent);
GenericEditorPlugin::instance()->initializeEditor(genericEditor);
return genericEditor->editableInterface();
}
......@@ -67,6 +86,3 @@ Core::IFile *EditorFactory::open(const QString &fileName)
Core::IEditor *iface = Core::EditorManager::instance()->openEditor(fileName, id());
return iface ? iface->file() : 0;
}
void EditorFactory::addMimeType(const QString &mimeType)
{ m_mimeTypes.append(mimeType); }
......@@ -47,21 +47,13 @@ public:
EditorFactory(QObject *parent = 0);
virtual ~EditorFactory();
// Currently there are language specific factores which configure the correct highlighter.
// Would it be a good idea if the createEditor method also received the mime type? This would
// also discard the necessity of overriding the open method.
virtual Core::IEditor *createEditor(QWidget *parent);
virtual QStringList mimeTypes() const;
virtual QString id() const;
virtual QString displayName() const;
virtual Core::IFile *open(const QString &fileName);
protected:
void addMimeType(const QString &mimeType);
private:
virtual Editor *createGenericEditor(QWidget *parent) = 0;
private:
QStringList m_mimeTypes;
};
......
......@@ -8,7 +8,6 @@ CONFIG += help
HEADERS += \
genericeditorplugin.h \
progressdata.h \
languagespecificfactories.h \
specificrules.h \
rule.h \
reuse.h \
......@@ -28,7 +27,6 @@ HEADERS += \
SOURCES += \
genericeditorplugin.cpp \
progressdata.cpp \
languagespecificfactories.cpp \
specificrules.cpp \
rule.cpp \
keywordlist.cpp \
......
include(../../plugins/coreplugin/coreplugin.pri)
include(../../plugins/texteditor/texteditor.pri)
include(../../libs/utils/utils.pri)
......@@ -28,12 +28,13 @@
**************************************************************************/
#include "genericeditorplugin.h"
#include "languagespecificfactories.h"
#include "highlightdefinition.h"
#include "highlightdefinitionhandler.h"
#include "highlighter.h"
#include "highlighterexception.h"
#include "genericeditorconstants.h"
#include "editor.h"
#include "editorfactory.h"
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
......@@ -48,6 +49,7 @@
using namespace GenericEditor;
using namespace Internal;
// Todo: Temp.
const QLatin1String GenericEditorPlugin::kAlertDefinitionId(":/genericeditor/XML/alert.xml");
const QLatin1String GenericEditorPlugin::kCDefinitionId(":/genericeditor/XML/c.xml");
const QLatin1String GenericEditorPlugin::kCppDefinitionId(":/genericeditor/XML/cpp.xml");
......@@ -73,7 +75,8 @@ const QLatin1String GenericEditorPlugin::kTclDefinitionId(":/genericeditor/XML/t
GenericEditorPlugin *GenericEditorPlugin::m_instance = 0;
GenericEditorPlugin::GenericEditorPlugin()
GenericEditorPlugin::GenericEditorPlugin() :
m_actionHandler(0)
{
QTC_ASSERT(!m_instance, return);
m_instance = this;
......@@ -117,7 +120,13 @@ GenericEditorPlugin::GenericEditorPlugin()
}
GenericEditorPlugin::~GenericEditorPlugin()
{}
{
delete m_actionHandler;