";
generateText(brief, node, marker);
if (!relative || node == relative)
out() << " More...
\n";
}
}
void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker)
{
if (!inner->includes().isEmpty()) {
out() << " toc = node->doc().tableOfContents();
if (toc.isEmpty())
return;
QString nodeName = "";
if (node != relative)
nodeName = node->name();
QStringList sectionNumber;
int columnSize = 0;
QString tdTag;
if (numColumns > 1) {
tdTag = "";
out() << "\n" << tdTag << "\n";
}
// disable nested links in table of contents
inContents = true;
inLink = true;
for (int i = 0; i < toc.size(); ++i) {
Atom *atom = toc.at(i);
int nextLevel = atom->string().toInt();
if (nextLevel > (int)sectioningUnit)
continue;
if (sectionNumber.size() < nextLevel) {
do {
out() << "";
sectionNumber.append("1");
} while (sectionNumber.size() < nextLevel);
} else {
while (sectionNumber.size() > nextLevel) {
out() << " \n";
sectionNumber.removeLast();
}
sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
}
int numAtoms;
Text headingText = Text::sectionHeading(atom);
if (sectionNumber.size() == 1 && columnSize > toc.size() / numColumns) {
out() << "" << tdTag << "\n";
sectionNumber.removeLast();
}
if (numColumns > 1)
out() << " \n";
inContents = false;
inLink = false;
}
#if 0
void HtmlGenerator::generateNavigationBar(const NavigationBar& bar,
const Node *node,
CodeMarker *marker)
{
if (bar.prev.begin() != 0 || bar.current.begin() != 0 ||
bar.next.begin() != 0) {
out() << "";
if (bar.prev.begin() != 0) {
#if 0
out() << "[Prev: ";
generateText(section.previousHeading(), node, marker);
out() << "]\n";
#endif
}
if (bar.current.begin() != 0) {
out() << "[Home]\n";
}
if (bar.next.begin() != 0) {
out() << "[Next: ";
generateText(Text::sectionHeading(bar.next.begin()), node, marker);
out() << "]\n";
}
out() << " \n";
}
}
#endif
QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker)
{
QList sections;
QList::ConstIterator s;
sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay);
if (sections.isEmpty())
return QString();
QString fileName = fileBase(inner) + "-members." + fileExtension(inner);
beginSubPage(inner->location(), fileName);
QString title = "List of All Members for " + inner->name();
generateHeader(title, inner, marker, false);
generateTitle(title, Text(), SmallSubTitle, inner, marker);
out() << "This is the complete list of members for ";
generateFullName(inner, 0, marker);
out() << ", including inherited members. \n";
Section section = sections.first();
generateSectionList(section, 0, marker, CodeMarker::SeparateList);
generateFooter();
endSubPage();
return fileName;
}
QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker,
CodeMarker::Status status)
{
QList sections = marker->sections(inner, CodeMarker::Summary, status);
QMutableListIterator j(sections);
while (j.hasNext()) {
if (j.next().members.size() == 0)
j.remove();
}
if (sections.isEmpty())
return QString();
int i;
QString title;
QString fileName;
if (status == CodeMarker::Compat) {
title = "Qt 3 Support Members for " + inner->name();
fileName = fileBase(inner) + "-qt3." + fileExtension(inner);
} else {
title = "Obsolete Members for " + inner->name();
fileName = fileBase(inner) + "-obsolete." + fileExtension(inner);
}
beginSubPage(inner->location(), fileName);
generateHeader(title, inner, marker, false);
generateTitle(title, Text(), SmallSubTitle, inner, marker);
if (status == CodeMarker::Compat) {
out() << "The following class members are part of the "
"Qt 3 support layer. "
"They are provided to help you port old code to Qt 4. We advise against "
"using them in new code. \n";
} else {
out() << "The following class members are obsolete. They are provided to keep "
"old source code working. We strongly advise against using them in new "
"code. \n";
}
out() << "\n";
for (i = 0; i < sections.size(); ++i) {
out() << "" << protect(sections.at(i).name) << "\n";
generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
}
sections = marker->sections(inner, CodeMarker::Detailed, status);
for (i = 0; i < sections.size(); ++i) {
out() << " \n";
out() << "" << protect(sections.at(i).name) << "\n";
NodeList::ConstIterator m = sections.at(i).members.begin();
while (m != sections.at(i).members.end()) {
if ((*m)->access() != Node::Private)
generateDetailedMember(*m, inner, marker);
++m;
}
}
generateFooter();
endSubPage();
return fileName;
}
void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker,
const QMap &classMap)
{
if (classMap.isEmpty())
return;
QMap topLevel;
QMap::ConstIterator c = classMap.begin();
while (c != classMap.end()) {
const ClassNode *classe = static_cast(*c);
if (classe->baseClasses().isEmpty())
topLevel.insert(classe->name(), classe);
++c;
}
QStack > stack;
stack.push(topLevel);
out() << "\n";
while (!stack.isEmpty()) {
if (stack.top().isEmpty()) {
stack.pop();
out() << " \n";
} else {
const ClassNode *child = static_cast(*stack.top().begin());
out() << "";
generateFullName(child, relative, marker);
out() << "\n";
stack.top().erase(stack.top().begin());
QMap newTop;
foreach (const RelatedClass &d, child->derivedClasses()) {
if (d.access != Node::Private)
newTop.insert(d.node->name(), d.node);
}
if (!newTop.isEmpty()) {
stack.push(newTop);
out() << "\n";
}
}
}
}
void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker,
const QMap &nodeMap)
{
out() << "\n";
int row = 0;
foreach (const QString &name, nodeMap.keys()) {
const Node *node = nodeMap[name];
if (++row % 2 == 1)
out() << "";
else
out() << " ";
out() << "";
generateFullName(node, relative, marker);
out() << " | ";
if (!(node->type() == Node::Fake)) {
Text brief = node->doc().trimmedBriefText(name);
if (!brief.isEmpty()) {
out() << "";
generateText(brief, node, marker);
out() << " | ";
}
} else {
out() << "";
out() << protect(node->doc().briefText().toString());
out() << " | ";
}
out() << " \n";
}
out() << " \n";
}
void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker,
const QMap &classMap)
{
const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'
const int NumColumns = 4; // number of columns in the result
if (classMap.isEmpty())
return;
/*
First, find out the common prefix of all non-namespaced classes.
For Qt, the prefix is Q. It can easily be derived from the first
and last classes in alphabetical order (QAccel and QXtWidget in Qt 2.1).
*/
int commonPrefixLen = 0;
QString commonPrefix;
QString first;
QString last;
QMap::const_iterator iter = classMap.begin();
while (iter != classMap.end()) {
if (!iter.key().contains("::")) {
first = iter.key();
break;
}
++iter;
}
if (first.isEmpty())
first = classMap.begin().key();
iter = classMap.end();
while (iter != classMap.begin()) {
--iter;
if (!iter.key().contains("::")) {
last = iter.key();
break;
}
}
if (last.isEmpty())
last = classMap.begin().key();
if (classMap.size() > 1) {
while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1
&& first[commonPrefixLen] == last[commonPrefixLen])
++commonPrefixLen;
}
commonPrefix = first.left(commonPrefixLen);
/*
Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z,
underscore (_). QAccel will fall in paragraph 10 (A) and
QXtWidget in paragraph 33 (X). This is the only place where we
assume that NumParagraphs is 37. Each paragraph is a
QMap.
*/
QMap paragraph[NumParagraphs];
QString paragraphName[NumParagraphs];
QMap::ConstIterator c = classMap.begin();
while (c != classMap.end()) {
QStringList pieces = c.key().split("::");
QString key;
if (pieces.size() == 1)
key = pieces.last().mid(commonPrefixLen).toLower();
else
key = pieces.last().toLower();
int paragraphNo = NumParagraphs - 1;
if (key[0].digitValue() != -1) {
paragraphNo = key[0].digitValue();
} else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
paragraphNo = 10 + key[0].unicode() - 'a';
}
paragraphName[paragraphNo] = key[0].toUpper();
paragraph[paragraphNo].insert(key, c.value());
++c;
}
/*
Each paragraph j has a size: paragraph[j].count(). In the
discussion, we will assume paragraphs 0 to 5 will have sizes
3, 1, 4, 1, 5, 9.
We now want to compute the paragraph offset. Paragraphs 0 to 6
start at offsets 0, 3, 4, 8, 9, 14, 23.
*/
int paragraphOffset[NumParagraphs + 1];
int i, j, k;
paragraphOffset[0] = 0;
for (j = 0; j < NumParagraphs; j++)
paragraphOffset[j + 1] = paragraphOffset[j] + paragraph[j].count();
int firstOffset[NumColumns + 1];
int currentOffset[NumColumns];
int currentParagraphNo[NumColumns];
int currentOffsetInParagraph[NumColumns];
int numRows = (classMap.count() + NumColumns - 1) / NumColumns;
int curParagNo = 0;
for (i = 0; i < NumColumns; i++) {
firstOffset[i] = qMin(i * numRows, classMap.size());
currentOffset[i] = firstOffset[i];
for (j = curParagNo; j < NumParagraphs; j++) {
if (paragraphOffset[j] > firstOffset[i])
break;
if (paragraphOffset[j] <= firstOffset[i])
curParagNo = j;
}
currentParagraphNo[i] = curParagNo;
currentOffsetInParagraph[i] = firstOffset[i] -
paragraphOffset[curParagNo];
}
firstOffset[NumColumns] = classMap.count();
out() << "\n";
for (k = 0; k < numRows; k++) {
out() << "\n";
for (i = 0; i < NumColumns; i++) {
if (currentOffset[i] >= firstOffset[i + 1]) {
// this column is finished
out() << "\n | \n";
} else {
while (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count()) {
++currentParagraphNo[i];
currentOffsetInParagraph[i] = 0;
}
out() << "";
if (currentOffsetInParagraph[i] == 0) {
// start a new paragraph
out() << "" << paragraphName[currentParagraphNo[i]] << " ";
}
out() << " | \n";
// bad loop
QMap::Iterator it;
it = paragraph[currentParagraphNo[i]].begin();
for (j = 0; j < currentOffsetInParagraph[i]; j++)
++it;
out() << "";
// Previously, we used generateFullName() for this, but we
// require some special formatting.
out() << "";
QStringList pieces = fullName(it.value(), relative, marker).split("::");
out() << protect(pieces.last());
out() << "";
if (pieces.size() > 1) {
out() << " (";
generateFullName(it.value()->parent(), relative, marker);
out() << ")";
}
out() << " | \n";
currentOffset[i]++;
currentOffsetInParagraph[i]++;
}
}
out() << " \n";
}
out() << " \n";
}
void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker)
{
out() << "";
for (int i = 0; i < 26; i++) {
QChar ch('a' + i);
out() << QString("%2 ").arg(ch).arg(ch.toUpper());
}
out() << " \n";
char nextLetter = 'a';
char currentLetter;
#if 1
out() << "\n";
#endif
QMap >::ConstIterator f = funcIndex.begin();
while (f != funcIndex.end()) {
#if 1
out() << "- ";
#else
out() << "
";
#endif
out() << protect(f.key()) << ":";
currentLetter = f.key()[0].unicode();
while (islower(currentLetter) && currentLetter >= nextLetter) {
out() << QString("").arg(nextLetter);
nextLetter++;
}
QMap::ConstIterator s = (*f).begin();
while (s != (*f).end()) {
out() << " ";
generateFullName((*s)->parent(), relative, marker, *s);
++s;
}
#if 1
out() << " ";
#else
out() << "";
#endif
out() << "\n";
++f;
}
#if 1
out() << " \n";
#endif
}
void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker)
{
QMap::ConstIterator it = legaleseTexts.begin();
while (it != legaleseTexts.end()) {
Text text = it.key();
out() << " \n";
generateText(text, relative, marker);
out() << "\n";
do {
out() << "- ";
generateFullName(it.value(), relative, marker);
out() << "
\n";
++it;
} while (it != legaleseTexts.end() && it.key() == text);
out() << " \n";
}
}
void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative,
CodeMarker *marker, CodeMarker::SynopsisStyle style)
{
QString marked = marker->markedUpSynopsis(node, relative, style);
QRegExp templateTag("(<[^@>]*>)");
if (marked.indexOf(templateTag) != -1) {
QString contents = protect(marked.mid(templateTag.pos(1),
templateTag.cap(1).length()));
marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
contents);
}
marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])@param>"), "\\1\\2");
marked.replace("<@param>", "");
marked.replace("@param>", "");
if (style == CodeMarker::Summary)
marked.replace("@name>", "b>");
if (style == CodeMarker::SeparateList) {
QRegExp extraRegExp("<@extra>.*@extra>");
extraRegExp.setMinimal(true);
marked.replace(extraRegExp, "");
} else {
marked.replace("<@extra>", " ");
marked.replace("@extra>", "");
}
if (style != CodeMarker::Detailed) {
marked.replace("<@type>", "");
marked.replace("@type>", "");
}
out() << highlightedCode(marked, marker, relative);
}
void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */)
{
QMap > fakeNodeMap;
QMap groupTitlesMap;
QMap uncategorizedNodeMap;
QRegExp singleDigit("\\b([0-9])\\b");
const NodeList children = tre->root()->childNodes();
foreach (Node *child, children) {
if (child->type() == Node::Fake && child != relative) {
FakeNode *fakeNode = static_cast(child);
// Check whether the page is part of a group or is the group
// definition page.
QString group;
bool isGroupPage = false;
if (fakeNode->doc().metaCommandsUsed().contains("group")) {
group = fakeNode->doc().metaCommandArgs("group")[0];
isGroupPage = true;
}
// there are too many examples; they would clutter the list
if (fakeNode->subType() == FakeNode::Example)
continue;
// not interested either in individual (Qt Designer etc.) manual chapters
if (fakeNode->links().contains(Node::ContentsLink))
continue;
// Discard external nodes.
if (fakeNode->subType() == FakeNode::ExternalPage)
continue;
QString sortKey = fakeNode->fullTitle().toLower();
if (sortKey.startsWith("the "))
sortKey.remove(0, 4);
sortKey.replace(singleDigit, "0\\1");
if (!group.isEmpty()) {
if (isGroupPage) {
// If we encounter a group definition page, we add all
// the pages in that group to the list for that group.
foreach (Node *member, fakeNode->groupMembers()) {
if (member->type() != Node::Fake)
continue;
FakeNode *page = static_cast(member);
if (page) {
QString sortKey = page->fullTitle().toLower();
if (sortKey.startsWith("the "))
sortKey.remove(0, 4);
sortKey.replace(singleDigit, "0\\1");
fakeNodeMap[const_cast(fakeNode)].insert(sortKey, page);
groupTitlesMap[fakeNode->fullTitle()] = const_cast(fakeNode);
}
}
} else if (!isGroupPage) {
// If we encounter a page that belongs to a group then
// we add that page to the list for that group.
const FakeNode *groupNode = static_cast(tre->root()->findNode(group, Node::Fake));
if (groupNode)
fakeNodeMap[groupNode].insert(sortKey, fakeNode);
//else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}
}
// We now list all the pages found that belong to groups.
// If only certain pages were found for a group, but the definition page
// for that group wasn't listed, the list of pages will be intentionally
// incomplete. However, if the group definition page was listed, all the
// pages in that group are listed for completeness.
if (!fakeNodeMap.isEmpty()) {
foreach (const QString &groupTitle, groupTitlesMap.keys()) {
const FakeNode *groupNode = groupTitlesMap[groupTitle];
out() << QString("\n").arg(
linkForNode(groupNode, relative)).arg(
protect(groupNode->fullTitle()));
if (fakeNodeMap[groupNode].count() == 0)
continue;
out() << "\n";
foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) {
QString title = fakeNode->fullTitle();
if (title.startsWith("The "))
title.remove(0, 4);
out() << "- "
<< protect(title) << "
\n";
}
out() << " \n";
}
}
if (!uncategorizedNodeMap.isEmpty()) {
out() << QString("Miscellaneous\n");
out() << "\n";
foreach (const FakeNode *fakeNode, uncategorizedNodeMap) {
QString title = fakeNode->fullTitle();
if (title.startsWith("The "))
title.remove(0, 4);
out() << "- "
<< protect(title) << "
\n";
}
out() << " \n";
}
}
void HtmlGenerator::generateSectionList(const Section& section, const Node *relative,
CodeMarker *marker, CodeMarker::SynopsisStyle style)
{
if (!section.members.isEmpty()) {
bool twoColumn = false;
if (style == CodeMarker::SeparateList) {
twoColumn = (section.members.count() >= 16);
} else if (section.members.first()->type() == Node::Property) {
twoColumn = (section.members.count() >= 5);
}
if (twoColumn)
out() << "\n"
<< "";
out() << "\n";
int i = 0;
NodeList::ConstIterator m = section.members.begin();
while (m != section.members.end()) {
if ((*m)->access() == Node::Private) {
++m;
continue;
}
if (twoColumn && i == (int) (section.members.count() + 1) / 2)
out() << " | \n";
out() << "- ";
if (style == CodeMarker::Accessors)
out() << "";
generateSynopsis(*m, relative, marker, style);
if (style == CodeMarker::Accessors)
out() << "";
out() << "
\n";
i++;
++m;
}
out() << " \n";
if (twoColumn)
out() << " | \n \n";
}
if (style == CodeMarker::Summary && !section.inherited.isEmpty()) {
out() << "\n";
generateSectionInheritedList(section, relative, marker);
out() << " \n";
}
}
void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative,
CodeMarker *marker)
{
QList >::ConstIterator p = section.inherited.begin();
while (p != section.inherited.end()) {
out() << "- ";
out() << (*p).second << " ";
if ((*p).second == 1) {
out() << section.singularMember;
} else {
out() << section.pluralMember;
}
out() << " inherited from "
<< protect(marker->plainFullName((*p).first, relative))
<< "
\n";
++p;
}
}
void HtmlGenerator::generateLink(const Atom *atom, const Node * /* relative */, CodeMarker *marker)
{
static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_");
if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {
// hack for C++: move () outside of link
int k = funcLeftParen.pos(1);
out() << protect(atom->string().left(k));
if (link.isEmpty()) {
if (showBrokenLinks)
out() << "";
} else {
out() << "";
}
inLink = false;
out() << protect(atom->string().mid(k));
} else if (marker->recognizeLanguage("Java")) {
// hack for Java: remove () and use when appropriate
bool func = atom->string().endsWith("()");
bool tt = (func || atom->string().contains(camelCase));
if (tt)
out() << "";
if (func) {
out() << protect(atom->string().left(atom->string().length() - 2));
} else {
out() << protect(atom->string());
}
out() << "";
} else {
out() << protect(atom->string());
}
}
QString HtmlGenerator::cleanRef(const QString& ref)
{
QString clean;
if (ref.isEmpty())
return clean;
clean.reserve(ref.size() + 20);
const QChar c = ref[0];
const uint u = c.unicode();
if ((u >= 'a' && u <= 'z') ||
(u >= 'A' && u <= 'Z') ||
(u >= '0' && u <= '9')) {
clean += c;
} else if (u == '~') {
clean += "dtor.";
} else if (u == '_') {
clean += "underscore.";
} else {
clean += "A";
}
for (int i = 1; i < (int) ref.length(); i++) {
const QChar c = ref[i];
const uint u = c.unicode();
if ((u >= 'a' && u <= 'z') ||
(u >= 'A' && u <= 'Z') ||
(u >= '0' && u <= '9') || u == '-' ||
u == '_' || u == ':' || u == '.') {
clean += c;
} else if (c.isSpace()) {
clean += "-";
} else if (u == '!') {
clean += "-not";
} else if (u == '&') {
clean += "-and";
} else if (u == '<') {
clean += "-lt";
} else if (u == '=') {
clean += "-eq";
} else if (u == '>') {
clean += "-gt";
} else if (u == '#') {
clean += "#";
} else {
clean += "-";
clean += QString::number((int)u, 16);
}
}
return clean;
}
QString HtmlGenerator::registerRef(const QString& ref)
{
QString clean = HtmlGenerator::cleanRef(ref);
for (;;) {
QString& prevRef = refMap[clean.toLower()];
if (prevRef.isEmpty()) {
prevRef = ref;
break;
} else if (prevRef == ref) {
break;
}
clean += "x";
}
return clean;
}
QString HtmlGenerator::protect(const QString& string)
{
#define APPEND(x) \
if (html.isEmpty()) { \
html = string; \
html.truncate(i); \
} \
html += (x);
QString html;
int n = string.length();
for (int i = 0; i < n; ++i) {
QChar ch = string.at(i);
if (ch == QLatin1Char('&')) {
APPEND("&");
} else if (ch == QLatin1Char('<')) {
APPEND("<");
} else if (ch == QLatin1Char('>')) {
APPEND(">");
} else if (ch == QLatin1Char('"')) {
APPEND(""");
} else if (ch.unicode() > 0x007F
|| (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))
|| (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
// we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
APPEND("");
html += QString::number(ch.unicode(), 16);
html += QLatin1Char(';');
} else {
if (!html.isEmpty())
html += ch;
}
}
if (!html.isEmpty())
return html;
return string;
#undef APPEND
}
static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(@link>)");
static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(@func>)");
static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(@\\2>)");
static QRegExp spanTag("@(?:comment|preprocessor|string|char)>");
static QRegExp unknownTag("?@[^>]*>");
bool parseArg(const QString &src,
const QString &tag,
int *pos,
int n,
QStringRef *contents,
QStringRef *par1 = 0,
bool debug = false)
{
#define SKIP_CHAR(c) \
if (debug) \
qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \
if (i >= n || src[i] != c) { \
if (debug) \
qDebug() << " char '" << c << "' not found"; \
return false; \
} \
++i;
#define SKIP_SPACE \
while (i < n && src[i] == ' ') \
++i;
int i = *pos;
int j = i;
// assume "<@" has been parsed outside
//SKIP_CHAR('<');
//SKIP_CHAR('@');
if (tag != QStringRef(&src, i, tag.length())) {
if (0 && debug)
qDebug() << "tag " << tag << " not found at " << i;
return false;
}
if (debug)
qDebug() << "haystack:" << src << "needle:" << tag << "i:" <).*(@link>)");
if (par1) {
SKIP_SPACE;
// read parameter name
j = i;
while (i < n && src[i].isLetter())
++i;
if (src[i] == '=') {
if (debug)
qDebug() << "read parameter" << QString(src.data() + j, i - j);
SKIP_CHAR('=');
SKIP_CHAR('"');
// skip parameter name
j = i;
while (i < n && src[i] != '"')
++i;
*par1 = QStringRef(&src, j, i - j);
SKIP_CHAR('"');
SKIP_SPACE;
} else {
if (debug)
qDebug() << "no optional parameter found";
}
}
SKIP_SPACE;
SKIP_CHAR('>');
// find contents up to closing "@tag>
j = i;
for (; true; ++i) {
if (i + 4 + tag.length() > n)
return false;
if (src[i] != '<')
continue;
if (src[i + 1] != '/')
continue;
if (src[i + 2] != '@')
continue;
if (tag != QStringRef(&src, i + 3, tag.length()))
continue;
if (src[i + 3 + tag.length()] != '>')
continue;
break;
}
*contents = QStringRef(&src, j, i - j);
i += tag.length() + 4;
*pos = i;
if (debug)
qDebug() << " tag " << tag << " found: pos now: " << i;
return true;
#undef SKIP_CHAR
}
static void addLink(const QString &linkTarget,
const QStringRef &nestedStuff,
QString *res)
{
if (!linkTarget.isEmpty()) {
*res += "";
*res += nestedStuff;
*res += "";
}
else {
*res += nestedStuff;
}
}
QString HtmlGenerator::highlightedCode(const QString& markedCode,
CodeMarker *marker,
const Node *relative)
{
QString src = markedCode;
QString html;
QStringRef arg;
QStringRef par1;
const QChar charLangle = '<';
const QChar charAt = '@';
// replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(@link>)"
static const QString linkTag("link");
for (int i = 0, n = src.size(); i < n;) {
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, linkTag, &i, n, &arg, &par1)) {
QString link = linkForNode(
CodeMarker::nodeForString(par1.toString()), relative);
addLink(link, arg, &html);
}
else {
html += charLangle;
html += charAt;
}
}
else {
html += src.at(i++);
}
}
if (slow) {
// is this block ever used at all?
// replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(@func>)"
src = html;
html = QString();
static const QString funcTag("func");
for (int i = 0, n = src.size(); i < n;) {
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, n, &arg, &par1)) {
QString link = linkForNode(
marker->resolveTarget(par1.toString(),
tre,
relative),
relative);
addLink(link, arg, &html);
par1 = QStringRef();
}
else {
html += charLangle;
html += charAt;
}
}
else {
html += src.at(i++);
}
}
}
// replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(@\\2>)" tags
src = html;
html = QString();
static const QString typeTags[] = { "type", "headerfile", "func" };
for (int i = 0, n = src.size(); i < n;) {
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
bool handled = false;
for (int k = 0; k != 3; ++k) {
if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) {
par1 = QStringRef();
QString link = linkForNode(
marker->resolveTarget(arg.toString(), tre, relative),
relative);
addLink(link, arg, &html);
handled = true;
break;
}
}
if (!handled) {
html += charLangle;
html += charAt;
}
}
else {
html += src.at(i++);
}
}
// replace all
// "<@comment>" -> " |