view dmd/ddoc/Util.d @ 153:560eaedcb7a2

added lots of ddoc code, still needs much care added helpers functions in ddoc.Util
author trass3r
date Wed, 15 Sep 2010 04:18:46 +0200
parents
children
line wrap: on
line source

module dmd.ddoc.Util;

public import std.string : cmp, icmp;

/*****************************************
 * Return !=0 if comment consists entirely of "ditto".
 */
bool isDitto(string comment)
{
	if (comment)
	{
		string p = skipwhitespace(comment);

		if (icmp(p, "ditto") == 0 && skipwhitespace(p[5..$])[0] == 0)
			return true;
	}
	return false;
}

/**********************************************
 * Skip white space.
 */
string skipwhitespace(string p)
{
	size_t i = 0;
	
	for (; true; i++)
	{   switch (p[i])
		{
			case ' ':
			case '\t':
			case '\n':
				continue;
			default:
		}
		break;
	}
	return p[i .. $];
}

/+
/************************************************
 * Scan forward to one of:
 *	  start of identifier
 *	  beginning of next line
 *	  end of buf
 */
unsigned skiptoident(OutBuffer buf, size_t i)
{
	while (i < buf.offset)
	{   dchar_t c;

		size_t oi = i;
		if (utf_decodeChar((unsigned char *)buf.data, buf.offset, &i, &c))
			/* Ignore UTF errors, but still consume input
			 */
			break;
		if (c >= 0x80)
		{
			if (!isUniAlpha(c))
				continue;
		}
		else if (!(isalpha(c) || c == '_' || c == '\n'))
			continue;
		i = oi;
		break;
	}
	return i;
}

/************************************************
 * Scan forward past end of identifier.
 */

unsigned skippastident(OutBuffer buf, size_t i)
{
	while (i < buf.offset)
	{   dchar_t c;

		size_t oi = i;
		if (utf_decodeChar((unsigned char *)buf.data, buf.offset, &i, &c))
			/* Ignore UTF errors, but still consume input
			 */
			break;
		if (c >= 0x80)
		{
			if (isUniAlpha(c))
				continue;
		}
		else if (isalnum(c) || c == '_')
			continue;
		i = oi;
		break;
	}
	return i;
}


/************************************************
 * Scan forward past URL starting at i.
 * We don't want to highlight parts of a URL.
 * Returns:
 *	  i if not a URL
 *	  index just past it if it is a URL
 */

unsigned skippastURL(OutBuffer buf, size_t i)
{   unsigned length = buf.offset - i;
	unsigned char *p = &buf.data[i];
	unsigned j;
	unsigned sawdot = 0;

	if (length > 7 && memicmp((char *)p, "http://", 7) == 0)
	{
		j = 7;
	}
	else if (length > 8 && memicmp((char *)p, "https://", 8) == 0)
	{
		j = 8;
	}
	else
		goto Lno;

	for (; j < length; j++)
	{   unsigned char c = p[j];
		if (isalnum(c))
			continue;
		if (c == '-' || c == '_' || c == '?' ||
			c == '=' || c == '%' || c == '&' ||
			c == '/' || c == '+' || c == '#' ||
			c == '~')
			continue;
		if (c == '.')
		{
			sawdot = 1;
			continue;
		}
		break;
	}
	if (sawdot)
		return i + j;

Lno:
	return i;
}


/****************************************************
 */
bool isKeyword(string p)
{
	static string[] table = [ "true", "false", "null" ];

	for (int i = 0; i < table.length; i++)
	{
		if (table[i][0 .. p.length] == p)
			return true;
	}
	return false;
}

/****************************************************
 */
Parameter isFunctionParameter(Dsymbol s, string p)
{
	FuncDeclaration f = s.isFuncDeclaration();

	/* f.type may be NULL for template members.
	 */
	if (f && f.type)
	{
		TypeFunction *tf;
		if (f.originalType)
		{
			tf = (TypeFunction *)f.originalType;
		}
		else
			tf = (TypeFunction *)f.type;

		if (tf.parameters)
		{
			for (size_t k = 0; k < tf.parameters.dim; k++)
			{   Parameter *arg = (Parameter *)tf.parameters.data[k];

				if (arg.ident && cmp(arg.ident.toChars(), p, len) == 0)
				{
					return arg;
				}
			}
		}
	}
	return NULL;
}
+/
/+
/**************************************************
 * Highlight text section.
 */
