Initial revision
This commit is contained in:
parent
a59ea66fa9
commit
84b1cb73b3
31 changed files with 3409 additions and 0 deletions
585
src/cmd/samterm/main.c
Normal file
585
src/cmd/samterm/main.c
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <thread.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include "flayer.h"
|
||||
#include "samterm.h"
|
||||
|
||||
Text cmd;
|
||||
Rune *scratch;
|
||||
long nscralloc;
|
||||
Cursor *cursor;
|
||||
Flayer *which = 0;
|
||||
Flayer *work = 0;
|
||||
long snarflen;
|
||||
long typestart = -1;
|
||||
long typeend = -1;
|
||||
long typeesc = -1;
|
||||
long modified = 0; /* strange lookahead for menus */
|
||||
char hostlock = 1;
|
||||
char hasunlocked = 0;
|
||||
int maxtab = 8;
|
||||
|
||||
void
|
||||
threadmain(int argc, char *argv[])
|
||||
{
|
||||
int i, got, scr;
|
||||
Text *t;
|
||||
Rectangle r;
|
||||
Flayer *nwhich;
|
||||
|
||||
getscreen(argc, argv);
|
||||
iconinit();
|
||||
initio();
|
||||
scratch = alloc(100*RUNESIZE);
|
||||
nscralloc = 100;
|
||||
r = screen->r;
|
||||
r.max.y = r.min.y+Dy(r)/5;
|
||||
flstart(screen->clipr);
|
||||
rinit(&cmd.rasp);
|
||||
flnew(&cmd.l[0], gettext, 1, &cmd);
|
||||
flinit(&cmd.l[0], r, font, cmdcols);
|
||||
cmd.nwin = 1;
|
||||
which = &cmd.l[0];
|
||||
cmd.tag = Untagged;
|
||||
outTs(Tversion, VERSION);
|
||||
startnewfile(Tstartcmdfile, &cmd);
|
||||
|
||||
got = 0;
|
||||
for(;;got = waitforio()){
|
||||
if(hasunlocked && RESIZED())
|
||||
resize();
|
||||
if(got&(1<<RHost))
|
||||
rcv();
|
||||
if(got&(1<<RPlumb)){
|
||||
for(i=0; cmd.l[i].textfn==0; i++)
|
||||
;
|
||||
current(&cmd.l[i]);
|
||||
flsetselect(which, cmd.rasp.nrunes, cmd.rasp.nrunes);
|
||||
type(which, RPlumb);
|
||||
}
|
||||
if(got&(1<<RKeyboard))
|
||||
if(which)
|
||||
type(which, RKeyboard);
|
||||
else
|
||||
kbdblock();
|
||||
if(got&(1<<RMouse)){
|
||||
if(hostlock==2 || !ptinrect(mousep->xy, screen->r)){
|
||||
mouseunblock();
|
||||
continue;
|
||||
}
|
||||
nwhich = flwhich(mousep->xy);
|
||||
scr = which && ptinrect(mousep->xy, which->scroll);
|
||||
if(mousep->buttons)
|
||||
flushtyping(1);
|
||||
if(mousep->buttons&1){
|
||||
if(nwhich){
|
||||
if(nwhich!=which)
|
||||
current(nwhich);
|
||||
else if(scr)
|
||||
scroll(which, 1);
|
||||
else{
|
||||
t=(Text *)which->user1;
|
||||
if(flselect(which)){
|
||||
outTsl(Tdclick, t->tag, which->p0);
|
||||
t->lock++;
|
||||
}else if(t!=&cmd)
|
||||
outcmd();
|
||||
}
|
||||
}
|
||||
}else if((mousep->buttons&2) && which){
|
||||
if(scr)
|
||||
scroll(which, 2);
|
||||
else
|
||||
menu2hit();
|
||||
}else if((mousep->buttons&4)){
|
||||
if(scr)
|
||||
scroll(which, 3);
|
||||
else
|
||||
menu3hit();
|
||||
}
|
||||
mouseunblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
resize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
flresize(screen->clipr);
|
||||
for(i = 0; i<nname; i++)
|
||||
if(text[i])
|
||||
hcheck(text[i]->tag);
|
||||
}
|
||||
|
||||
void
|
||||
current(Flayer *nw)
|
||||
{
|
||||
Text *t;
|
||||
|
||||
if(which)
|
||||
flborder(which, 0);
|
||||
if(nw){
|
||||
flushtyping(1);
|
||||
flupfront(nw);
|
||||
flborder(nw, 1);
|
||||
buttons(Up);
|
||||
t = (Text *)nw->user1;
|
||||
t->front = nw-&t->l[0];
|
||||
if(t != &cmd)
|
||||
work = nw;
|
||||
}
|
||||
which = nw;
|
||||
}
|
||||
|
||||
void
|
||||
closeup(Flayer *l)
|
||||
{
|
||||
Text *t=(Text *)l->user1;
|
||||
int m;
|
||||
|
||||
m = whichmenu(t->tag);
|
||||
if(m < 0)
|
||||
return;
|
||||
flclose(l);
|
||||
if(l == which){
|
||||
which = 0;
|
||||
current(flwhich(Pt(0, 0)));
|
||||
}
|
||||
if(l == work)
|
||||
work = 0;
|
||||
if(--t->nwin == 0){
|
||||
rclear(&t->rasp);
|
||||
free((uchar *)t);
|
||||
text[m] = 0;
|
||||
}else if(l == &t->l[t->front]){
|
||||
for(m=0; m<NL; m++) /* find one; any one will do */
|
||||
if(t->l[m].textfn){
|
||||
t->front = m;
|
||||
return;
|
||||
}
|
||||
panic("close");
|
||||
}
|
||||
}
|
||||
|
||||
Flayer *
|
||||
findl(Text *t)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i<NL; i++)
|
||||
if(t->l[i].textfn==0)
|
||||
return &t->l[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
duplicate(Flayer *l, Rectangle r, Font *f, int close)
|
||||
{
|
||||
Text *t=(Text *)l->user1;
|
||||
Flayer *nl = findl(t);
|
||||
Rune *rp;
|
||||
ulong n;
|
||||
|
||||
if(nl){
|
||||
flnew(nl, gettext, l->user0, (char *)t);
|
||||
flinit(nl, r, f, l->f.cols);
|
||||
nl->origin = l->origin;
|
||||
rp = (*l->textfn)(l, l->f.nchars, &n);
|
||||
flinsert(nl, rp, rp+n, l->origin);
|
||||
flsetselect(nl, l->p0, l->p1);
|
||||
if(close){
|
||||
flclose(l);
|
||||
if(l==which)
|
||||
which = 0;
|
||||
}else
|
||||
t->nwin++;
|
||||
current(nl);
|
||||
hcheck(t->tag);
|
||||
}
|
||||
setcursor(mousectl, cursor);
|
||||
}
|
||||
|
||||
void
|
||||
buttons(int updown)
|
||||
{
|
||||
while(((mousep->buttons&7)!=0) != updown)
|
||||
getmouse();
|
||||
}
|
||||
|
||||
int
|
||||
getr(Rectangle *rp)
|
||||
{
|
||||
Point p;
|
||||
Rectangle r;
|
||||
|
||||
*rp = getrect(3, mousectl);
|
||||
if(rp->max.x && rp->max.x-rp->min.x<=5 && rp->max.y-rp->min.y<=5){
|
||||
p = rp->min;
|
||||
r = cmd.l[cmd.front].entire;
|
||||
*rp = screen->r;
|
||||
if(cmd.nwin==1){
|
||||
if (p.y <= r.min.y)
|
||||
rp->max.y = r.min.y;
|
||||
else if (p.y >= r.max.y)
|
||||
rp->min.y = r.max.y;
|
||||
if (p.x <= r.min.x)
|
||||
rp->max.x = r.min.x;
|
||||
else if (p.x >= r.max.x)
|
||||
rp->min.x = r.max.x;
|
||||
}
|
||||
}
|
||||
return rectclip(rp, screen->r) &&
|
||||
rp->max.x-rp->min.x>100 && rp->max.y-rp->min.y>40;
|
||||
}
|
||||
|
||||
void
|
||||
snarf(Text *t, int w)
|
||||
{
|
||||
Flayer *l = &t->l[w];
|
||||
|
||||
if(l->p1>l->p0){
|
||||
snarflen = l->p1-l->p0;
|
||||
outTsll(Tsnarf, t->tag, l->p0, l->p1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cut(Text *t, int w, int save, int check)
|
||||
{
|
||||
long p0, p1;
|
||||
Flayer *l;
|
||||
|
||||
l = &t->l[w];
|
||||
p0 = l->p0;
|
||||
p1 = l->p1;
|
||||
if(p0 == p1)
|
||||
return;
|
||||
if(p0 < 0)
|
||||
panic("cut");
|
||||
if(save)
|
||||
snarf(t, w);
|
||||
outTsll(Tcut, t->tag, p0, p1);
|
||||
flsetselect(l, p0, p0);
|
||||
t->lock++;
|
||||
hcut(t->tag, p0, p1-p0);
|
||||
if(check)
|
||||
hcheck(t->tag);
|
||||
}
|
||||
|
||||
void
|
||||
paste(Text *t, int w)
|
||||
{
|
||||
if(snarflen){
|
||||
cut(t, w, 0, 0);
|
||||
t->lock++;
|
||||
outTsl(Tpaste, t->tag, t->l[w].p0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scrorigin(Flayer *l, int but, long p0)
|
||||
{
|
||||
Text *t=(Text *)l->user1;
|
||||
|
||||
switch(but){
|
||||
case 1:
|
||||
outTsll(Torigin, t->tag, l->origin, p0);
|
||||
break;
|
||||
case 2:
|
||||
outTsll(Torigin, t->tag, p0, 1L);
|
||||
break;
|
||||
case 3:
|
||||
horigin(t->tag,p0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
alnum(int c)
|
||||
{
|
||||
/*
|
||||
* Hard to get absolutely right. Use what we know about ASCII
|
||||
* and assume anything above the Latin control characters is
|
||||
* potentially an alphanumeric.
|
||||
*/
|
||||
if(c<=' ')
|
||||
return 0;
|
||||
if(0x7F<=c && c<=0xA0)
|
||||
return 0;
|
||||
if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
raspc(Rasp *r, long p)
|
||||
{
|
||||
ulong n;
|
||||
rload(r, p, p+1, &n);
|
||||
if(n)
|
||||
return scratch[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
ctlw(Rasp *r, long o, long p)
|
||||
{
|
||||
int c;
|
||||
|
||||
if(--p < o)
|
||||
return o;
|
||||
if(raspc(r, p)=='\n')
|
||||
return p;
|
||||
for(; p>=o && !alnum(c=raspc(r, p)); --p)
|
||||
if(c=='\n')
|
||||
return p+1;
|
||||
for(; p>o && alnum(raspc(r, p-1)); --p)
|
||||
;
|
||||
return p>=o? p : o;
|
||||
}
|
||||
|
||||
long
|
||||
ctlu(Rasp *r, long o, long p)
|
||||
{
|
||||
for(; p-1>=o && raspc(r, p-1)!='\n'; --p)
|
||||
;
|
||||
return p>=o? p : o;
|
||||
}
|
||||
|
||||
int
|
||||
center(Flayer *l, long a)
|
||||
{
|
||||
Text *t;
|
||||
|
||||
t = l->user1;
|
||||
if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
|
||||
if(a > t->rasp.nrunes)
|
||||
a = t->rasp.nrunes;
|
||||
outTsll(Torigin, t->tag, a, 2L);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
onethird(Flayer *l, long a)
|
||||
{
|
||||
Text *t;
|
||||
Rectangle s;
|
||||
long lines;
|
||||
|
||||
t = l->user1;
|
||||
if(!t->lock && (a<l->origin || l->origin+l->f.nchars<a)){
|
||||
if(a > t->rasp.nrunes)
|
||||
a = t->rasp.nrunes;
|
||||
s = insetrect(l->scroll, 1);
|
||||
lines = ((s.max.y-s.min.y)/l->f.font->height+1)/3;
|
||||
if (lines < 2)
|
||||
lines = 2;
|
||||
outTsll(Torigin, t->tag, a, lines);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
flushtyping(int clearesc)
|
||||
{
|
||||
Text *t;
|
||||
ulong n;
|
||||
|
||||
if(clearesc)
|
||||
typeesc = -1;
|
||||
if(typestart == typeend) {
|
||||
modified = 0;
|
||||
return;
|
||||
}
|
||||
t = which->user1;
|
||||
if(t != &cmd)
|
||||
modified = 1;
|
||||
rload(&t->rasp, typestart, typeend, &n);
|
||||
scratch[n] = 0;
|
||||
if(t==&cmd && typeend==t->rasp.nrunes && scratch[typeend-typestart-1]=='\n'){
|
||||
setlock();
|
||||
outcmd();
|
||||
}
|
||||
outTslS(Ttype, t->tag, typestart, scratch);
|
||||
typestart = -1;
|
||||
typeend = -1;
|
||||
}
|
||||
|
||||
#define SCROLLKEY Kdown
|
||||
#define BACKSCROLLKEY Kup
|
||||
#define ESC 0x1B
|
||||
|
||||
void
|
||||
type(Flayer *l, int res) /* what a bloody mess this is */
|
||||
{
|
||||
Text *t = (Text *)l->user1;
|
||||
Rune buf[100];
|
||||
Rune *p = buf;
|
||||
int c, backspacing;
|
||||
long a, a0;
|
||||
int scrollkey;
|
||||
|
||||
scrollkey = 0;
|
||||
if(res == RKeyboard)
|
||||
scrollkey = (qpeekc()==SCROLLKEY || qpeekc()==BACKSCROLLKEY); /* ICK */
|
||||
|
||||
if(hostlock || t->lock){
|
||||
kbdblock();
|
||||
return;
|
||||
}
|
||||
a = l->p0;
|
||||
if(a!=l->p1 && !scrollkey){
|
||||
flushtyping(1);
|
||||
cut(t, t->front, 1, 1);
|
||||
return; /* it may now be locked */
|
||||
}
|
||||
backspacing = 0;
|
||||
while((c = kbdchar())>0){
|
||||
if(res == RKeyboard){
|
||||
if(c==SCROLLKEY || c==BACKSCROLLKEY || c==ESC)
|
||||
break;
|
||||
/* backspace, ctrl-u, ctrl-w, del */
|
||||
if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){
|
||||
backspacing = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p++ = c;
|
||||
if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))
|
||||
break;
|
||||
}
|
||||
if(p > buf){
|
||||
if(typestart < 0)
|
||||
typestart = a;
|
||||
if(typeesc < 0)
|
||||
typeesc = a;
|
||||
hgrow(t->tag, a, p-buf, 0);
|
||||
t->lock++; /* pretend we Trequest'ed for hdatarune*/
|
||||
hdatarune(t->tag, a, buf, p-buf);
|
||||
a += p-buf;
|
||||
l->p0 = a;
|
||||
l->p1 = a;
|
||||
typeend = a;
|
||||
if(c=='\n' || typeend-typestart>100)
|
||||
flushtyping(0);
|
||||
onethird(l, a);
|
||||
}
|
||||
if(c == SCROLLKEY){
|
||||
flushtyping(0);
|
||||
center(l, l->origin+l->f.nchars+1);
|
||||
/* backspacing immediately after outcmd(): sorry */
|
||||
}else if(c == BACKSCROLLKEY){
|
||||
flushtyping(0);
|
||||
a0 = l->origin-l->f.nchars;
|
||||
if(a0 < 0)
|
||||
a0 = 0;
|
||||
center(l, a0);
|
||||
}else if(backspacing && !hostlock){
|
||||
if(l->f.p0>0 && a>0){
|
||||
switch(c){
|
||||
case '\b':
|
||||
case 0x7F: /* del */
|
||||
l->p0 = a-1;
|
||||
break;
|
||||
case 0x15: /* ctrl-u */
|
||||
l->p0 = ctlu(&t->rasp, l->origin, a);
|
||||
break;
|
||||
case 0x17: /* ctrl-w */
|
||||
l->p0 = ctlw(&t->rasp, l->origin, a);
|
||||
break;
|
||||
}
|
||||
l->p1 = a;
|
||||
if(l->p1 != l->p0){
|
||||
/* cut locally if possible */
|
||||
if(typestart<=l->p0 && l->p1<=typeend){
|
||||
t->lock++; /* to call hcut */
|
||||
hcut(t->tag, l->p0, l->p1-l->p0);
|
||||
/* hcheck is local because we know rasp is contiguous */
|
||||
hcheck(t->tag);
|
||||
}else{
|
||||
flushtyping(0);
|
||||
cut(t, t->front, 0, 1);
|
||||
}
|
||||
}
|
||||
if(typeesc >= l->p0)
|
||||
typeesc = l->p0;
|
||||
if(typestart >= 0){
|
||||
if(typestart >= l->p0)
|
||||
typestart = l->p0;
|
||||
typeend = l->p0;
|
||||
if(typestart == typeend){
|
||||
typestart = -1;
|
||||
typeend = -1;
|
||||
modified = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(c==ESC && typeesc>=0){
|
||||
l->p0 = typeesc;
|
||||
l->p1 = a;
|
||||
flushtyping(1);
|
||||
}
|
||||
for(l=t->l; l<&t->l[NL]; l++)
|
||||
if(l->textfn)
|
||||
flsetselect(l, l->p0, l->p1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
outcmd(void){
|
||||
if(work)
|
||||
outTsll(Tworkfile, ((Text *)work->user1)->tag, work->p0, work->p1);
|
||||
}
|
||||
|
||||
void
|
||||
panic(char *s)
|
||||
{
|
||||
panic1(display, s);
|
||||
}
|
||||
|
||||
void
|
||||
panic1(Display *d, char *s)
|
||||
{
|
||||
fprint(2, "samterm:panic: ");
|
||||
perror(s);
|
||||
abort();
|
||||
}
|
||||
|
||||
Rune*
|
||||
gettext(Flayer *l, long n, ulong *np)
|
||||
{
|
||||
Text *t;
|
||||
|
||||
t = l->user1;
|
||||
rload(&t->rasp, l->origin, l->origin+n, np);
|
||||
return scratch;
|
||||
}
|
||||
|
||||
long
|
||||
scrtotal(Flayer *l)
|
||||
{
|
||||
return ((Text *)l->user1)->rasp.nrunes;
|
||||
}
|
||||
|
||||
void*
|
||||
alloc(ulong n)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(n);
|
||||
if(p == 0)
|
||||
panic("alloc");
|
||||
memset(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue