acme: add spacesindent mode

This commit is contained in:
spew 2018-08-01 11:14:59 -04:00
parent 2b619dc966
commit 4757debd0b
8 changed files with 115 additions and 34 deletions

View file

@ -4,7 +4,7 @@ acme, win \- interactive text windows
.SH SYNOPSIS
.B acme
[
.B -ab
.B -aib
]
[
.B -c
@ -174,6 +174,16 @@ The option
.B -a
causes each window to start in
autoindent mode.
.PP
When a window is in spacesindent mode
(see the
.B Spaces
command below) and a tab character is typed,
acme indents the line with spaces equal to the current
tabstop for the window. The option
.B -i
causes each window to start in spacesindent
mode.
.SS "Directory context
Each window's tag names a directory: explicitly if the window
holds a directory; implicitly if it holds a regular file
@ -430,6 +440,17 @@ Place selected text in snarf buffer.
Arrange the windows in the column from top to bottom in lexicographical
order based on their names.
.TP
.B Spaces
Set the spacesindent mode according to the argument:
.B on
and
.B off
set the mode for the current window;
.B ON
and
.B OFF
set the mode for all existing and future windows.
.TP
.B Tab
Set the width of tab stops for this window to the value of the argument, in units of widths of the zero
character.

View file

@ -66,7 +66,7 @@ threadmain(int argc, char *argv[])
loadfile = nil;
ARGBEGIN{
case 'a':
globalautoindent = TRUE;
globalindent[AUTOINDENT] = TRUE;
break;
case 'b':
bartflag = TRUE;
@ -89,6 +89,9 @@ threadmain(int argc, char *argv[])
if(fontnames[1] == nil)
goto Usage;
break;
case 'i':
globalindent[SPACESINDENT] = TRUE;
break;
case 'l':
loadfile = ARGF();
if(loadfile == nil)
@ -96,7 +99,7 @@ threadmain(int argc, char *argv[])
break;
default:
Usage:
fprint(2, "usage: acme [-ab] [-c ncol] [-f font] [-F fixedfont] [-l loadfile | file...]\n");
fprint(2, "usage: acme [-aib] [-c ncol] [-f font] [-F fixedfont] [-l loadfile | file...]\n");
exits("usage");
}ARGEND

View file

@ -224,6 +224,13 @@ void textsetselect(Text*, uint, uint);
void textshow(Text*, uint, uint, int);
void texttype(Text*, Rune);
enum
{
SPACESINDENT = 0,
AUTOINDENT,
NINDENT,
};
struct Window
{
QLock;
@ -235,7 +242,7 @@ struct Window
uchar isscratch;
uchar filemenu;
uchar dirty;
uchar autoindent;
uchar indent[NINDENT];
uchar showdel;
uint noredraw;
int id;
@ -538,7 +545,7 @@ int plumbeditfd;
char wdir[];
int editing;
int messagesize; /* negotiated in 9P version setup */
int globalautoindent;
int globalindent[NINDENT];
Channel *cplumb; /* chan(Plumbmsg*) */
Channel *cwait; /* chan(Waitmsg) */

View file

@ -73,7 +73,7 @@ Exectab exectab[] = {
{ L"Get", get, FALSE, TRUE, XXX },
{ L"ID", id, FALSE, XXX, XXX },
{ L"Incl", incl, FALSE, XXX, XXX },
{ L"Indent", indent, FALSE, XXX, XXX },
{ L"Indent", indent, FALSE, AUTOINDENT, XXX },
{ L"Kill", kill, FALSE, XXX, XXX },
{ L"Load", dump, FALSE, FALSE, XXX },
{ L"Local", local, FALSE, XXX, XXX },
@ -87,6 +87,7 @@ Exectab exectab[] = {
{ L"Send", sendx, TRUE, XXX, XXX },
{ L"Snarf", cut, FALSE, TRUE, FALSE },
{ L"Sort", sort, FALSE, XXX, XXX },
{ L"Spaces", indent, FALSE, SPACESINDENT, XXX },
{ L"Tab", tab, FALSE, XXX, XXX },
{ L"Undo", undo, FALSE, TRUE, XXX },
{ L"Zerox", zeroxx, FALSE, XXX, XXX },
@ -1087,57 +1088,67 @@ incl(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg)
enum {
IGlobal = -2,
IError = -1,
Ion = 0,
Ioff = 1,
};
static int
indentval(Rune *s, int n)
indentval(Rune *s, int n, int type)
{
static char *strs[] = {
[SPACESINDENT] "Spaces",
[AUTOINDENT] "Indent",
};
if(n < 2)
return IError;
if(runestrncmp(s, L"ON", n) == 0){
globalautoindent = TRUE;
warning(nil, "Indent ON\n");
globalindent[type] = TRUE;
warning(nil, "%s ON\n", strs[type]);
return IGlobal;
}
if(runestrncmp(s, L"OFF", n) == 0){
globalautoindent = FALSE;
warning(nil, "Indent OFF\n");
globalindent[type] = FALSE;
warning(nil, "%s OFF\n", strs[type]);
return IGlobal;
}
return runestrncmp(s, L"on", n) == 0;
if(runestrncmp(s, L"on", n) == 0)
return TRUE;
if(runestrncmp(s, L"off", n) == 0)
return FALSE;
return IError;
}
static void
fixindent(Window *w, void*)
fixindent(Window *w, void *v)
{
w->autoindent = globalautoindent;
int t;
t = (int)v;
w->indent[t] = globalindent[t];
}
void
indent(Text *et, Text*, Text *argt, int, int, Rune *arg, int narg)
indent(Text *et, Text*, Text *argt, int type, int, Rune *arg, int narg)
{
Rune *a, *r;
Window *w;
int na, len, autoindent;
int na, len, ival;
w = nil;
if(et!=nil && et->w!=nil)
w = et->w;
autoindent = IError;
ival = IError;
getarg(argt, FALSE, TRUE, &r, &len);
if(r!=nil && len>0)
autoindent = indentval(r, len);
ival = indentval(r, len, type);
else{
a = findbl(arg, narg, &na);
if(a != arg)
autoindent = indentval(arg, narg-na);
ival = indentval(arg, narg-na, type);
}
if(autoindent == IGlobal)
allwindows(fixindent, nil);
else if(w != nil && autoindent >= 0)
w->autoindent = autoindent;
if(ival == IGlobal)
allwindows(fixindent, (void*)type);
else if(w != nil && ival >= 0)
w->indent[type] = ival;
}
void

View file

@ -663,9 +663,11 @@ openfile(Text *t, Expand *e)
runemove(rp, ow->incl[i], n);
winaddincl(w, rp, n);
}
w->autoindent = ow->autoindent;
for(i=0; i < NINDENT; i++)
w->indent[i] = ow->indent[i];
}else
w->autoindent = globalautoindent;
for(i=0; i < NINDENT; i++)
w->indent[i] = globalindent[i];
}
if(e->a1 == e->a0)
eval = FALSE;

View file

@ -502,6 +502,27 @@ textreadc(Text *t, uint q)
return r;
}
static int
spacesindentbswidth(Text *t)
{
uint q, col;
Rune r;
col = textbswidth(t, 0x15);
q = t->q0;
while(q > 0){
r = textreadc(t, q-1);
if(r != ' ')
break;
q--;
if(--col % t->tabstop == 0)
break;
}
if(t->q0 == q)
return 1;
return t->q0-q;
}
int
textbswidth(Text *t, Rune c)
{
@ -510,8 +531,11 @@ textbswidth(Text *t, Rune c)
int skipping;
/* there is known to be at least one character to erase */
if(c == 0x08) /* ^H: erase character */
if(c == 0x08){ /* ^H: erase character */
if(t->what == Body && t->w->indent[SPACESINDENT])
return spacesindentbswidth(t);
return 1;
}
q = t->q0;
skipping = TRUE;
while(q > 0){
@ -775,8 +799,19 @@ texttype(Text *t, Rune r)
for(i=0; i<t->file->ntext; i++)
textfill(t->file->text[i]);
return;
case '\t':
if(t->what == Body && t->w->indent[SPACESINDENT]){
nnb = textbswidth(t, 0x15);
if(nnb == 1 && textreadc(t, t->q0-1) == '\n')
nnb = 0;
nnb = t->tabstop - nnb % t->tabstop;
rp = runemalloc(nnb);
for(nr = 0; nr < nnb; nr++)
rp[nr] = ' ';
}
break;
case '\n':
if(t->what == Body && t->w->autoindent){
if(t->what == Body && t->w->indent[AUTOINDENT]){
/* find beginning of previous line using backspace code */
nnb = textbswidth(t, 0x15); /* ^U case */
rp = runemalloc(nnb + 1);

View file

@ -85,7 +85,8 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
runemove(r, incl[i], n);
winaddincl(w, r, n);
}
w->autoindent = globalautoindent;
for(i=0; i<NINDENT; i++)
w->indent[i] = globalindent[i];
return w;
}

View file

@ -20,7 +20,7 @@ wininit(Window *w, Window *clone, Rectangle r)
File *f;
Reffont *rf;
Rune *rp;
int nc;
int nc, i;
w->tag.w = w;
w->taglines = 1;
@ -78,13 +78,14 @@ wininit(Window *w, Window *clone, Rectangle r)
draw(screen, br, button, nil, button->r.min);
w->filemenu = TRUE;
w->maxlines = w->body.maxlines;
w->autoindent = globalautoindent;
for(i=0; i<NINDENT; i++)
w->indent[i] = globalindent[i];
if(clone){
w->dirty = clone->dirty;
w->autoindent = clone->autoindent;
for(i=0; i<NINDENT; i++)
w->indent[i] = clone->indent[i];
textsetselect(&w->body, clone->body.q0, clone->body.q1);
winsettag(w);
w->autoindent = clone->autoindent;
}
}