void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset)
{
	//printf("highlightText()\n");
	const char *sid = s.ident.toChars();
	FuncDeclaration *f = s.isFuncDeclaration();
	unsigned char *p;
	const char *se;

	int leadingBlank = 1;
	int inCode = 0;
	int inComment = 0;				  // in <!-- ... -. comment
	unsigned iCodeStart;				// start of code section

	unsigned iLineStart = offset;

	for (unsigned i = offset; i < buf.offset; i++)
	{   unsigned char c = buf.data[i];

	 Lcont:
		switch (c)
		{
			case ' ':
			case '\t':
				break;

			case '\n':
				if (sc && !inCode && i == iLineStart && i + 1 < buf.offset)	// if "\n\n"
				{
					static char blankline[] = "$(DDOC_BLANKLINE)\n";

					i = buf.insert(i, blankline, sizeof(blankline) - 1);
				}
				leadingBlank = 1;
				iLineStart = i + 1;
				break;

			case '<':
				leadingBlank = 0;
				if (inCode)
					break;
				p = &buf.data[i];

				// Skip over comments
				if (p[1] == '!' && p[2] == '-' && p[3] == '-')
				{   unsigned j = i + 4;
					p += 4;
					while (1)
					{
						if (j == buf.offset)
							goto L1;
						if (p[0] == '-' && p[1] == '-' && p[2] == '>')
						{
							i = j + 2;  // place on closing '>'
							break;
						}
						j++;
						p++;
					}
					break;
				}

				// Skip over HTML tag
				if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
				{   unsigned j = i + 2;
					p += 2;
					while (1)
					{
						if (j == buf.offset)
							goto L1;
						if (p[0] == '>')
						{
							i = j;	  // place on closing '>'
							break;
						}
						j++;
						p++;
					}
					break;
				}

			L1:
				// Replace '<' with '&lt;' character entity
				se = Escape::escapeChar('<');
				if (se)
				{   size_t len = strlen(se);
					buf.remove(i, 1);
					i = buf.insert(i, se, len);
					i--;		// point to ';'
				}
				break;

			case '>':
				leadingBlank = 0;
				if (inCode)
					break;
				// Replace '>' with '&gt;' character entity
				se = Escape::escapeChar('>');
				if (se)
				{   size_t len = strlen(se);
					buf.remove(i, 1);
					i = buf.insert(i, se, len);
					i--;		// point to ';'
				}
				break;

			case '&':
				leadingBlank = 0;
				if (inCode)
					break;
				p = &buf.data[i];
				if (p[1] == '#' || isalpha(p[1]))
					break;					  // already a character entity
				// Replace '&' with '&amp;' character entity
				se = Escape::escapeChar('&');
				if (se)
				{   size_t len = strlen(se);
					buf.remove(i, 1);
					i = buf.insert(i, se, len);
					i--;		// point to ';'
				}
				break;

			case '-':
				/* A line beginning with --- delimits a code section.
				 * inCode tells us if it is start or end of a code section.
				 */
				if (leadingBlank)
				{   int istart = i;
					int eollen = 0;

					leadingBlank = 0;
					while (1)
					{
						++i;
						if (i >= buf.offset)
							break;
						c = buf.data[i];
						if (c == '\n')
						{   eollen = 1;
							break;
						}
						if (c == '\r')
						{
							eollen = 1;
							if (i + 1 >= buf.offset)
								break;
							if (buf.data[i + 1] == '\n')
							{   eollen = 2;
								break;
							}
						}
						// BUG: handle UTF PS and LS too
						if (c != '-')
							goto Lcont;
					}
					if (i - istart < 3)
						goto Lcont;

					// We have the start/end of a code section

					// Remove the entire --- line, including blanks and \n
					buf.remove(iLineStart, i - iLineStart + eollen);
					i = iLineStart;

					if (inCode && (i <= iCodeStart))
					{   // Empty code section, just remove it completely.
						inCode = 0;
						break;
					}

					if (inCode)
					{
						inCode = 0;
						// The code section is from iCodeStart to i
						OutBuffer codebuf;

						codebuf.write(buf.data + iCodeStart, i - iCodeStart);
						codebuf.writeByte(0);
						highlightCode2(sc, s, &codebuf, 0);
						buf.remove(iCodeStart, i - iCodeStart);
						i = buf.insert(iCodeStart, codebuf.data, codebuf.offset);
						i = buf.insert(i, ")\n", 2);
						i--;
					}
					else
					{   static char pre[] = "$(D_CODE \n";

						inCode = 1;
						i = buf.insert(i, pre, sizeof(pre) - 1);
						iCodeStart = i;
						i--;			// place i on >
						leadingBlank = true;
					}
				}
				break;

			default:
				leadingBlank = 0;
				if (sc && !inCode && isIdStart(&buf.data[i]))
				{   unsigned j;

					j = skippastident(buf, i);
					if (j > i)
					{
						unsigned k = skippastURL(buf, i);
						if (k > i)
						{   i = k - 1;
							break;
						}

						if (buf.data[i] == '_')		// leading '_' means no highlight
						{
							buf.remove(i, 1);
							i = j - 1;
						}
						else
						{
							if (cmp(sid, buf.data + i, j - i) == 0)
							{
								i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
								break;
							}
							else if (isKeyword(buf.data + i, j - i))
							{
								i = buf.bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1;
								break;
							}
							else
							{
								if (f && isFunctionParameter(f, buf.data + i, j - i))
								{
									//printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j);
									i = buf.bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
									break;
								}
							}
							i = j - 1;
						}
					}
				}
				break;
		}
	}
  Ldone:
	if (inCode)
		s.error("unmatched --- in DDoc comment");
	;
}+/