Allow not only a colon as a keyword-text divider in todos.

This makes possible to scan such things as doxygen \todo, @todo
entries where colons cannot be added after a keyword.

Change-Id: I13c757294c94a1f4758e7dc9634a79ea6e91c68f
Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
This commit is contained in:
Dmitry Savchenko
2012-04-26 20:37:48 +03:00
committed by Eike Ziller
parent b6b2441e55
commit 9fe784115a
3 changed files with 66 additions and 19 deletions

View File

@@ -35,6 +35,7 @@
#include "keyword.h"
#include "ui_keyworddialog.h"
#include "constants.h"
#include "lineparser.h"
#include <QColorDialog>
@@ -124,7 +125,7 @@ void KeywordDialog::setupColorWidgets(const QColor &color)
bool KeywordDialog::canAccept()
{
if (!isKeywordNameCorrect()) {
showError(tr("Keyword cannot be empty, contain spaces or colons."));
showError(tr("Keyword cannot be empty, contain spaces, colons, slashes or asterisks."));
return false;
}
@@ -146,7 +147,7 @@ bool KeywordDialog::isKeywordNameCorrect()
return false;
for (int i = 0; i < name.size(); ++i)
if (name.at(i).isSpace() || name.at(i) == QLatin1Char(':'))
if (LineParser::isKeywordSeparator(name.at(i)))
return false;
return true;

View File

@@ -38,10 +38,6 @@
namespace Todo {
namespace Internal {
LineParser::LineParser()
{
}
LineParser::LineParser(const KeywordList &keywordList)
{
setKeywordList(keywordList);
@@ -59,6 +55,14 @@ QList<TodoItem> LineParser::parse(const QString &line)
return todoItemsFromKeywordEntries(entries);
}
bool LineParser::isKeywordSeparator(const QChar &ch)
{
return ch.isSpace()
|| (ch == QLatin1Char(':'))
|| (ch == QLatin1Char('/'))
|| (ch == QLatin1Char('*'));
}
LineParser::KeywordEntryCandidates LineParser::findKeywordEntryCandidates(const QString &line)
{
KeywordEntryCandidates entryCandidates;
@@ -66,17 +70,14 @@ LineParser::KeywordEntryCandidates LineParser::findKeywordEntryCandidates(const
for (int i = 0; i < m_keywords.count(); ++i) {
int searchFrom = -1;
forever {
const int index = line.lastIndexOf(m_keywords.at(i).name
+ QLatin1Char(':'), searchFrom);
const int index = line.lastIndexOf(m_keywords.at(i).name, searchFrom);
if (index == -1)
break; // 'forever' loop exit condition
searchFrom = index - line.length() - 1;
if (!isFirstCharOfTheWord(index, line))
continue;
if (isKeywordAt(index, line, m_keywords.at(i).name))
entryCandidates.insert(index, i);
}
}
@@ -84,9 +85,25 @@ LineParser::KeywordEntryCandidates LineParser::findKeywordEntryCandidates(const
return entryCandidates;
}
bool LineParser::isKeywordAt(int index, const QString &line, const QString &keyword)
{
if (!isFirstCharOfTheWord(index, line))
return false;
if (!isLastCharOfTheWord(index + keyword.length() - 1, line))
return false;
return true;
}
bool LineParser::isFirstCharOfTheWord(int index, const QString &line)
{
return (index == 0) || !line.at(index - 1).isLetterOrNumber();
return (index == 0) || isKeywordSeparator(line.at(index - 1));
}
bool LineParser::isLastCharOfTheWord(int index, const QString &line)
{
return (index == line.length() - 1) || isKeywordSeparator(line.at(index + 1));
}
QList<LineParser::KeywordEntry> LineParser::keywordEntriesFromCandidates(
@@ -109,15 +126,15 @@ QList<LineParser::KeywordEntry> LineParser::keywordEntriesFromCandidates(
entry.keywordStart = i.key();
entry.keywordIndex = i.value();
int keywordLength = m_keywords.at(entry.keywordIndex).name.length() + 1; // include colon
int keywordLength = m_keywords.at(entry.keywordIndex).name.length();
int entryTextLength = -1;
if (!entries.empty())
entryTextLength = entries.last().keywordStart - (entry.keywordStart + keywordLength);
entry.text = line.mid(entry.keywordStart + keywordLength, entryTextLength).trimmed();
entry.text = line.mid(entry.keywordStart + keywordLength, entryTextLength);
if (entry.text.isEmpty() && !entries.empty())
if (trimSeparators(entry.text).isEmpty() && !entries.empty())
// Take the text form the previous entry, consider:
// '<keyword1>: <keyword2>: <some text>'
entry.text = entries.last().text;
@@ -128,14 +145,36 @@ QList<LineParser::KeywordEntry> LineParser::keywordEntriesFromCandidates(
return entries;
}
QString LineParser::trimSeparators(const QString &string)
{
QString result = string.trimmed();
while (startsWithSeparator(result))
result = result.right(result.length() - 1);
while (endsWithSeparator(result))
result = result.left(result.length() - 1);
return result;
}
bool LineParser::startsWithSeparator(const QString &string)
{
return !string.isEmpty() && isKeywordSeparator(string.at(0));
}
bool LineParser::endsWithSeparator(const QString &string)
{
return !string.isEmpty() && isKeywordSeparator(string.at(string.length() - 1));
}
QList<TodoItem> LineParser::todoItemsFromKeywordEntries(const QList<KeywordEntry> &entries)
{
QList<TodoItem> todoItems;
foreach (const KeywordEntry &entry, entries) {
TodoItem item;
item.text = m_keywords.at(entry.keywordIndex).name
+ QLatin1String(": ") + entry.text;
item.text = m_keywords.at(entry.keywordIndex).name + entry.text;
item.color = m_keywords.at(entry.keywordIndex).color;
item.iconResource = m_keywords.at(entry.keywordIndex).iconResource;
todoItems << item;

View File

@@ -43,12 +43,14 @@ namespace Internal {
class LineParser
{
public:
LineParser();
explicit LineParser(const KeywordList &keywordList);
void setKeywordList(const KeywordList &keywordList);
QList<TodoItem> parse(const QString &line);
// This can also be used from KeywordDialog to avoid code duplication
static bool isKeywordSeparator(const QChar &ch);
private:
// map key here is keyword start position in the text line
@@ -62,8 +64,13 @@ private:
};
KeywordEntryCandidates findKeywordEntryCandidates(const QString &line);
bool isKeywordAt(int index, const QString &line, const QString &keyword);
bool isFirstCharOfTheWord(int index, const QString &line);
bool isLastCharOfTheWord(int index, const QString &line);
QList<KeywordEntry> keywordEntriesFromCandidates(const QMap<int, int> &candidates, const QString &line);
QString trimSeparators(const QString &string);
bool startsWithSeparator(const QString &string);
bool endsWithSeparator(const QString &string);
QList<TodoItem> todoItemsFromKeywordEntries(const QList<KeywordEntry> &entries);
KeywordList m_keywords;