[PATCH v2] Cache the expanded prompt for editline

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Previously, the prompt would be expanded every time editline called the
getprompt callback. I think the code may have been written assuming that
editline only calls getprompt once per prompt, but it may actually call
it many times, for instance every time you type backspace. This results
not only in slower editing from expanding complex prompts repeatedly, it
also consumes more and more stack memory each time getprompt is called.
This can be seen by setting PS1 to some command substitution, typing
many characters at the prompt, then holding backspace and observing
memory usage. Thankfully all this stack memory is freed between prompts
by the stackmark calls around el_gets.

This change causes prompt expansion to always happen in the setprompt
call, as it would when editline is disabled, and a cached copy of the
prompt is saved for getprompt to return every time editline calls it.
Since getprompt is no longer doing expansion, the stackmark calls
surrounding el_gets can be removed.
---

v2: Missed adding breaks when replacing returns with assignments.

 src/input.c  |  6 +----
 src/parser.c | 66 ++++++++++++++++++++++++++++------------------------
 2 files changed, 37 insertions(+), 35 deletions(-)

diff --git a/src/input.c b/src/input.c
index 17544e7..4167bd1 100644
--- a/src/input.c
+++ b/src/input.c
@@ -152,12 +152,8 @@ retry:
 		static const char *rl_cp;
 		static int el_len;
 
-		if (rl_cp == NULL) {
-			struct stackmark smark;
-			pushstackmark(&smark, stackblocksize());
+		if (rl_cp == NULL)
 			rl_cp = el_gets(el, &el_len);
-			popstackmark(&smark);
-		}
 		if (rl_cp == NULL)
 			nr = 0;
 		else {
diff --git a/src/parser.c b/src/parser.c
index a47022e..270a01d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -107,6 +107,9 @@ struct heredoc *heredoc;
 int quoteflag;			/* set if (part of) last token was quoted */
 
 
+static char *promptcache;
+
+
 STATIC union node *list(int);
 STATIC union node *andor(void);
 STATIC union node *pipeline(void);
@@ -1541,27 +1544,6 @@ synerror(const char *msg)
 	/* NOTREACHED */
 }
 
-STATIC void
-setprompt(int which)
-{
-	struct stackmark smark;
-	int show;
-
-	needprompt = 0;
-	whichprompt = which;
-
-#ifdef SMALL
-	show = 1;
-#else
-	show = !el;
-#endif
-	if (show) {
-		pushstackmark(&smark, stackblocksize());
-		out2str(getprompt(NULL));
-		popstackmark(&smark);
-	}
-}
-
 const char *
 expandstr(const char *ps)
 {
@@ -1611,22 +1593,25 @@ out:
 	return result;
 }
 
-/*
- * called by editline -- any expansions to the prompt
- *    should be added here.
- */
-const char *
-getprompt(void *unused)
+STATIC void
+setprompt(int which)
 {
+	struct stackmark smark;
 	const char *prompt;
+	int show;
+
+	needprompt = 0;
+	whichprompt = which;
 
 	switch (whichprompt) {
 	default:
 #ifdef DEBUG
-		return "<internal prompt error>";
+		prompt = "<internal prompt error>";
+		break;
 #endif
 	case 0:
-		return nullstr;
+		prompt = nullstr;
+		break;
 	case 1:
 		prompt = ps1val();
 		break;
@@ -1635,7 +1620,28 @@ getprompt(void *unused)
 		break;
 	}
 
-	return expandstr(prompt);
+#ifdef SMALL
+	show = 1;
+#else
+	show = !el;
+#endif
+	pushstackmark(&smark, stackblocksize());
+	if (show) {
+		out2str(expandstr(prompt));
+	} else {
+		free(promptcache);
+		promptcache = savestr(expandstr(prompt));
+	}
+	popstackmark(&smark);
+}
+
+/*
+ * called by editline -- return the cached prompt expansion.
+ */
+const char *
+getprompt(void *unused)
+{
+	return promptcache;
 }
 
 const char *const *
-- 
2.29.2




[Index of Archives]     [LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

  Powered by Linux