commit b55e85b730136a073724c9f149ebe174ce27eefa
parent de8e7863fbf29ee41290753a3657f96a675e4f23
Author: Rafael Garcia <rafael.garcia.gallego@gmail.com>
Date:   Wed, 10 Aug 2011 03:33:07 +0200
Autoindent is back (start sandy with -a), now using a awk one liner rather than hardcode in C; can also be set/unset. Helper functions moved to the config file for now.
Diffstat:
5 files changed, 45 insertions(+), 19 deletions(-)
diff --git a/README b/README
@@ -28,6 +28,7 @@ Use the following syntax:
 	sandy [-r] [-S | -s SYNTAX] [-t TABSTOP] [File]
 
 Where:
+-a starts with autoindent
 -r opens the file read-only
 -S use no syntax colors at all.
 -s SYNTAX  lets you specify the syntax colors for this file
diff --git a/TODO b/TODO
@@ -2,7 +2,6 @@ In no particular order, at sandy.c:
 - Update manpage
 - Create m_*vline
 - Bracket matching?
-- Autoindenting?
 - Number modifier?
 - Smart end? is it really needed?
 - BUG: high CPU usage on continuous resize
diff --git a/config.def.h b/config.def.h
@@ -20,6 +20,11 @@ static const char   spcstr[2]  = { ' ', 0 };
 static const char   nlstr[1]   = { 0 };
 #endif
 
+/* Helper config functions, not used in main code */
+static void f_moveb(const Arg*);
+static void f_pipeb(const Arg*);
+static void f_pipelines(const Arg*);
+
 /* Args to f_spawn */
 #define PROMPT(prompt, default, cmd) { .v = (const char *[]){ "/bin/sh", "-c", \
 	"dmenu -v >/dev/null 2>&1 || DISPLAY=\"\";"\
