commit bf136561b21a6a47e69fd4184a09d7a5f6077bb0
parent 9202804032cdd790ce9a777e494b56c4ad932083
Author: Rafael Garcia <rafael.garcia.gallego@gmail.com>
Date: Wed, 3 Aug 2011 10:36:51 +0200
Paradigm change: selection is now done automatically and key-bindings do unique things. Deleted S_Selecting status for true modelessness (save rw and icase). I still have to test this thoroughly, but I like it so far.
Diffstat:
config.def.h | | | 45 | +++++++++++++++++---------------------------- |
sandy.1 | | | 22 | +++++++++++++--------- |
sandy.c | | | 96 | ++++++++++++++++++++++++++++++++++++------------------------------------------- |
3 files changed, 74 insertions(+), 89 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -54,25 +54,24 @@ static const char nlstr[1] = { 0 };
static const Key curskeys[] = { /* Don't use CONTROL or META here */
/* keyv, tests, func, arg */
-{ {KEY_BACKSPACE}, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
{ {KEY_BACKSPACE}, { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
{ {KEY_DC}, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
{ {KEY_DC}, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
{ {KEY_IC}, { t_sel, 0, 0, 0 }, f_pipero, TOCLIP },
{ {KEY_SDC}, { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ {KEY_SIC}, { t_rw, 0, 0, 0 }, f_pipe, FROMCLIP },
-{ {KEY_HOME}, { 0, 0, 0, 0 }, f_move, { .m = m_bol } },
-{ {KEY_END}, { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ {KEY_SHOME}, { 0, 0, 0, 0 }, f_move, { .m = m_bof } },
-{ {KEY_SEND}, { 0, 0, 0, 0 }, f_move, { .m = m_eof } },
-{ {KEY_PPAGE}, { 0, 0, 0, 0 }, f_move, { .m = m_prevscr } },
-{ {KEY_NPAGE}, { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } },
-{ {KEY_UP}, { 0, 0, 0, 0 }, f_move, { .m = m_prevline } },
-{ {KEY_DOWN}, { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ {KEY_LEFT}, { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
-{ {KEY_RIGHT}, { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ {KEY_SLEFT}, { 0, 0, 0, 0 }, f_move, { .m = m_prevword } },
-{ {KEY_SRIGHT}, { 0, 0, 0, 0 }, f_move, { .m = m_nextword } },
+{ {KEY_HOME}, { 0, 0, 0, 0 }, f_moveb, { .m = m_bol } },
+{ {KEY_END}, { 0, 0, 0, 0 }, f_moveb, { .m = m_eol } },
+{ {KEY_SHOME}, { 0, 0, 0, 0 }, f_moveb, { .m = m_bof } },
+{ {KEY_SEND}, { 0, 0, 0, 0 }, f_moveb, { .m = m_eof } },
+{ {KEY_PPAGE}, { 0, 0, 0, 0 }, f_moveb, { .m = m_prevscr } },
+{ {KEY_NPAGE}, { 0, 0, 0, 0 }, f_moveb, { .m = m_nextscr } },
+{ {KEY_UP}, { 0, 0, 0, 0 }, f_moveb, { .m = m_prevline } },
+{ {KEY_DOWN}, { 0, 0, 0, 0 }, f_moveb, { .m = m_nextline } },
+{ {KEY_LEFT}, { 0, 0, 0, 0 }, f_moveb, { .m = m_prevchar } },
+{ {KEY_RIGHT}, { 0, 0, 0, 0 }, f_moveb, { .m = m_nextchar } },
+{ {KEY_SLEFT}, { 0, 0, 0, 0 }, f_moveb, { .m = m_prevword } },
+{ {KEY_SRIGHT}, { 0, 0, 0, 0 }, f_moveb, { .m = m_nextword } },
};
static const Key stdkeys[] = {
@@ -84,27 +83,21 @@ static const Key stdkeys[] = {
{ CONTROL('C'), { t_warn,t_mod,0, 0 }, f_toggle, { .i = S_Running } },
{ CONTROL('C'), { t_mod, 0, 0, 0 }, f_toggle, { .i = S_Warned } },
{ CONTROL('C'), { 0, 0, 0, 0 }, f_toggle, { .i = S_Running } },
-{ META('c'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "awk '{ for ( i=1; i <= NF; i++) { $i=tolower($i) ; sub(\".\", substr(toupper($i),1,1) , $i) } printf \"%s\", $0 }'" } },
+{ META('c'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "awk '{ for ( i=1; i <= NF; i++) { $i=tolower($i) ; sub(\".\", substr(toupper($i),1,1) , $i) } print }'" } },
{ CONTROL('D'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ CONTROL('D'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ CONTROL('D'), { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ META('d'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
-{ META('d'), { 0, 0, 0, 0 }, f_select, { .m = m_nextword } },
+{ META('d'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextword } },
{ CONTROL('E'), { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
{ CONTROL('F'), { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
{ META('f'), { 0, 0, 0, 0 }, f_move, { .m = m_nextword } },
{ CONTROL('G'), { t_sel, 0, 0, 0 }, f_select, { .m = m_stay } },
-{ CONTROL('G'), { 0, 0, 0, 0 }, f_toggle, { .i = S_Selecting } },
-{ CONTROL('H'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ CONTROL('H'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ CONTROL('H'), { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
{ CONTROL('I'), { t_sel, t_rw, 0, 0 }, f_pipelines, { .v = "sed 's/^/\\t/'" } },
{ CONTROL('I'), { t_rw, 0, 0, 0 }, f_insert, { .v = "\t" } },
{ CONTROL('J'), { t_rw, 0, 0, 0 }, f_insert, { .v = "\n" } },
{ CONTROL('J'), { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ CONTROL('K'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ CONTROL('K'), { t_eol, t_rw, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ CONTROL('K'), { 0, 0, 0, 0 }, f_select, { .m = m_eol } },
+{ CONTROL('K'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } },
{ CONTROL('L'), { 0, 0, 0, 0 }, f_center, { 0 } },
{ META('l'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "tr [A-Z] [a-z]" } },
{ CONTROL('M'), { t_rw, 0, 0, 0 }, f_insert, { .v = "\n" } },
@@ -120,14 +113,12 @@ static const Key stdkeys[] = {
{ CONTROL('S'), { 0, 0, 0, 0 }, f_spawn, FIND },
{ META('s'), { 0, 0, 0, 0 }, f_findfw, { 0 } },
{ CONTROL('T'), { 0, 0, 0, 0 }, f_pipero , TOCLIP },
-{ CONTROL('U'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ CONTROL('U'), { t_bol, t_rw, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ CONTROL('U'), { 0, 0, 0, 0 }, f_select, { .m = m_bol } },
+{ CONTROL('U'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_bol } },
{ META('u'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "tr [a-z] [A-Z]" } },
{ CONTROL('V'), { 0, 0, 0, 0 }, f_move, { .m = m_prevscr } },
{ META('v'), { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } },
-{ CONTROL('W'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
-{ CONTROL('W'), { 0, 0, 0, 0 }, f_select, { .m = m_prevword } },
+{ CONTROL('W'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevword } },
{ CONTROL('X'), { t_mod, 0, 0, 0 }, f_save, { 0 } },
{ CONTROL('X'), { 0, 0, 0, 0 }, f_toggle, { .i = S_Running } },
{ CONTROL('Y'), { t_rw, 0, 0, 0 }, f_pipe, FROMCLIP },
@@ -138,9 +129,7 @@ static const Key stdkeys[] = {
{ CONTROL('^'), { t_redo,t_rw, 0, 0 }, f_undo, { .i = -1 } },
{ CONTROL('^'), { t_rw, 0, 0, 0 }, f_repeat, { 0 } },
{ CONTROL('_'), { t_undo,t_rw, 0, 0 }, f_undo, { .i = 1 } },
-{ CONTROL('?'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP },
{ CONTROL('?'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ CONTROL('?'), { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
};
/* Commands read at the fifo */
diff --git a/sandy.1 b/sandy.1
@@ -38,7 +38,8 @@ shells (specifically
.IR mksh (1)),
which actually differs a bit from what
.IR emacs (1)
-does. External input is handled using
+does. Text is selected manually with the mouse or keyboard, or automtically
+when you search, pipe, undo or enter new text. External input is handled using
.IR dmenu (1)
if the DISPLAY environment variable is set, read using
.IR sh (1)
@@ -46,8 +47,13 @@ otherwise. Similarly, X11 clipboard interaction occurs through
.IR xsel (1)
if DISPLAY is set, using a hidden file in the HOME directory otherwise.
.SS Cursor movement
-Cursor movement bindings can also be used to select text by pressing Ctrl\-g to
-start a selection (see below)
+Cursor movement bindings are used to move the text insertion point and
+optionally to select text. Special keys (such as arrows, Home/End, Prev/Next)
+move the cursor and cancel any selection; they can be used to browse the text.
+Control keybindings extend or shrink the selection by moving the end at the
+insertion point; they are useful to perform minor changes without taking your
+fingers off the home row. Remember to cancel the selection with Ctrl\-g
+before moving to select a new piece of text.
.TP
.BR Ctrl\-f " or " Right
Move cursor to next char.
@@ -85,7 +91,7 @@ Move cursor to the beginning of the file.
.BR Shift\-End
Move cursor to the end of the file.
.SS Finding and selecting
-Text is searched and selected using POSIX regular expressions
+Text is searched (and selected) using POSIX regular expressions
.TP
.B Ctrl\-s
Prompt for a search regex forward or if there is a selection, repeat search
@@ -105,14 +111,12 @@ Repeat search backwards.
Extend selection to word, line, or full file from current.
.TP
.B Ctrl\-g
-Cancel selection, or start selecting text manually.
+Cancel current selection.
.TP
.B Ctrl\-o
-Move to the opposite size of the selection, usually to extend it.
+Move to the opposite size of the selection, usually to modify it.
.SS Deleting
-If any text is selected, any of these bindings deletes it and, unless Backspace
-or Delete, moves it to the clipboard. Otherwise they behave as per this text.
-In read\-only mode, these bindings select text instead.
+TODO
.TP
.BR Ctrl\-d " or " Delete
Delete next character.
diff --git a/sandy.c b/sandy.c
@@ -119,12 +119,11 @@ enum { /* To use in statusflags */
S_InsEsc = 1<<2,
S_CaseIns = 1<<3,
S_Modified = 1<<4,
- S_Selecting = 1<<5,
- S_DirtyScr = 1<<6,
- S_DirtyDown = 1<<7,
- S_NeedResize = 1<<8,
- S_Warned = 1<<9,
- S_GroupUndo = 1<<10,
+ S_DirtyScr = 1<<5,
+ S_DirtyDown = 1<<6,
+ S_NeedResize = 1<<7,
+ S_Warned = 1<<8,
+ S_GroupUndo = 1<<9,
};
enum { /* To use in Undo.flags */
@@ -183,6 +182,7 @@ static void f_insert(const Arg*);
static void f_line(const Arg*);
static void f_mark(const Arg*);
static void f_move(const Arg*);
+static void f_moveb(const Arg*);
static void f_offset(const Arg*);
static void f_pipe(const Arg*);
static void f_pipelines(const Arg*);
@@ -203,7 +203,7 @@ static void i_addundo(bool, Filepos, Filepos, char*);
static void i_advpos(Filepos *pos, int o);
static void i_calcvlen(Line *l);
static void i_cleanup(int);
-static void i_deltext(Filepos, Filepos);
+static bool i_deltext(Filepos, Filepos);
static void i_die(char *str);
static void i_dirtyrange(Line*, Line*);
static bool i_dotests(bool (*const a[])(void));
@@ -286,10 +286,9 @@ f_delete(const Arg *arg) {
i_sortpos(&pos0, &pos1);
s=i_gettext(pos0, pos1);
i_addundo(FALSE, pos0, pos1, s);
- i_deltext(pos0, pos1);
- fcur=fsel=pos0;
+ if(i_deltext(pos0, pos1)) fcur=pos0;
+ else fcur=fsel=pos0;
statusflags|=S_Modified;
- statusflags&=~S_Selecting;
lastaction=LastDelete;
}
@@ -310,14 +309,9 @@ f_extsel(const Arg *arg) {
break;
case ExtDefault:
default:
- if(statusflags & S_Selecting) {
- if(fsel.o == 0 && fcur.o == fcur.l->len) f_extsel(&(const Arg){.i = ExtAll});
- else f_extsel(&(const Arg){.i = ExtLines});
- } else {
- if(!t_sel()) f_extsel(&(const Arg){.i = ExtWord});
- }
+ if(fsel.o == 0 && fcur.o == fcur.l->len) f_extsel(&(const Arg){.i = ExtAll});
+ else f_extsel(&(const Arg){.i = ExtLines});
}
- statusflags|=S_Selecting;
}
void /* Find arg->v regex backwards, same as last if arg->v == NULL */
@@ -332,21 +326,17 @@ f_findfw(const Arg *arg) {
void /* Insert arg->v at cursor position, deleting the selection if any. Your responsibility: call only if t_rw() */
f_insert(const Arg *arg) {
- bool killsel;
+ Filepos newcur;
- if((killsel=t_sel())) {
- f_delete(&(const Arg) { .m = m_tosel });
- undos->flags^=RedoMore;
+ newcur=i_addtext((char*)arg->v, fcur);
+ if((statusflags & S_GroupUndo) && undos && (undos->flags & UndoIns) && fcur.o == undos->endo && undos->endl == i_lineno(fcur.l))
+ i_addtoundo(newcur, arg->v);
+ else {
+ i_addundo(TRUE, fcur, newcur, strdup((char*)arg->v));
+ fsel=fcur;
}
- fsel=i_addtext((char*)arg->v, fcur);
- if((statusflags & S_GroupUndo) && !killsel && undos && (undos->flags & UndoIns) && fcur.o == undos->endo && undos->endl == i_lineno(fcur.l)) {
- i_addtoundo(fsel, arg->v);
- } else
- i_addundo(TRUE, fcur, fsel, strdup((char*)arg->v));
- if(killsel) undos->flags^=UndoMore;
- fcur=fsel;
+ fcur=newcur;
statusflags|=(S_Modified|S_GroupUndo);
- statusflags&=~S_Selecting;
lastaction=LastInsert;
}
@@ -358,7 +348,6 @@ f_line(const Arg *arg) {
fcur.l=i_lineat(l);
if(fcur.o>fcur.l->len) fcur.o=fcur.l->len;
FIXNEXT(fcur);
- if(! (statusflags & S_Selecting)) fsel=fcur;
}
void /* Set mark at current position */
@@ -366,10 +355,14 @@ f_mark(const Arg *arg) {
fmrk=fcur;
}
-void /* Move cursor or extend/shrink selection as per arg->m */
+void /* Move cursor and extend/shrink selection as per arg->m */
f_move(const Arg *arg) {
fcur=arg->m(fcur);
- if(! (statusflags & S_Selecting)) fsel=fcur;
+}
+
+void /* Move cursor as per arg->m, then copy at selection */
+f_moveb(const Arg *arg) {
+ fsel=fcur=arg->m(fcur);
}
void /* Got to atoi(arg->v) position in the current line */
@@ -377,7 +370,6 @@ f_offset(const Arg *arg) {
fcur.o=atoi(arg->v);
if(fcur.o>fcur.l->len) fcur.o=fcur.l->len;
FIXNEXT(fcur);
- if(! (statusflags & S_Selecting)) fsel=fcur;
}
void /* Pipe selection through arg->v external command. Your responsibility: call only if t_rw() */
@@ -401,13 +393,15 @@ f_pipero(const Arg *arg) {
statusflags|=S_Readonly;
i_pipetext(arg->v);
- statusflags=oldsf&(~S_Selecting);
+ statusflags=oldsf;
lastaction=LastPipeRO;
}
void /* Repeat the last action. Your responsibility: call only if t_rw() */
f_repeat(const Arg *arg) {
Filepos pos;
+ bool was_sel;
+
i_sortpos(&fsel, &fcur);
switch(lastaction) {
case LastDelete:
@@ -415,8 +409,13 @@ f_repeat(const Arg *arg) {
break;
case LastInsert:
if(undos && undos->flags & UndoIns) {
+ if((was_sel=t_sel())) { /* Convenience: delete selection before repeating insertion */
+ f_delete(&(const Arg) { .m = m_tosel });
+ undos->flags^=RedoMore;
+ }
pos=fsel;
- f_insert(&(const Arg){ .v = undos->str });
+ f_insert(&(const Arg){ .v = (was_sel?undos->prev:undos)->str });
+ if(was_sel) undos->flags^=UndoMore;
fsel=pos;
}
break;
@@ -427,14 +426,12 @@ f_repeat(const Arg *arg) {
f_pipero(&(const Arg) { .v = getenv(envs[EnvPipe]) });
break;
}
- statusflags&=~S_Selecting;
}
void /* Save file with arg->v filename, same if NULL. Your responsibility: call only if t_mod() */
f_save(const Arg *arg) {
Undo *u;
- statusflags&=~S_Selecting;
if(arg && arg->v && *((char*)arg->v)) {
free(filename);
filename=strdup((char*)arg->v);
@@ -453,22 +450,17 @@ f_save(const Arg *arg) {
}
}
-void /* Move cursor as per arg->m, without moving the selection point */
+void /* Move cursor as per arg->m, then move the selection point to previous cursor */
f_select(const Arg *arg) {
- Filepos tmppos=fcur; /* for f_select(m_tosel) */
+ Filepos tmppos=fcur; /* for f_select(m_tosel), which reverses the selection */
fcur=arg->m(fcur);
fsel=tmppos;
- if(t_sel())
- statusflags|=S_Selecting;
- else
- statusflags&=~S_Selecting;
}
void /* Spawn (char **)arg->v */
f_spawn(const Arg *arg) {
int pid=-1;
- statusflags&=~S_Selecting;
reset_shell_mode();
if((pid=fork()) == 0) {
setsid();
@@ -493,7 +485,7 @@ void /* Set syntax with name arg->v */
f_syntax(const Arg *arg) {
int i, j;
- statusflags=(statusflags|S_DirtyScr)&~S_Selecting;
+ statusflags|=S_DirtyScr;
for(i=0; i<LENGTH(syntaxes); i++)
if((arg && arg->v) ? !strcmp(arg->v, syntaxes[i].name)
: !regexec(syntax_file_res[i], filename, 1, NULL, 0)) {
@@ -533,7 +525,6 @@ f_undo(const Arg *arg) {
Undo *u;
int n;
- statusflags&=~S_Selecting;
u=(isredo?redos:undos);
fsel.o=u->starto, fsel.l=i_lineat(u->startl);
fcur=fsel;
@@ -701,11 +692,13 @@ i_dirtyrange(Line *l0, Line *l1) {
for(; pos0.l && pos0.l != pos1.l->next; pos0.l=pos0.l->next) pos0.l->dirty=TRUE;
}
-void /* Delete text between pos0 and pos1, which MUST be in order, fcur and fsel integrity is NOT assured after deletion */
+bool /* Delete text between pos0 and pos1, which MUST be in order, fcur integrity is NOT assured after deletion, fsel integrity is returned as a bool */
i_deltext(Filepos pos0, Filepos pos1) {
Line *ldel=NULL;
size_t vlines=1;
+ bool integrity=TRUE;
+ if(pos0.l==fsel.l) integrity=(fsel.o<=pos0.o || (pos0.l==pos1.l && fsel.o>pos1.o));
if(pos0.l==pos1.l) {
vlines=VLINES(pos0.l);
memmove(pos0.l->c+pos0.o, pos0.l->c+pos1.o, (pos0.l->len - pos1.o));
@@ -724,11 +717,13 @@ i_deltext(Filepos pos0, Filepos pos1) {
pos0.l->next=pos0.l->next->next;
if(scrline == ldel) scrline=ldel->prev;
if(lstline == ldel) lstline=ldel->prev;
+ if(fsel.l == ldel) integrity=FALSE;
free(ldel->c);
free(ldel);
}
}
if(ldel!=NULL || vlines != VLINES(pos0.l)) statusflags|=S_DirtyDown;
+ return integrity;
}
bool /* test an array of t_ functions */
@@ -755,7 +750,7 @@ i_edit(void) {
if(fsel.l != oldsel.l) i_dirtyrange(oldsel.l, fsel.l);
else if(fsel.o != oldsel.o) fsel.l->dirty=TRUE;
if(fcur.l != oldcur.l) i_dirtyrange(oldcur.l, fcur.l);
- else if(fcur.o != oldcur.o && t_sel()) fcur.l->dirty=TRUE;
+ else if(fcur.o != oldcur.o) fcur.l->dirty=TRUE;
oldsel=fsel, oldcur=fcur;
i_update();
@@ -942,7 +937,6 @@ i_pipetext(const char *cmd) {
Filepos auxp;
fd_set fdI, fdO;
- statusflags&=~S_Selecting;
if(!cmd || cmd[0] == '\0') return;
setenv(envs[EnvPipe], cmd, 1);
if (pipe(pin) == -1) return;
@@ -1138,7 +1132,6 @@ i_scrtofpos(int x, int y) {
bool /* Update find_res[sel_re] and sel_re. Return TRUE if find term is a valid RE or NULL */
i_setfindterm(char *find_term) {
- statusflags&=~S_Selecting;
if(find_term) { /* Modify find term; use NULL to repeat search */
if(!regcomp(find_res[sel_re^1], find_term, REG_EXTENDED|REG_NEWLINE|(statusflags&S_CaseIns?REG_ICASE:0))) {
sel_re^=1;
@@ -1415,13 +1408,12 @@ i_update(void) {
else {
statusflags&=~S_Warned; /* Reset warning */
snprintf(buf, 4, "%ld%%", (100*ncur)/nlst);
- snprintf(title, BUFSIZ, "%s [%s]%s%s%s%s %ld,%d %s",
+ snprintf(title, BUFSIZ, "%s [%s]%s%s%s %ld,%d %s",
(filename == NULL?"<No file>":filename),
(syntx>=0 ? syntaxes[syntx].name : "none"),
(t_mod()?"[+]":""),
(!t_rw()?"[RO]":""),
(statusflags&S_CaseIns?"[icase]":""),
- (statusflags&S_Selecting?"[SEL]":""),
ncur, (int)fcur.o,
(scrline==fstline?
(nlst<lines3?"All":"Top"):