acme: angle bracket tag matching, for XML, HTML etc

http://codereview.appspot.com/98042
This commit is contained in:
Russ Cox 2009-07-26 15:05:07 -04:00
parent 6f4a41c68c
commit e47d0a1e98
2 changed files with 111 additions and 0 deletions

View file

@ -198,6 +198,7 @@ struct Text
uint textbacknl(Text*, uint, uint);
uint textbsinsert(Text*, uint, Rune*, uint, int, int*);
int textbswidth(Text*, Rune);
int textclickhtmlmatch(Text*, uint*, uint*);
int textclickmatch(Text*, int, int, int, uint*);
void textclose(Text*);
void textcolumnate(Text*, Dirlist**, int);

View file

@ -1381,6 +1381,10 @@ textdoubleclick(Text *t, uint *q0, uint *q1)
return;
}
}
if(textclickhtmlmatch(t, q0, q1))
return;
/* try filling out word to right */
while(*q1<t->file->b.nc && isalnum(textreadc(t, *q1)))
(*q1)++;
@ -1417,6 +1421,112 @@ textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
return cl=='\n' && nest==1;
}
// Is the text starting at location q an html tag?
// Return 1 for <a>, -1 for </a>, 0 for no tag or <a />.
// Set *q1, if non-nil, to the location after the tag.
static int
ishtmlstart(Text *t, uint q, uint *q1)
{
int c, c1, c2;
if(q+2 > t->file->b.nc)
return 0;
if(textreadc(t, q++) != '<')
return 0;
c = textreadc(t, q++);
c1 = c;
c2 = c;
while(c != '>') {
if(q >= t->file->b.nc)
return 0;
c2 = c;
c = textreadc(t, q++);
}
if(q1)
*q1 = q;
if(c1 == '/') // closing tag
return -1;
if(c2 == '/' || c2 == '!') // open + close tag or comment
return 0;
return 1;
}
// Is the text ending at location q an html tag?
// Return 1 for <a>, -1 for </a>, 0 for no tag or <a />.
// Set *q0, if non-nil, to the start of the tag.
static int
ishtmlend(Text *t, uint q, uint *q0)
{
int c, c1, c2;
if(q < 2)
return 0;
if(textreadc(t, --q) != '>')
return 0;
c = textreadc(t, --q);
c1 = c;
c2 = c;
while(c != '<') {
if(q == 0)
return 0;
c1 = c;
c = textreadc(t, --q);
}
if(q0)
*q0 = q;
if(c1 == '/') // closing tag
return -1;
if(c2 == '/' || c2 == '!') // open + close tag or comment
return 0;
return 1;
}
int
textclickhtmlmatch(Text *t, uint *q0, uint *q1)
{
int depth, n;
uint q, nq;
q = *q0;
// after opening tag? scan forward for closing tag
if(ishtmlend(t, q, nil) == 1) {
depth = 1;
while(q < t->file->b.nc) {
n = ishtmlstart(t, q, &nq);
if(n != 0) {
depth += n;
if(depth == 0) {
*q1 = q;
return 1;
}
q = nq;
continue;
}
q++;
}
}
// before closing tag? scan backward for opening tag
if(ishtmlstart(t, q, nil) == -1) {
depth = -1;
while(q > 0) {
n = ishtmlend(t, q, &nq);
if(n != 0) {
depth += n;
if(depth == 0) {
*q0 = q;
return 1;
}
q = nq;
continue;
}
q--;
}
}
return 0;
}
uint
textbacknl(Text *t, uint p, uint n)
{