@@ -99,12 +104,14 @@ static const Key stdkeys[] = {
 { .keyv.c = CONTROL('H'), { t_sel, t_rw, 0,   0 },  f_delete,    { .m = m_tosel } },
 { .keyv.c = CONTROL('H'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_prevchar } },
 { .keyv.c = CONTROL('I'), { t_rw,  0,    0,   0 },  f_insert,    { .v = "\t" } },
+{ .keyv.c = CONTROL('J'), { t_rw,  t_ai, 0,   0 },  f_pipeb,     { .v = "awk 'BEGIN{ l=\"\\n\" } ; { if(match($0, \"^[\t ]+[^\t ]\")) l=substr($0, RSTART, RLENGTH-1); else l=\"\";  if(FNR==NR && $0 ~ /^[\t ]+$/) print \"\" ; else print }; END{ ORS=\"\"; print l }'" } } ,
 { .keyv.c = CONTROL('J'), { t_rw,  0,    0,   0 },  f_insert,    { .v = "\n" } },
 { .keyv.c = CONTROL('J'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline } },
 { .keyv.c = CONTROL('K'), { t_eol, t_rw, 0,   0 },  f_delete,    { .m = m_nextchar } },
 { .keyv.c = CONTROL('K'), { t_rw,  0,    0,   0 },  f_delete,    { .m = m_eol } },
 { .keyv.c = CONTROL('L'), { 0,     0,    0,   0 },  f_center,    { 0 } },
 { .keyv.c = META('l'),    { t_sel, t_rw, 0,   0 },  f_pipe,      { .v = "tr [A-Z] [a-z]" } },
+{ .keyv.c = CONTROL('M'), { t_rw,  t_ai, 0,   0 },  f_pipeb,     { .v = "awk 'BEGIN{ l=\"\\n\" } ; { if(match($0, \"^[\t ]+[^\t ]\")) l=substr($0, RSTART, RLENGTH-1); else l=\"\";  if(FNR==NR && $0 ~ /^[\t ]+$/) print \"\" ; else print }; END{ ORS=\"\"; print l }'" } } ,
 { .keyv.c = CONTROL('M'), { t_rw,  0,    0,   0 },  f_insert,    { .v = "\n" } },
 { .keyv.c = CONTROL('M'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline } },
 { .keyv.c = CONTROL('N'), { 0,     0,    0,   0 },  f_move,      { .m = m_nextline } },
@@ -156,6 +163,7 @@ static const Command cmds[] = { /* if(arg == 0) arg.v=regex_match */
 {"^offset (.*)$",   { 0,     0,    0 }, f_offset, { 0 } },
 {"^set icase$",     { 0,     0,    0 }, f_toggle, { .i = S_CaseIns } },
 {"^set ro$",        { 0,     0,    0 }, f_toggle, { .i = S_Readonly } },
+{"^set ai$",        { 0,     0,    0 }, f_toggle, { .i = S_AutoIndent } },
 {"^q$",             { t_mod, 0,    0 }, f_toggle, { .i = S_Warned } },
 {"^q$",             { 0,     0,    0 }, f_toggle, { .i = S_Running } },
 {"^q!$",            { 0,     0,    0 }, f_toggle, { .i = S_Running } },
@@ -291,3 +299,24 @@ static const short  bgcolors[LastBG] = {
 	[SelBG] = COLOR_YELLOW,
 };
 
+/* Helper config functions implementation */
+void /* Move cursor as per arg->m, then cancel selection */
+f_moveb(const Arg *arg) {
+	fsel=fcur=arg->m(fcur);
+}
+
+void /* Pipe selection from bol, then cancel selection */
+f_pipeb(const Arg *arg) {
+	i_sortpos(&fsel, &fcur);
+	fsel.o=0;
+	f_pipe(arg);
+	fsel=fcur;
+}
+
+void /* Pipe full lines including the selection */
+f_pipelines(const Arg *arg) {
+	f_extsel(&(const Arg){ .i = ExtLines });
+	i_pipetext(arg->v);
+	statusflags|=S_Modified;
+	lastaction=LastPipe;
+}
diff --git a/sandy.1 b/sandy.1
@@ -3,7 +3,7 @@
 sandy \- simple ncurses text editor
 .SH SYNOPSIS
 .B sandy
-.RB [ \-hruS ]
+.RB [ \-ahruS ]
 .RB [ \-t
 .IR tabstop ]
 .RB [ \-s
@@ -16,6 +16,9 @@ commands.  A small degree of external control can be achieved by writing to a
 named pipe.
 .SH OPTIONS
 .TP
+.B \-a
+Autoindents text while editing.
+.TP
 .B \-h
 Prints usage information to stderr, then exits.
 .TP
diff --git a/sandy.c b/sandy.c
@@ -127,6 +127,7 @@ enum { /* To use in statusflags */
 	S_NeedResize = 1<<7,
 	S_Warned     = 1<<8,
 	S_GroupUndo  = 1<<9,
+	S_AutoIndent = 1<<10,
 };
 
 enum { /* To use in Undo.flags */
@@ -185,10 +186,8 @@ 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*);
 static void f_pipero(const Arg*);
 static void f_repeat(const Arg*);
 static void f_save(const Arg*);
@@ -233,6 +232,7 @@ static void           i_usage(void);
 static bool           i_writefile(char*);
 
 /* t_* functions to know whether to process an action or keybinding */
+static bool t_ai(void);
 static bool t_bol(void);
 static bool t_eol(void);
 static bool t_mod(void);
@@ -363,11 +363,6 @@ f_move(const Arg *arg) {
 	fcur=arg->m(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 */
 f_offset(const Arg *arg) {
 	fcur.o=atoi(arg->v);
@@ -382,14 +377,6 @@ f_pipe(const Arg *arg) {
 	lastaction=LastPipe;
 }
 
-void /* Pipe full lines including the selection through arg->v external command. Your responsibility: call only if t_rw() */
-f_pipelines(const Arg *arg) {
-	f_extsel(&(const Arg){ .i = ExtLines });
-	i_pipetext(arg->v);
-	statusflags|=S_Modified;
-	lastaction=LastPipe;
-}
-
 void /* Pipe selection through arg->v external command but do not update text on screen */
 f_pipero(const Arg *arg) {
 	char oldsf=statusflags;
@@ -1405,12 +1392,13 @@ i_update(void) {
 	else {
 		statusflags&=~S_Warned; /* Reset warning */
 		snprintf(buf, 4, "%ld%%", (100*ncur)/nlst);
-		snprintf(title, BUFSIZ, "%s [%s]%s%s%s %ld,%d  %s",
+		snprintf(title, BUFSIZ, "%s [%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_AutoIndent?"[ai]":""),
 			ncur, (int)fcur.o,
 			(scrline==fstline?
 				(nlst<lines3?"All":"Top"):
@@ -1439,7 +1427,7 @@ i_update(void) {
 void /* Print help, die */
 i_usage(void) {
 	fputs("sandy - simple editor\n", stderr);
-	i_die("usage: sandy [-r] [-u] [-t TABSTOP] [-s SYNTAX] [file | -]\n");
+	i_die("usage: sandy [-a] [-r] [-u] [-t TABSTOP] [-s SYNTAX] [file | -]\n");
 }
 
 bool /* Write buffer to disk */
@@ -1625,6 +1613,10 @@ m_tosel(Filepos pos) {
 
 /* T_* FUNCTIONS
 	Used to test for conditions, take no arguments and return bool. */
+bool /* TRUE is autoindent is on */
+t_ai(void) {
+	return (statusflags & S_AutoIndent);
+}
 
 bool /* TRUE at the beginning of line */
 t_bol(void) {
@@ -1678,6 +1670,8 @@ main(int argc, char **argv){
 	for(i = 1; i < argc && argv[i][0] == '-' && argv[i][1] != '\0'; i++) {
 		if(!strcmp(argv[i], "-r")) {
 			statusflags|=S_Readonly;
+		} else if(!strcmp(argv[i], "-a")) {
+			statusflags|=S_AutoIndent;
 		} else if(!strcmp(argv[i], "-t")) {
 			if(++i < argc) {
 				tabstop=atoi(argv[i]);