// Look for string s in token source. // If found, return 1, with buffer at next char after s, // else return 0 (caller should back up). static int findstr(TokenSource* ts, Rune* s) { int c0; int n; int nexti; int i; int c; c0 = s[0]; n = runestrlen(s); while(1) { c = getchar(ts); if(c < 0) break; if(c == c0) { if(n == 1) return 1; nexti = ts->i; for(i = 1; i < n; i++) { c = getchar(ts); if(c < 0) goto mainloop_done; if(c != s[i]) break; } if(i == n) return 1; backup(ts, nexti); } } mainloop_done: return 0; }
void renderrunes(Bytes *b, Rune *r) { int i, n; n = runestrlen(r); for(i=0; i<n; i++){ switch(r[i]){ case '\n': if(inword) emitword(b, r+wordi, i-wordi); col = 0; if(b->n == 0) break; /* don't start with blank lines */ if(b->n<2 || b->b[b->n-1]!='\n' || b->b[b->n-2]!='\n') growbytes(b, "\n", 1); break; case ' ': if(inword) emitword(b, r+wordi, i-wordi); break; default: if(!inword) wordi = i; inword = 1; break; } } if(inword) emitword(b, r+wordi, i-wordi); }
static void loadchilds(Page *p, Kidinfo *k) { Runestr rs; Kidinfo *t; Page *c; addrefresh(p, "loading frames..."); p->kidinfo = k; for(t=k->kidinfos; t!=nil; t=t->next){ c = emalloc(sizeof(Page)); addchild(p, c); if(t->isframeset){ c->url = urldup(p->url); loadchilds(c, t); }else{ c->kidinfo = t; /* this check shouldn't be necessary, but... */ if(t->src){ rs.r = urlcombine(p->url->act.r, t->src); rs.nr = runestrlen(rs.r); pageload1(c, urlalloc(&rs, nil, HGet), FALSE); closerunestr(&rs); } } } }
Window* errorwin1(Rune *dir, int ndir, Rune **incl, int nincl) { Window *w; Rune *r; int i, n; r = runemalloc(ndir+8); if(n = ndir){ /* assign = */ runemove(r, dir, ndir); r[n++] = L'/'; } runemove(r+n, L"+Errors", 7); n += 7; w = lookfile(r, n); if(w == nil){ if(row.ncol == 0) if(rowadd(&row, nil, -1) == nil) error("can't create column to make error window"); w = coladd(row.col[row.ncol-1], nil, nil, -1); w->filemenu = FALSE; winsetname(w, r, n); } free(r); for(i=nincl; --i>=0; ){ n = runestrlen(incl[i]); r = runemalloc(n); runemove(r, incl[i], n); winaddincl(w, r, n); } w->autoindent = globalautoindent; return w; }
char* fullurl(URLwin *u, Rune *rhref) { char *base, *href, *hrefbase; char *result; if(rhref == nil) return estrdup("NULL URL"); href = runetobyte(rhref, runestrlen(rhref)); hrefbase = baseurl(href); result = nil; if(hrefbase==nil && (base = baseurl(u->url))!=nil){ result = estrdup(base); if(base[strlen(base)-1]!='/' && (href==nil || href[0]!='/')) result = eappend(result, "/", ""); free(base); } if(href){ if(result) result = eappend(result, "", href); else result = estrdup(href); } free(hrefbase); if(result == nil) return estrdup("***unknown***"); return result; }
void flushdi(void) { int n; Rune *p; if(ndi == 0 || difmtinit == 0) return; fmtrune(&difmt, Uunformatted); p = runefmtstrflush(&difmt); memset(&difmt, 0, sizeof difmt); difmtinit = 0; if(p == nil) warn("out of memory in diversion %C%S", dot, di[ndi-1]); else{ n = runestrlen(p); if(n > 0 && p[n-1] != '\n'){ p = runerealloc(p, n+2); p[n] = '\n'; p[n+1] = 0; } } as(di[ndi-1], p); free(p); }
static int inclass(char c, Rune* cl) { int n, ans, negate, i; n = runestrlen(cl); if(n == 0) return 0; ans = 0; negate = 0; if(cl[0] == '^') { negate = 1; cl++; n--; } for(i=0; i<n; i++) { if(cl[i]=='-' && i>0 && i<n-1) { if(c>=cl[i - 1] && c<=cl[i+1]) { ans = 1; break; } i++; } else if(c == cl[i]) { ans = 1; break; } } if(negate) ans = !ans; return ans; }
static Cimage * loadimg(Rune *src, int x , int y) { Channel *sync; Cimage *ci; Runestr rs; Exec *e; char *filter; int fd, p[2], q[2]; ci = emalloc(sizeof(Cimage)); rs. r = src; rs.nr = runestrlen(rs.r); ci->url = urlalloc(&rs, nil, HGet); fd = urlopen(ci->url); if(fd < 0){ Err1: return ci; } filter = getfilter(ci->url->ctype.r, x, y); if(filter == nil){ werrstr("%S unsupported: %S", ci->url->ctype.r, ci->url->act.r); Err2: close(fd); goto Err1; } if(pipe(p)<0 || pipe(q)<0) error("can't create pipe"); close(p[0]); p[0] = fd; sync = chancreate(sizeof(ulong), 0); if(sync == nil) error("can't create channel"); e = emalloc(sizeof(Exec)); e->p[0] = p[0]; e->p[1] = p[1]; e->q[0] = q[0]; e->q[1] = q[1]; e->cmd = filter; e->sync = sync; proccreate(execproc, e, STACK); recvul(sync); chanfree(sync); close(p[0]); close(p[1]); close(q[1]); ci->mi = readmemimage(q[0]); close(q[0]); if(ci->mi == nil){ werrstr("can't read image"); goto Err2; } free(filter); return ci; }
int plumbgetc(void *a, uint n) { Rune *r; r = a; if(n>runestrlen(r)) return 0; return r[n]; }
Rune* runestrdup(Rune *s) { Rune *ns; ns = malloc(sizeof(Rune)*(runestrlen(s) + 1)); if(ns == 0) return 0; setmalloctag(ns, getcallerpc(&s)); return runestrcpy(ns, s); }
Rune* runestrdup(Rune *s) { Rune *ns; ns = malloc(sizeof(Rune)*(runestrlen(s) + 1)); if(ns == 0) return 0; return runestrcpy(ns, s); }
void _inputstring(Rune *s, void (*push)(Istack*)) { Istack *is; is = emalloc(sizeof *is); is->s = erunestrdup(s); is->p = is->s; is->ep = is->p+runestrlen(is->p); push(is); }
void addhttp(Url *u) { Rune *s; if(validurl(u->src.r)) return; s = u->src.r; u->src.r = runesmprint("http://%S", u->src.r); free(s); u->src.nr = runestrlen(u->src.r); }
// tired of typing http://, tired of going to google first. void justgoogleit(Url *u) { Rune *s; s = ucvt(u->src.r+2); free(u->src.r); u->src.r = runesmprint("http://www.google.com/search?hl=en&ie=UTF-8&q=%S", s); free(s); u->src.nr = runestrlen(u->src.r); }
void urlcanon(Rune *name){ Rune *s, *t; Rune **comp, **p, **q; int rooted; name = runestrchr(name, L'/')+2; rooted=name[0]==L'/'; /* * Break the name into a list of components */ comp=emalloc(runestrlen(name)*sizeof(char *)); p=comp; *p++=name; for(s=name;;s++){ if(*s==L'/'){ *p++=s+1; *s='\0'; } else if(*s=='\0') break; } *p=0; /* * go through the component list, deleting components that are empty (except * the last component) or ., and any .. and its non-.. predecessor. */ p=q=comp; while(*p){ if(runestrcmp(*p, L"")==0 && p[1]!=0 || runestrcmp(*p, L".")==0) p++; else if(runestrcmp(*p, L"..")==0 && q!=comp && runestrcmp(q[-1], L"..")!=0){ --q; p++; } else *q++=*p++; } *q=0; /* * rebuild the path name */ s=name; if(rooted) *s++='/'; for(p=comp;*p;p++){ t=*p; while(*t) *s++=*t++; if(p[1]!=0) *s++='/'; } *s='\0'; free(comp); }
void warning(Mntdir *md, char *s, ...) { Rune *r; va_list arg; va_start(arg, s); r = runevsmprint(s, arg); va_end(arg); if(r == nil) error("runevsmprint failed"); addwarningtext(md, r, runestrlen(r)); free(r); }
int e_w(void) { Rune *a; Rune buf[40]; a = getqarg(); runesnprint(buf, sizeof buf, "%ld", runestrlen(a)); pushinputstring(buf); nr(L("st"), 0); nr(L("sb"), 0); nr(L("ct"), 0); return 0; }
void _appleputsnarf(char *s) { CFDataRef cfdata; PasteboardSyncFlags flags; /* fprint(2, "appleputsnarf\n"); */ if(strlen(s) >= SnarfSize) return; qlock(&clip.lk); strcpy(clip.buf, s); runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s); if(clip.apple == nil){ if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){ fprint(2, "apple pasteboard create failed\n"); qunlock(&clip.lk); return; } } if(PasteboardClear(clip.apple) != noErr){ fprint(2, "apple pasteboard clear failed\n"); qunlock(&clip.lk); return; } flags = PasteboardSynchronize(clip.apple); if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ fprint(2, "apple pasteboard cannot assert ownership\n"); qunlock(&clip.lk); return; } cfdata = CFDataCreate(kCFAllocatorDefault, (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2); if(cfdata == nil){ fprint(2, "apple pasteboard cfdatacreate failed\n"); qunlock(&clip.lk); return; } if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1, CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){ fprint(2, "apple pasteboard putitem failed\n"); CFRelease(cfdata); qunlock(&clip.lk); return; } /* CFRelease(cfdata); ??? */ qunlock(&clip.lk); }
int e_w(void) { Rune *a; Rune buf[40]; static Rune zero; a = getqarg(); if(a == nil){ warn("no arg for \\w"); a = &zero; } runesnprint(buf, sizeof buf, "%ld", runestrlen(a)); pushinputstring(buf); nr(L("st"), 0); nr(L("sb"), 0); nr(L("ct"), 0); return 0; }
void columnate(void) { int i, j; int words_per_line; int nlines; int col; int endcol; scanwords(); if(nwords==0) return; maxwidth = nexttab(maxwidth+mintab-1); words_per_line = linewidth/maxwidth; if(words_per_line <= 0) words_per_line = 1; nlines=(nwords+words_per_line-1)/words_per_line; for(i = 0; i < nlines; i++){ col = endcol = 0; for(j = i; j < nwords; j += nlines){ endcol += maxwidth; Bprint(&bout, "%S", word[j]); col += wordsize(word[j], runestrlen(word[j])); if(j+nlines < nwords){ if(tabflag) { while(col < endcol){ Bputc(&bout, '\t'); col = nexttab(col); } }else{ while(col < endcol){ Bputc(&bout, ' '); col++; } } } } Bputc(&bout, '\n'); } }
Runestr includefile(Rune *dir, Rune *file, int nfile) { int m, n; char *a; Rune *r; static Rune Lslash[] = { '/', 0 }; m = runestrlen(dir); a = emalloc((m+1+nfile)*UTFmax+1); sprint(a, "%S/%.*S", dir, nfile, file); n = access(a, 0); free(a); if(n < 0) return runestr(nil, 0); r = runemalloc(m+1+nfile); runemove(r, dir, m); runemove(r+m, Lslash, 1); runemove(r+m+1, file, nfile); free(file); return cleanrname(runestr(r, m+1+nfile)); }
/* define macro - .de, .am, .ig */ void r_de(int argc, Rune **argv) { Rune *end, *p; Fmt fmt; int ignore, len; delreq(argv[1]); delraw(argv[1]); ignore = runestrcmp(argv[0], L("ig")) == 0; if(!ignore) runefmtstrinit(&fmt); end = L(".."); if(argc >= 3) end = argv[2]; if(runestrcmp(argv[0], L("am")) == 0 && (p=getds(argv[1])) != nil) fmtrunestrcpy(&fmt, p); len = runestrlen(end); while((p = readline(CopyMode)) != nil){ if(runestrncmp(p, end, len) == 0 && (p[len]==' ' || p[len]==0 || p[len]=='\t' || (p[len]=='\\' && p[len+1]=='}'))){ free(p); goto done; } if(!ignore) fmtprint(&fmt, "%S\n", p); free(p); } warn("eof in %C%S %S - looking for %#Q", dot, argv[0], argv[1], end); done: if(ignore) return; p = runefmtstrflush(&fmt); if(p == nil) sysfatal("out of memory"); ds(argv[1], p); free(p); }
void pagesetrefresh(Page *p) { Runestr rs; Rune *s, *q, *t; char *v; int n; if(!p->doc || !p->doc->refresh) return; s = p->doc->refresh; q = runestrchr(s, L'='); if(q == nil) return; q++; if(!q) return; n = runestrlen(q); if(*q == L'''){ q++; n -= 2; }
/* * Incoming window should be locked. * It will be unlocked and returned window * will be locked in its place. */ Window* errorwinforwin(Window *w) { int i, n, nincl, owner; Rune **incl; Runestr dir; Text *t; t = &w->body; dir = dirname(t, nil, 0); if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ free(dir.r); dir.r = nil; dir.nr = 0; } incl = nil; nincl = w->nincl; if(nincl > 0){ incl = emalloc(nincl*sizeof(Rune*)); for(i=0; i<nincl; i++){ n = runestrlen(w->incl[i]); incl[i] = runemalloc(n+1); runemove(incl[i], w->incl[i], n); } } owner = w->owner; winunlock(w); for(;;){ w = errorwin1(dir.r, dir.nr, incl, nincl); winlock(w, owner); if(w->col != nil) break; /* window deleted too fast */ winunlock(w); } return w; }
void readfile(Column *c, char *s) { Window *w; Rune rb[256]; int nr; Runestr rs; w = coladd(c, nil, nil, -1); if(s[0] != '/') runesnprint(rb, sizeof rb, "%s/%s", wdir, s); else runesnprint(rb, sizeof rb, "%s", s); nr = runestrlen(rb); rs = cleanrname(runestr(rb, nr)); winsetname(w, rs.r, rs.nr); textload(&w->body, 0, s, 1); w->body.file->mod = FALSE; w->dirty = FALSE; winsettag(w); winresize(w, w->r, FALSE, TRUE); textscrdraw(&w->body); textsetselect(&w->tag, w->tag.file->b.nc, w->tag.file->b.nc); }
static void pageloadproc(void *v) { Page *p; char buf[BUFSIZE], *s; int32_t n, l; int fd, i, ctype; threadsetname("pageloadproc"); rfork(RFFDG); p = v; addrefresh(p, "opening: %S...", p->url->src.r); fd = urlopen(p->url); if(fd < 0){ addrefresh(p, "%S: %r", p->url->src.r); Err: p->loading = FALSE; return; } if(runestrlen(p->url->ctype.r) == 0) /* assume .html when headers don't say anyting */ goto Html; snprint(buf, sizeof(buf), "%S", p->url->ctype.r); for(i=0; mimetab[i]!=nil; i++) if(cistrncmp(buf, mimetab[i], strlen(mimetab[i])) == 0) break; if(mimetab[i]){ Html: ctype = TextHtml; }else if(cistrncmp(buf, "text/", 5) == 0) ctype = TextPlain; else{ close(fd); addrefresh(p, "%S: unsupported mime type: '%S'", p->url->act.r, p->url->ctype.r); goto Err; } addrefresh(p, "loading: %S...", p->url->src.r); s = nil; l = 0; while((n=read(fd, buf, sizeof(buf))) > 0){ if(p->aborting){ if(s){ free(s); s = nil; } break; } s = erealloc(s, l+n+1); memmove(s+l, buf, n); l += n; s[l] = '\0'; } close(fd); n = l; if(s){ s = convert(p->url->ctype, s, &n); p->items = parsehtml((uint8_t *)s, n, p->url->act.r, ctype, UTF_8, &p->doc); free(s); fixtext(p); if(ctype==TextHtml && p->aborting==FALSE){ p->changed = TRUE; addrefresh(p, ""); if(p->doc->doctitle){ p->title.r = erunestrdup(p->doc->doctitle); p->title.nr = runestrlen(p->title.r); } p->loading = XXX; if(p->doc->kidinfo) loadchilds(p, p->doc->kidinfo); else if(p->doc->images) loadimages(p); } } p->changed = TRUE; p->loading = FALSE; addrefresh(p, ""); }
void waitthread(void *v) { Waitmsg *w; Command *c, *lc; uint pid; int found, ncmd; Rune *cmd; char *err; Text *t; Pid *pids, *p, *lastp; enum { WErr, WKill, WWait, WCmd, NWALT }; Alt alts[NWALT+1]; USED(v); threadsetname("waitthread"); pids = nil; alts[WErr].c = cerr; alts[WErr].v = &err; alts[WErr].op = CHANRCV; alts[WKill].c = ckill; alts[WKill].v = &cmd; alts[WKill].op = CHANRCV; alts[WWait].c = cwait; alts[WWait].v = &w; alts[WWait].op = CHANRCV; alts[WCmd].c = ccommand; alts[WCmd].v = &c; alts[WCmd].op = CHANRCV; alts[NWALT].op = CHANEND; command = nil; for(;;){ switch(alt(alts)){ case WErr: qlock(&row.lk); warning(nil, "%s", err); free(err); flushimage(display, 1); qunlock(&row.lk); break; case WKill: found = FALSE; ncmd = runestrlen(cmd); for(c=command; c; c=c->next){ /* -1 for blank */ if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE){ if(postnote(PNGROUP, c->pid, "kill") < 0) warning(nil, "kill %S: %r\n", cmd); found = TRUE; } } if(!found) warning(nil, "Kill: no process %S\n", cmd); free(cmd); break; case WWait: pid = w->pid; lc = nil; for(c=command; c; c=c->next){ if(c->pid == pid){ if(lc) lc->next = c->next; else command = c->next; break; } lc = c; } qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); if(c == nil){ /* helper processes use this exit status */ if(strncmp(w->msg, "libthread", 9) != 0){ p = emalloc(sizeof(Pid)); p->pid = pid; strncpy(p->msg, w->msg, sizeof(p->msg)); p->next = pids; pids = p; } }else{ if(search(t, c->name, c->nname)){ textdelete(t, t->q0, t->q1, TRUE); textsetselect(t, 0, 0); } if(w->msg[0]) warning(c->md, "%.*S: exit %s\n", c->nname-1, c->name, w->msg); flushimage(display, 1); } qunlock(&row.lk); free(w); Freecmd: if(c){ if(c->iseditcmd) sendul(cedit, 0); free(c->text); free(c->name); fsysdelid(c->md); free(c); } break; case WCmd: /* has this command already exited? */ lastp = nil; for(p=pids; p!=nil; p=p->next){ if(p->pid == c->pid){ if(p->msg[0]) warning(c->md, "%s\n", p->msg); if(lastp == nil) pids = p->next; else lastp->next = p->next; free(p); goto Freecmd; } lastp = p; } c->next = command; command = c; qlock(&row.lk); t = &row.tag; textcommit(t, TRUE); textinsert(t, 0, c->name, c->nname, TRUE); textsetselect(t, 0, 0); flushimage(display, 1); qunlock(&row.lk); break; } } }
void render(URLwin *u, Bytes *t, Item *items, int curanchor) { Item *il; Itext *it; Ifloat *ifl; Ispacer *is; Itable *ita; Iimage *im; Anchor *a; Table *tab; Tablecell *cell; char *href; inword = 0; col = 0; wordi = 0; for(il=items; il!=nil; il=il->next){ if(il->state & IFbrk) renderbytes(t, "\n"); if(il->state & IFbrksp) renderbytes(t, "\n"); switch(il->tag){ case Itexttag: it = (Itext*)il; if(it->state & IFwrap) renderrunes(t, it->s); else emitword(t, it->s, runestrlen(it->s)); break; case Iruletag: if(t->n>0 && t->b[t->n-1]!='\n') renderbytes(t, "\n"); renderbytes(t, "=======\n"); break; case Iimagetag: if(!aflag) break; im = (Iimage*)il; if(im->imsrc){ href = fullurl(u, im->imsrc); renderbytes(t, "[image %s]", href); free(href); } break; case Iformfieldtag: if(aflag) renderbytes(t, "[formfield]"); break; case Itabletag: ita = (Itable*)il; tab = ita->table; for(cell=tab->cells; cell!=nil; cell=cell->next){ render(u, t, cell->content, curanchor); } if(t->n>0 && t->b[t->n-1]!='\n') renderbytes(t, "\n"); break; case Ifloattag: ifl = (Ifloat*)il; render(u, t, ifl->item, curanchor); break; case Ispacertag: is = (Ispacer*)il; if(is->spkind != ISPnull) renderbytes(t, " "); break; default: error("unknown item tag %d\n", il->tag); } if(il->anchorid != 0 && il->anchorid!=curanchor){ for(a=u->docinfo->anchors; a!=nil; a=a->next) if(aflag && a->index == il->anchorid){ href = fullurl(u, a->href); renderbytes(t, "[%s]", href); free(href); break; } curanchor = il->anchorid; } } if(t->n>0 && t->b[t->n-1]!='\n') renderbytes(t, "\n"); }
void wkeyctl(Window *w, Rune r) { uint q0; if(r == 0) return; if(w->deleted) return; fprint(2, "wkyctl: skipping all ctl chars\n"); #if 0 uint q0 ,q1; int n, nb, nr; Rune *rp; int *notefd; /* navigation keys work only when mouse is not open */ if(!w->mouseopen) switch(r){ case Kdown: n = w->maxlines/3; goto case_Down; case Kscrollonedown: n = mousescrollsize(w->maxlines); if(n <= 0) n = 1; goto case_Down; case Kpgdown: n = 2*w->maxlines/3; case_Down: q0 = w->org+frcharofpt(w, Pt(w->Frame.r.min.x, w->Frame.r.min.y+n*w->font->height)); wsetorigin(w, q0, TRUE); return; case Kup: n = w->maxlines/3; goto case_Up; case Kscrolloneup: n = mousescrollsize(w->maxlines); if(n <= 0) n = 1; goto case_Up; case Kpgup: n = 2*w->maxlines/3; case_Up: q0 = wbacknl(w, w->org, n); wsetorigin(w, q0, TRUE); return; case Kleft: if(w->q0 > 0){ q0 = w->q0-1; wsetselect(w, q0, q0); wshow(w, q0); } return; case Kright: if(w->q1 < w->nr){ q1 = w->q1+1; wsetselect(w, q1, q1); wshow(w, q1); } return; case Khome: wshow(w, 0); return; case Kend: wshow(w, w->nr); return; case 0x01: /* ^A: beginning of line */ if(w->q0==0 || w->q0==w->qh || w->run[w->q0-1]=='\n') return; nb = wbswidth(w, 0x15 /* ^U */); wsetselect(w, w->q0-nb, w->q0-nb); wshow(w, w->q0); return; case 0x05: /* ^E: end of line */ q0 = w->q0; while(q0 < w->nr && w->run[q0]!='\n') q0++; wsetselect(w, q0, q0); wshow(w, w->q0); return; } if(w->rawing && (w->q0==w->nr || w->mouseopen)){ waddraw(w, &r, 1); return; } if(r==0x1B || (w->holding && r==0x7F)){ /* toggle hold */ if(w->holding) --w->holding; else w->holding++; wrepaint(w); if(r == 0x1B) return; } if(r != 0x7F){ wsnarf(w); wcut(w); } switch(r){ case 0x7F: /* send interrupt */ w->qh = w->nr; wshow(w, w->qh); notefd = emalloc(sizeof(int)); *notefd = w->notefd; proccreate(interruptproc, notefd, 4096); return; case 0x06: /* ^F: file name completion */ case Kins: /* Insert: file name completion */ rp = namecomplete(w); if(rp == nil) return; nr = runestrlen(rp); q0 = w->q0; q0 = winsert(w, rp, nr, q0); wshow(w, q0+nr); free(rp); return; case 0x08: /* ^H: erase character */ case 0x15: /* ^U: erase line */ case 0x17: /* ^W: erase word */ if(w->q0==0 || w->q0==w->qh) return; nb = wbswidth(w, r); q1 = w->q0; q0 = q1-nb; if(q0 < w->org){ q0 = w->org; nb = q1-q0; } if(nb > 0){ wdelete(w, q0, q0+nb); wsetselect(w, q0, q0); } return; } wshow(w, q0+1); #endif /* otherwise ordinary character; just insert */ q0 = w->q0; q0 = winsert(w, &r, 1, q0); }
void texttype(Text *t, Rune r) { uint q0, q1; int nnb, nb, n, i; int nr; Rune *rp; Text *u; if(t->what!=Body && r=='\n') return; nr = 1; rp = &r; switch(r){ case Kleft: if(t->q0 > 0){ typecommit(t); textshow(t, t->q0-1, t->q0-1, TRUE); } return; case Kright: if(t->q1 < t->file->nc){ typecommit(t); textshow(t, t->q1+1, t->q1+1, TRUE); } return; case Kdown: n = t->maxlines/3; goto case_Down; case Kscrollonedown: n = mousescrollsize(t->maxlines); if(n <= 0) n = 1; goto case_Down; case Kpgdown: n = 2*t->maxlines/3; case_Down: q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); textsetorigin(t, q0, TRUE); return; case Kup: n = t->maxlines/3; goto case_Up; case Kscrolloneup: n = mousescrollsize(t->maxlines); goto case_Up; case Kpgup: n = 2*t->maxlines/3; case_Up: q0 = textbacknl(t, t->org, n); textsetorigin(t, q0, TRUE); return; case Khome: typecommit(t); textshow(t, 0, 0, FALSE); return; case Kend: typecommit(t); textshow(t, t->file->nc, t->file->nc, FALSE); return; case 0x01: /* ^A: beginning of line */ typecommit(t); /* go to where ^U would erase, if not already at BOL */ nnb = 0; if(t->q0>0 && textreadc(t, t->q0-1)!='\n') nnb = textbswidth(t, 0x15); textshow(t, t->q0-nnb, t->q0-nnb, TRUE); return; case 0x05: /* ^E: end of line */ typecommit(t); q0 = t->q0; while(q0<t->file->nc && textreadc(t, q0)!='\n') q0++; textshow(t, q0, q0, TRUE); return; } if(t->what == Body){ seq++; filemark(t->file); } if(t->q1 > t->q0){ if(t->ncache != 0) error("text.type"); cut(t, t, nil, TRUE, TRUE, nil, 0); t->eq0 = ~0; } textshow(t, t->q0, t->q0, 1); switch(r){ case 0x06: case Kins: rp = textcomplete(t); if(rp == nil) return; nr = runestrlen(rp); break; /* fall through to normal insertion case */ case 0x1B: if(t->eq0 != ~0) textsetselect(t, t->eq0, t->q0); if(t->ncache > 0) typecommit(t); return; case 0x08: /* ^H: erase character */ case 0x15: /* ^U: erase line */ case 0x17: /* ^W: erase word */ if(t->q0 == 0) /* nothing to erase */ return; nnb = textbswidth(t, r); q1 = t->q0; q0 = q1-nnb; /* if selection is at beginning of window, avoid deleting invisible text */ if(q0 < t->org){ q0 = t->org; nnb = q1-q0; } if(nnb <= 0) return; for(i=0; i<t->file->ntext; i++){ u = t->file->text[i]; u->nofill = TRUE; nb = nnb; n = u->ncache; if(n > 0){ if(q1 != u->cq0+n) error("text.type backspace"); if(n > nb) n = nb; u->ncache -= n; textdelete(u, q1-n, q1, FALSE); nb -= n; } if(u->eq0==q1 || u->eq0==~0) u->eq0 = q0; if(nb && u==t) textdelete(u, q0, q0+nb, TRUE); if(u != t) textsetselect(u, u->q0, u->q1); else textsetselect(t, q0, q0); u->nofill = FALSE; } for(i=0; i<t->file->ntext; i++) textfill(t->file->text[i]); return; case '\n': if(t->w->autoindent){ /* find beginning of previous line using backspace code */ nnb = textbswidth(t, 0x15); /* ^U case */ rp = runemalloc(nnb + 1); nr = 0; rp[nr++] = r; for(i=0; i<nnb; i++){ r = textreadc(t, t->q0-nnb+i); if(r != ' ' && r != '\t') break; rp[nr++] = r; } } break; /* fall through to normal code */ } /* otherwise ordinary character; just insert, typically in caches of all texts */ for(i=0; i<t->file->ntext; i++){ u = t->file->text[i]; if(u->eq0 == ~0) u->eq0 = t->q0; if(u->ncache == 0) u->cq0 = t->q0; else if(t->q0 != u->cq0+u->ncache) error("text.type cq1"); textinsert(u, t->q0, rp, nr, FALSE); if(u != t) textsetselect(u, u->q0, u->q1); if(u->ncache+nr > u->ncachealloc){ u->ncachealloc += 10 + nr; u->cache = runerealloc(u->cache, u->ncachealloc); } runemove(u->cache+u->ncache, rp, nr); u->ncache += nr; } if(rp != &r) free(rp); textsetselect(t, t->q0+nr, t->q0+nr); if(r=='\n' && t->w!=nil) wincommit(t->w, t); }