📄 text.c
字号:
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);}voidtextcommit(Text *t, int tofile){ if(t->ncache == 0) return; if(tofile) fileinsert(t->file, t->cq0, t->cache, t->ncache); if(t->what == Body){ t->w->dirty = TRUE; t->w->utflastqid = -1; } t->ncache = 0;}static Text *clicktext;static uint clickmsec;static Text *selecttext;static uint selectq;/* * called from frame library */voidframescroll(Frame *f, int dl){ if(f != &selecttext->Frame) error("frameselect not right frame"); textframescroll(selecttext, dl);}voidtextframescroll(Text *t, int dl){ uint q0; if(dl == 0){ scrsleep(100); return; } if(dl < 0){ q0 = textbacknl(t, t->org, -dl); if(selectq > t->org+t->p0) textsetselect(t, t->org+t->p0, selectq); else textsetselect(t, selectq, t->org+t->p0); }else{ if(t->org+t->nchars == t->file->nc) return; q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height)); if(selectq > t->org+t->p1) textsetselect(t, t->org+t->p1, selectq); else textsetselect(t, selectq, t->org+t->p1); } textsetorigin(t, q0, TRUE);}voidtextselect(Text *t){ uint q0, q1; int b, x, y; int state; selecttext = t; /* * To have double-clicking and chording, we double-click * immediately if it might make sense. */ b = mouse->buttons; q0 = t->q0; q1 = t->q1; selectq = t->org+frcharofpt(t, mouse->xy); if(clicktext==t && mouse->msec-clickmsec<500) if(q0==q1 && selectq==q0){ textdoubleclick(t, &q0, &q1); textsetselect(t, q0, q1); flushimage(display, 1); x = mouse->xy.x; y = mouse->xy.y; /* stay here until something interesting happens */ do readmouse(mousectl); while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3); mouse->xy.x = x; /* in case we're calling frselect */ mouse->xy.y = y; q0 = t->q0; /* may have changed */ q1 = t->q1; selectq = q0; } if(mouse->buttons == b){ t->Frame.scroll = framescroll; frselect(t, mousectl); /* horrible botch: while asleep, may have lost selection altogether */ if(selectq > t->file->nc) selectq = t->org + t->p0; t->Frame.scroll = nil; if(selectq < t->org) q0 = selectq; else q0 = t->org + t->p0; if(selectq > t->org+t->nchars) q1 = selectq; else q1 = t->org+t->p1; } if(q0 == q1){ if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){ textdoubleclick(t, &q0, &q1); clicktext = nil; }else{ clicktext = t; clickmsec = mouse->msec; } }else clicktext = nil; textsetselect(t, q0, q1); flushimage(display, 1); state = 0; /* undo when possible; +1 for cut, -1 for paste */ while(mouse->buttons){ mouse->msec = 0; b = mouse->buttons; if((b&1) && (b&6)){ if(state==0 && t->what==Body){ seq++; filemark(t->w->body.file); } if(b & 2){ if(state==-1 && t->what==Body){ winundo(t->w, TRUE); textsetselect(t, q0, t->q0); state = 0; }else if(state != 1){ cut(t, t, nil, TRUE, TRUE, nil, 0); state = 1; } }else{ if(state==1 && t->what==Body){ winundo(t->w, TRUE); textsetselect(t, q0, t->q1); state = 0; }else if(state != -1){ paste(t, t, nil, TRUE, FALSE, nil, 0); state = -1; } } textscrdraw(t); clearmouse(); } flushimage(display, 1); while(mouse->buttons == b) readmouse(mousectl); clicktext = nil; }}voidtextshow(Text *t, uint q0, uint q1, int doselect){ int qe; int nl; uint q; if(t->what != Body){ if(doselect) textsetselect(t, q0, q1); return; } if(t->w!=nil && t->maxlines==0) colgrow(t->col, t->w, 1); if(doselect) textsetselect(t, q0, q1); qe = t->org+t->nchars; if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache))) textscrdraw(t); else{ if(t->w->nopen[QWevent] > 0) nl = 3*t->maxlines/4; else nl = t->maxlines/4; q = textbacknl(t, q0, nl); /* avoid going backwards if trying to go forwards - long lines! */ if(!(q0>t->org && q<t->org)) textsetorigin(t, q, TRUE); while(q0 > t->org+t->nchars) textsetorigin(t, t->org+1, FALSE); }}staticintregion(int a, int b){ if(a < b) return -1; if(a == b) return 0; return 1;}voidselrestore(Frame *f, Point pt0, uint p0, uint p1){ if(p1<=f->p0 || p0>=f->p1){ /* no overlap */ frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); return; } if(p0>=f->p0 && p1<=f->p1){ /* entirely inside */ frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); return; } /* they now are known to overlap */ /* before selection */ if(p0 < f->p0){ frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); p0 = f->p0; pt0 = frptofchar(f, p0); } /* after selection */ if(p1 > f->p1){ frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); p1 = f->p1; } /* inside selection */ frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);}voidtextsetselect(Text *t, uint q0, uint q1){ int p0, p1; /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ t->q0 = q0; t->q1 = q1; /* compute desired p0,p1 from q0,q1 */ p0 = q0-t->org; p1 = q1-t->org; if(p0 < 0) p0 = 0; if(p1 < 0) p1 = 0; if(p0 > t->nchars) p0 = t->nchars; if(p1 > t->nchars) p1 = t->nchars; if(p0==t->p0 && p1==t->p1) return; /* screen disagrees with desired selection */ if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ /* no overlap or too easy to bother trying */ frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); frdrawsel(t, frptofchar(t, p0), p0, p1, 1); goto Return; } /* overlap; avoid unnecessary painting */ if(p0 < t->p0){ /* extend selection backwards */ frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); }else if(p0 > t->p0){ /* trim first part of selection */ frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); } if(p1 > t->p1){ /* extend selection forwards */ frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); }else if(p1 < t->p1){ /* trim last part of selection */ frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); } Return: t->p0 = p0; t->p1 = p1;}/* * Release the button in less than DELAY ms and it's considered a null selection * if the mouse hardly moved, regardless of whether it crossed a char boundary. */enum { DELAY = 2, MINMOVE = 4,};uintxselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */{ uint p0, p1, q, tmp; ulong msec; Point mp, pt0, pt1, qt; int reg, b; mp = mc->xy; b = mc->buttons; msec = mc->msec; /* remove tick */ if(f->p0 == f->p1) frtick(f, frptofchar(f, f->p0), 0); p0 = p1 = frcharofpt(f, mp); pt0 = frptofchar(f, p0); pt1 = frptofchar(f, p1); reg = 0; frtick(f, pt0, 1); do{ q = frcharofpt(f, mc->xy); if(p1 != q){ if(p0 == p1) frtick(f, pt0, 0); if(reg != region(q, p0)){ /* crossed starting point; reset */ if(reg > 0) selrestore(f, pt0, p0, p1); else if(reg < 0) selrestore(f, pt1, p1, p0); p1 = p0; pt1 = pt0; reg = region(q, p0); if(reg == 0) frdrawsel0(f, pt0, p0, p1, col, display->white); } qt = frptofchar(f, q); if(reg > 0){ if(q > p1) frdrawsel0(f, pt1, p1, q, col, display->white); else if(q < p1) selrestore(f, qt, q, p1); }else if(reg < 0){ if(q > p1) selrestore(f, pt1, p1, q); else frdrawsel0(f, qt, q, p1, col, display->white); } p1 = q; pt1 = qt; } if(p0 == p1) frtick(f, pt0, 1); flushimage(f->display, 1); readmouse(mc); }while(mc->buttons == b); if(mc->msec-msec < DELAY && p0!=p1 && abs(mp.x-mc->xy.x)<MINMOVE && abs(mp.y-mc->xy.y)<MINMOVE) { if(reg > 0) selrestore(f, pt0, p0, p1); else if(reg < 0) selrestore(f, pt1, p1, p0); p1 = p0; } if(p1 < p0){ tmp = p0; p0 = p1; p1 = tmp; } pt0 = frptofchar(f, p0); if(p0 == p1) frtick(f, pt0, 0); selrestore(f, pt0, p0, p1); /* restore tick */ if(f->p0 == f->p1) frtick(f, frptofchar(f, f->p0), 1); flushimage(f->display, 1); *p1p = p1; return p0;}inttextselect23(Text *t, uint *q0, uint *q1, Image *high, int mask){ uint p0, p1; int buts; p0 = xselect(t, mousectl, high, &p1); buts = mousectl->buttons; if((buts & mask) == 0){ *q0 = p0+t->org; *q1 = p1+t->org; } while(mousectl->buttons) readmouse(mousectl); return buts;}inttextselect2(Text *t, uint *q0, uint *q1, Text **tp){ int buts; *tp = nil; buts = textselect23(t, q0, q1, but2col, 4); if(buts & 4) return 0; if(buts & 1){ /* pick up argument */ *tp = argtext; return 1; } return 1;}inttextselect3(Text *t, uint *q0, uint *q1){ int h; h = (textselect23(t, q0, q1, but3col, 1|2) == 0); return h;}static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };static Rune left2[] = { L'\n', 0 };static Rune left3[] = { L'\'', L'"', L'`', 0 };staticRune *left[] = { left1, left2, left3, nil};staticRune *right[] = { right1, left2, left3, nil};voidtextdoubleclick(Text *t, uint *q0, uint *q1){ int c, i; Rune *r, *l, *p; uint q; for(i=0; left[i]!=nil; i++){ q = *q0; l = left[i]; r = right[i]; /* try matching character to left, looking right */ if(q == 0) c = '\n'; else c = textreadc(t, q-1); p = runestrchr(l, c); if(p != nil){ if(textclickmatch(t, c, r[p-l], 1, &q)) *q1 = q-(c!='\n'); return; } /* try matching character to right, looking left */ if(q == t->file->nc) c = '\n'; else c = textreadc(t, q); p = runestrchr(r, c); if(p != nil){ if(textclickmatch(t, c, l[p-r], -1, &q)){ *q1 = *q0+(*q0<t->file->nc && c=='\n'); *q0 = q; if(c!='\n' || q!=0 || textreadc(t, 0)=='\n') (*q0)++; } return; } } /* try filling out word to right */ while(*q1<t->file->nc && isalnum(textreadc(t, *q1))) (*q1)++; /* try filling out word to left */ while(*q0>0 && isalnum(textreadc(t, *q0-1))) (*q0)--;}inttextclickmatch(Text *t, int cl, int cr, int dir, uint *q){ Rune c; int nest; nest = 1; for(;;){ if(dir > 0){ if(*q == t->file->nc) break; c = textreadc(t, *q); (*q)++; }else{ if(*q == 0) break; (*q)--; c = textreadc(t, *q); } if(c == cr){ if(--nest==0) return 1; }else if(c == cl) nest++; } return cl=='\n' && nest==1;}uinttextbacknl(Text *t, uint p, uint n){ int i, j; /* look for start of this line if n==0 */ if(n==0 && p>0 && textreadc(t, p-1)!='\n') n = 1; i = n; while(i-->0 && p>0){ --p; /* it's at a newline now; back over it */ if(p == 0) break; /* at 128 chars, call it a line anyway */ for(j=128; --j>0 && p>0; p--) if(textreadc(t, p-1)=='\n') break; } return p;}voidtextsetorigin(Text *t, uint org, int exact){ int i, a, fixup; Rune *r; uint n; if(org>0 && !exact){ /* org is an estimate of the char posn; find a newline */ /* don't try harder than 256 chars */ for(i=0; i<256 && org<t->file->nc; i++){ if(textreadc(t, org) == '\n'){ org++; break; } org++; } } a = org-t->org; fixup = 0; if(a>=0 && a<t->nchars){ frdelete(t, 0, a); fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ } else if(a<0 && -a<t->nchars){ n = t->org - org; r = runemalloc(n); bufread(t->file, org, r, n); frinsert(t, r, r+n, 0); free(r); }else frdelete(t, 0, t->nchars); t->org = org; textfill(t); textscrdraw(t); textsetselect(t, t->q0, t->q1); if(fixup && t->p1 > t->p0) frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1);}voidtextreset(Text *t){ t->file->seq = 0; t->eq0 = ~0; /* do t->delete(0, t->nc, TRUE) without building backup stuff */ textsetselect(t, t->org, t->org); frdelete(t, 0, t->nchars); t->org = 0; t->q0 = 0; t->q1 = 0; filereset(t->file); bufreset(t->file);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -