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); }
void waddraw(Window *w, Rune *r, int nr) { print_func_entry(); w->raw = runerealloc(w->raw, w->nraw+nr); runemove(w->raw+w->nraw, r, nr); w->nraw += nr; print_func_exit(); }
static void sizecache(Buffer *b, uint n) { if(n <= b->cmax) return; b->cmax = n+Slop; b->c = runerealloc(b->c, b->cmax); }
uint winsert(Window *w, Rune *r, int n, uint q0) { uint m; if(n == 0) return q0; if(w->nr+n>HiWater && q0>=w->org && q0>=w->qh){ m = min(HiWater-LoWater, min(w->org, w->qh)); w->org -= m; w->qh -= m; if(w->q0 > m) w->q0 -= m; else w->q0 = 0; if(w->q1 > m) w->q1 -= m; else w->q1 = 0; w->nr -= m; runemove(w->run, w->run+m, w->nr); q0 -= m; } if(w->nr+n > w->maxr){ /* * Minimize realloc breakage: * Allocate at least MinWater * Double allocation size each time * But don't go much above HiWater */ m = max(min(2*(w->nr+n), HiWater), w->nr+n)+MinWater; if(m > HiWater) m = max(HiWater+MinWater, w->nr+n); if(m > w->maxr){ w->run = runerealloc(w->run, m); w->maxr = m; } } runemove(w->run+q0+n, w->run+q0, w->nr-q0); runemove(w->run+q0, r, n); w->nr += n; /* if output touches, advance selection, not qh; works best for keyboard and output */ // TODO don't know if we might want this for displaying text. if(q0 <= w->q1) w->q1 += n; if(q0 <= w->q0) w->q0 += n; if(q0 < w->qh) w->qh += n; if(q0 < w->org) w->org += n; return q0; }
Runestr includename(Text *t, Rune *r, int n) { Window *w; char buf[128]; Rune Lsysinclude[] = { '/', 's', 'y', 's', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 }; Rune Lusrinclude[] = { '/', 'u', 's', 'r', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 }; Rune Lusrlocalinclude[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 }; Rune Lusrlocalplan9include[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l', '/', 'p', 'l', 'a', 'n', '9', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 }; Runestr file; int i; if(objdir==nil && objtype!=nil){ sprint(buf, "/%s/include", objtype); objdir = bytetorune(buf, &i); objdir = runerealloc(objdir, i+1); objdir[i] = '\0'; } w = t->w; if(n==0 || r[0]=='/' || w==nil) goto Rescue; if(n>2 && r[0]=='.' && r[1]=='/') goto Rescue; file.r = nil; file.nr = 0; for(i=0; i<w->nincl && file.r==nil; i++) file = includefile(w->incl[i], r, n); if(file.r == nil) file = includefile(Lsysinclude, r, n); if(file.r == nil) file = includefile(Lusrlocalplan9include, r, n); if(file.r == nil) file = includefile(Lusrlocalinclude, r, n); if(file.r == nil) file = includefile(Lusrinclude, r, n); if(file.r==nil && objdir!=nil) file = includefile(objdir, r, n); if(file.r == nil) goto Rescue; return file; Rescue: return runestr(r, n); }
void textinsert(Text *t, uint q0, Rune *r, uint n) { if(n == 0) return; t->rs.r = runerealloc(t->rs.r, t->rs.nr+n); runemove(t->rs.r+q0+n, t->rs.r+q0, t->rs.nr-q0); runemove(t->rs.r+q0, r, n); t->rs.nr += n; if(q0 < t->q1) t->q1 += n; if(q0 < t->q0) t->q0 += n; if(q0 < t->org) t->org += n; else if(q0 <= t->org+t->nchars) frinsert(t, r, r+n, q0-t->org); }
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); }
void texttype(Text *t, Rune r) { uint q0, q1; int nnb, nb, n, i; int nr; Rune *rp; Text *u; if(t->what!=Body && t->what!=Tag && r=='\n') return; if(t->what == Tag) t->w->tagsafe = FALSE; nr = 1; rp = &r; switch(r){ case Kleft: typecommit(t); if(t->q0 > 0) textshow(t, t->q0-1, t->q0-1, TRUE); return; case Kright: typecommit(t); if(t->q1 < t->file->b.nc) textshow(t, t->q1+1, t->q1+1, TRUE); return; case Kdown: if(t->what == Tag) goto Tagdown; n = t->fr.maxlines/3; goto case_Down; case Kscrollonedown: if(t->what == Tag) goto Tagdown; n = mousescrollsize(t->fr.maxlines); if(n <= 0) n = 1; goto case_Down; case Kpgdown: n = 2*t->fr.maxlines/3; case_Down: q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height)); textsetorigin(t, q0, TRUE); return; case Kup: if(t->what == Tag) goto Tagup; n = t->fr.maxlines/3; goto case_Up; case Kscrolloneup: if(t->what == Tag) goto Tagup; n = mousescrollsize(t->fr.maxlines); goto case_Up; case Kpgup: n = 2*t->fr.maxlines/3; case_Up: q0 = textbacknl(t, t->org, n); textsetorigin(t, q0, TRUE); return; case Khome: typecommit(t); if(t->org > t->iq1) { q0 = textbacknl(t, t->iq1, 1); textsetorigin(t, q0, TRUE); } else textshow(t, 0, 0, FALSE); return; case Kend: typecommit(t); if(t->iq1 > t->org+t->fr.nchars) { if(t->iq1 > t->file->b.nc) { // should not happen, but does. and it will crash textbacknl. t->iq1 = t->file->b.nc; } q0 = textbacknl(t, t->iq1, 1); textsetorigin(t, q0, TRUE); } else textshow(t, t->file->b.nc, t->file->b.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->b.nc && textreadc(t, q0)!='\n') q0++; textshow(t, q0, q0, TRUE); return; case Kcmd+'c': /* %C: copy */ typecommit(t); cut(t, t, nil, TRUE, FALSE, nil, 0); return; case Kcmd+'z': /* %Z: undo */ typecommit(t); undo(t, nil, nil, TRUE, 0, nil, 0); return; Tagdown: /* expand tag to show all text */ if(!t->w->tagexpand){ t->w->tagexpand = TRUE; winresize(t->w, t->w->r, FALSE, TRUE); } return; Tagup: /* shrink tag to single line */ if(t->w->tagexpand){ t->w->tagexpand = FALSE; t->w->taglines = 1; winresize(t->w, t->w->r, FALSE, TRUE); } return; } if(t->what == Body){ seq++; filemark(t->file); } /* cut/paste must be done after the seq++/filemark */ switch(r){ case Kcmd+'x': /* %X: cut */ typecommit(t); if(t->what == Body){ seq++; filemark(t->file); } cut(t, t, nil, TRUE, TRUE, nil, 0); textshow(t, t->q0, t->q0, 1); t->iq1 = t->q0; return; case Kcmd+'v': /* %V: paste */ typecommit(t); if(t->what == Body){ seq++; filemark(t->file); } paste(t, t, nil, TRUE, FALSE, nil, 0); textshow(t, t->q0, t->q1, 1); t->iq1 = t->q1; return; } 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: /* ^F: complete */ case Kins: typecommit(t); rp = textcomplete(t); if(rp == nil) return; nr = runestrlen(rp); break; /* fall through to normal insertion case */ case 0x1B: if(t->eq0 != ~0) { if(t->eq0 <= t->q0) textsetselect(t, t->eq0, t->q0); else textsetselect(t, t->q0, t->eq0); } if(t->ncache > 0) typecommit(t); t->iq1 = t->q0; 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]); t->iq1 = t->q0; 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"); /* * Change the tag before we add to ncache, * so that if the window body is resized the * commit will not find anything in ncache. */ if(u->what==Body && u->ncache == 0){ u->needundo = TRUE; winsettag(t->w); u->needundo = FALSE; } 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); t->iq1 = t->q0; }