diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libtk/tmark.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libtk/tmark.c')
| -rw-r--r-- | libtk/tmark.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/libtk/tmark.c b/libtk/tmark.c new file mode 100644 index 00000000..37f5deef --- /dev/null +++ b/libtk/tmark.c @@ -0,0 +1,392 @@ +#include "lib9.h" +#include "draw.h" +#include "tk.h" +#include "textw.h" + +#define istring u.string +#define iwin u.win +#define imark u.mark +#define iline u.line + +static char* tktmarkgravity(Tk*, char*, char**); +static char* tktmarknames(Tk*, char*, char**); +static char* tktmarknext(Tk*, char*, char**); +static char* tktmarkprevious(Tk*, char*, char**); +static char* tktmarkset(Tk*, char*, char**); +static char* tktmarkunset(Tk*, char*, char**); + +TkCmdtab +tktmarkcmd[] = +{ + "gravity", tktmarkgravity, + "names", tktmarknames, + "next", tktmarknext, + "previous", tktmarkprevious, + "set", tktmarkset, + "unset", tktmarkunset, + nil +}; + +char* +tktaddmarkinfo(TkText *tkt, char *name, TkTmarkinfo **ret) +{ + TkTmarkinfo *mi; + + mi = malloc(sizeof(TkTmarkinfo)); + if(mi == nil) + return TkNomem; + + mi->name = strdup(name); + if(mi->name == nil) { + free(mi); + return TkNomem; + } + mi->gravity = Tkright; + mi->cur = nil; + mi->next = tkt->marks; + tkt->marks = mi; + *ret = mi; + return nil; +} + +void +tktfreemarks(TkTmarkinfo *m) +{ + TkTmarkinfo *n; + + while(m != nil) { + n = m->next; + free(m->name); + free(m); + m = n; + } +} + +TkTmarkinfo * +tktfindmark(TkTmarkinfo *m, char *name) +{ + while(m != nil) { + if(strcmp(m->name, name) == 0) + return m; + m = m->next; + } + return nil; +} + +int +tktmarkind(Tk *tk, char *name, TkTindex *ans) +{ + TkTmarkinfo *mk; + TkText *tkt = TKobj(TkText, tk); + + if(strcmp(name, "current") == 0) { + tktxyind(tk, tkt->current.x, tkt->current.y, ans); + return 1; + } + + mk = tktfindmark(tkt->marks, name); + if(mk == nil || mk->cur == nil) + return 0; + + ans->item = mk->cur; + ans->line = tktitemline(ans->item); + ans->pos = 0; + return 1; +} + +char* +tktmarkparse(Tk *tk, char **parg, TkTmarkinfo **ret) +{ + char *e, *buf; + TkText *tkt = TKobj(TkText, tk); + + buf = mallocz(Tkmaxitem, 0); + if(buf == nil) + return TkNomem; + + *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil); + if(*buf == '\0') { + free(buf); + return TkOparg; + } + + *ret = tktfindmark(tkt->marks, buf); + if(*ret == nil) { + e = tktaddmarkinfo(tkt, buf, ret); + if(e != nil) { + free(buf); + return e; + } + } + free(buf); + + return nil; +} + +/* + * Insert mark before ixnew, first removing it from old place, if any. + * Make sure ixnew continues to point after mark. + */ +char* +tktmarkmove(Tk *tk, TkTmarkinfo *m, TkTindex *ixnew) +{ + char *e; + int deleted, split; + TkTitem *i; + TkTindex ix, pix; + TkText *tkt = TKobj(TkText, tk); + + deleted = 0; + if(m->cur != nil) { + if(m->cur == ixnew->item) + return nil; + ix.item = m->cur; + ix.line = tktitemline(m->cur); + ix.pos = 0; + tktremitem(tkt, &ix); + deleted = 1; + } + + /* XXX - Tad: memory leak on 'i' if something fails later? */ + e = tktnewitem(TkTmark, 0, &i); + if(e != nil) + return e; + + i->imark = m; + m->cur = i; + + /* keep adjacent marks sorted: all rights, then all lefts */ + if(m->gravity == Tkright) { + while(ixnew->item->kind == TkTmark && ixnew->item->imark->gravity == Tkleft) + if(!tktadjustind(tkt, TkTbyitem, ixnew)) + break; + } + else { + for(;;) { + pix = *ixnew; + if(!tktadjustind(tkt, TkTbyitemback, &pix)) + break; + if(pix.item->kind == TkTmark && pix.item->imark->gravity == Tkright) + *ixnew = pix; + else + break; + } + } + + split = (ixnew->pos > 0); + e = tktsplititem(ixnew); + if(e != nil) + return e; + + e = tktiteminsert(tkt, ixnew, i); + if(e != nil) + return nil; + + if(strcmp(m->name, "insert") == 0 || split) { + if(deleted && ix.line != ixnew->line) { + tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0); + /* + * this is ok only because tktfixgeom cannot + * free mark items, and we know that i is a mark item. + */ + ixnew->item = i; + ixnew->line = tktitemline(i); + ixnew->pos = 0; + } + tktfixgeom(tk, tktprevwrapline(tk, ixnew->line), ixnew->line, 0); + tktextsize(tk, 1); + } + + ixnew->item = i; + ixnew->line = tktitemline(i); + ixnew->pos = 0; + return nil; +} + +/* Text Mark Commands (+ means implemented) + +gravity + +names + +next + +previous + +set + +unset +*/ + +static char* +tktmarkgravity(Tk *tk, char *arg, char **val) +{ + char *e; + TkTmarkinfo *m; + char *buf; + + e = tktmarkparse(tk, &arg, &m); + if(e != nil) + return e; + + if(*arg == '\0') + return tkvalue(val, (m->gravity & Tkleft)? "left" : "right"); + else { + buf = mallocz(Tkmaxitem, 0); + if(buf == nil) + return TkNomem; + tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil); + if(strcmp(buf, "left") == 0) + m->gravity = Tkleft; + else + if(strcmp(buf, "right") == 0) + m->gravity = Tkright; + else { + free(buf); + return TkBadcm; + } + free(buf); + } + return nil; +} + +static char* +tktmarknames(Tk *tk, char *arg, char **val) +{ + char *r, *fmt; + TkTmarkinfo *m; + TkText *tkt = TKobj(TkText, tk); + + USED(arg); + + fmt = "%s"; + for(m = tkt->marks; m != nil; m = m->next) { + r = tkvalue(val, fmt, m->name); + if(r != nil) + return r; + fmt = " %s"; + } + return nil; +} + +static char* +tktmarknext(Tk *tk, char *arg, char **val) +{ + char *e; + TkTmarkinfo *mix; + TkTindex ix, ixend; + TkText *tkt = TKobj(TkText, tk); + + /* special behavior if specified index is a mark name */ + mix = tktfindmark(tkt->marks, arg); + + e = tktindparse(tk, &arg, &ix); + if(e != nil) + return e; + + if(mix != nil) + tktadjustind(tkt, TkTbyitem, &ix); + + /* special behavior if index is 'end' */ + tktendind(tkt, &ixend); + if(tktindcompare(tkt, &ix, TkEq, &ixend)) { + do { + tktadjustind(tkt, TkTbyitemback, &ix); + } while(ix.item->kind == TkTmark); + } + + do { + if(ix.item->kind == TkTmark) + return tkvalue(val, "%s", ix.item->imark->name); + + } while(tktadjustind(tkt, TkTbyitem, &ix)); + + return nil; +} + +static char* +tktmarkprevious(Tk *tk, char *arg, char **val) +{ + char *e; + TkTindex ix; + TkText *tkt = TKobj(TkText, tk); + + e = tktindparse(tk, &arg, &ix); + if(e != nil) + return e; + + while(tktadjustind(tkt, TkTbyitemback, &ix)) { + if(ix.item->kind == TkTmark) + return tkvalue(val, "%s", ix.item->imark->name); + } + + return nil; +} + +/* XXX - Tad: possible memory leak here */ +static char* +tktmarkset(Tk *tk, char *arg, char **val) +{ + char *e; + TkTmarkinfo *m; + TkTindex ixnew; + + USED(val); + + e = tktmarkparse(tk, &arg, &m); + if(e != nil) + return e; + e = tktindparse(tk, &arg, &ixnew); + if(e != nil) + return e; + + return tktmarkmove(tk, m, &ixnew); +} + +static char* +tktmarkunset(Tk *tk, char *arg, char **val) +{ + TkText *tkt; + TkTmarkinfo *m, **p; + TkTindex ix; + char *e; + int resize; + + USED(val); + + tkt = TKobj(TkText, tk); + + e = tktmarkparse(tk, &arg, &m); + if(e != nil) + return e; + + resize = 0; + while(m != nil) { + if(strcmp(m->name, "insert") == 0 || strcmp(m->name, "current") == 0) + return TkBadvl; + + if(m->cur != nil) { + ix.item = m->cur; + ix.line = tktitemline(m->cur); + ix.pos = 0; + tktremitem(tkt, &ix); + tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0); + resize = 1; + } + + for(p = &tkt->marks; *p != nil; p = &(*p)->next) { + if(*p == m) { + *p = m->next; + break; + } + } + m->next = nil; + tktfreemarks(m); + + if(*arg != '\0') { + e = tktmarkparse(tk, &arg, &m); + if(e != nil) + return e; + } + else + m = nil; + } + if (resize) + tktextsize(tk, 1); + return nil; +} + |
