Index: fmtext.c
===================================================================
--- fmtext.c	(revision 801b7ac63b962640debbcfd422cb9a60da5fea31)
+++ fmtext.c	(revision a387d12ee4e32845e2a021fb4ecd3cf11d6c18a8)
@@ -9,8 +9,10 @@
 {
   f->textlen=0;
-  f->textbuff=owl_strdup("");
+  f->bufflen=5;
+  f->textbuff=owl_malloc(5);
   f->fmbuff=owl_malloc(5);
   f->fgcolorbuff=owl_malloc(5);
   f->bgcolorbuff=owl_malloc(5);
+  f->textbuff[0]=0;
   f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
   f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
@@ -18,4 +20,15 @@
 }
 
+/* Clear the data from an fmtext, but don't deallocate memory. This
+   fmtext can then be appended to again. */
+void owl_fmtext_clear(owl_fmtext *f)
+{
+    f->textlen = 0;
+    f->textbuff[0] = 0;
+    f->fmbuff[0]=OWL_FMTEXT_ATTR_NONE;
+    f->fgcolorbuff[0]=OWL_COLOR_DEFAULT;
+    f->bgcolorbuff[0]=OWL_COLOR_DEFAULT;
+}
+
 /* Internal function.  Set the attribute 'attr' from index 'first' to
  * index 'last'
@@ -59,4 +72,15 @@
 }
 
+void _owl_fmtext_realloc(owl_fmtext *f, int newlen) /*noproto*/
+{
+    if(newlen + 1 > f->bufflen) {
+      f->textbuff=owl_realloc(f->textbuff, newlen+1);
+      f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
+      f->fgcolorbuff=owl_realloc(f->fgcolorbuff, newlen+1);
+      f->bgcolorbuff=owl_realloc(f->bgcolorbuff, newlen+1);
+      f->bufflen = newlen+1;
+  }
+}
+
 /* append text to the end of 'f' with attribute 'attr' and color
  * 'color'
@@ -65,11 +89,7 @@
 {
   int newlen;
-
   newlen=strlen(f->textbuff)+strlen(text);
-  f->textbuff=owl_realloc(f->textbuff, newlen+2);
-  f->fmbuff=owl_realloc(f->fmbuff, newlen+2);
-  f->fgcolorbuff=owl_realloc(f->fgcolorbuff, newlen+2);
-  f->bgcolorbuff=owl_realloc(f->bgcolorbuff, newlen+2);
-
+  _owl_fmtext_realloc(f, newlen);
+  
   strcat(f->textbuff, text);
   _owl_fmtext_set_attr(f, attr, f->textlen, newlen);
@@ -154,8 +174,5 @@
 
   newlen=strlen(f->textbuff)+(stop-start+1);
-  f->textbuff=owl_realloc(f->textbuff, newlen+1);
-  f->fmbuff=owl_realloc(f->fmbuff, newlen+1);
-  f->fgcolorbuff=owl_realloc(f->fgcolorbuff, newlen+1);
-  f->bgcolorbuff=owl_realloc(f->bgcolorbuff, newlen+1);
+  _owl_fmtext_realloc(f, newlen);
 
   strncat(f->textbuff, in->textbuff+start, stop-start+1);
Index: global.c
===================================================================
--- global.c	(revision 8e401cae31daac6032012ce1dd4d2e601424b53e)
+++ global.c	(revision a387d12ee4e32845e2a021fb4ecd3cf11d6c18a8)
@@ -108,4 +108,6 @@
 
   owl_obarray_init(&(g->obarray));
+
+  owl_message_init_fmtext_cache();
 }
 
Index: message.c
===================================================================
--- message.c	(revision 963542b4198cbb7f26529758cf647ac4cfdbcb74)
+++ message.c	(revision a387d12ee4e32845e2a021fb4ecd3cf11d6c18a8)
@@ -13,4 +13,28 @@
 static const char fileIdent[] = "$Id$";
 
+static owl_fmtext_cache fmtext_cache[OWL_FMTEXT_CACHE_SIZE];
+static owl_fmtext_cache * fmtext_cache_next = fmtext_cache;
+
+void owl_message_init_fmtext_cache ()
+{
+    int i;
+    for(i = 0; i < OWL_FMTEXT_CACHE_SIZE; i++) {
+        owl_fmtext_init_null(&(fmtext_cache[i].fmtext));
+        fmtext_cache[i].message = NULL;
+    }
+}
+
+owl_fmtext_cache * owl_message_next_fmtext() /*noproto*/
+{
+    if(fmtext_cache_next->message != NULL) {
+        owl_message_invalidate_format(fmtext_cache_next->message);
+    }
+    owl_fmtext_cache * f = fmtext_cache_next;
+    fmtext_cache_next++;
+    if(fmtext_cache_next - fmtext_cache == OWL_FMTEXT_CACHE_SIZE)
+        fmtext_cache_next = fmtext_cache;
+    return f;
+}
+
 void owl_message_init(owl_message *m)
 {
@@ -19,5 +43,4 @@
   m->delete=0;
   m->zwriteline=NULL;
-  m->invalid_format=1;
 
   owl_message_set_hostname(m, "");
@@ -29,6 +52,5 @@
   m->timestr[strlen(m->timestr)-1]='\0';
 
-  /* initialize the fmtext */
-  owl_fmtext_init_null(&(m->fmtext));
+  m->fmtext = NULL;
 }
 
@@ -106,5 +128,9 @@
 void owl_message_invalidate_format(owl_message *m)
 {
-  m->invalid_format=1;
+  if(m->fmtext) {
+    m->fmtext->message = NULL;
+    owl_fmtext_clear(&(m->fmtext->fmtext));
+    m->fmtext=NULL;
+  }
 }
 
@@ -112,5 +138,5 @@
 {
   owl_message_format(m);
-  return(&(m->fmtext));
+  return(&(m->fmtext->fmtext));
 }
 
@@ -120,13 +146,12 @@
   owl_view *v;
 
-  if (m->invalid_format) {
+  if (!m->fmtext) {
+    m->fmtext = owl_message_next_fmtext();
+    m->fmtext->message = m;
     /* for now we assume there's just the one view and use that style */
     v=owl_global_get_current_view(&g);
     s=owl_view_get_style(v);
 
-    owl_fmtext_free(&(m->fmtext));
-    owl_fmtext_init_null(&(m->fmtext));
-    owl_style_get_formattext(s, &(m->fmtext), m);
-    m->invalid_format=0;
+    owl_style_get_formattext(s, &(m->fmtext->fmtext), m);
   }
 }
@@ -392,5 +417,5 @@
 char *owl_message_get_text(owl_message *m)
 {
-  return(owl_fmtext_get_text(&(m->fmtext)));
+  return(owl_fmtext_get_text(&(m->fmtext->fmtext)));
 }
 
@@ -437,5 +462,5 @@
   if (m == NULL) return(0);
   owl_message_format(m);
-  return(owl_fmtext_num_lines(&(m->fmtext)));
+  return(owl_fmtext_num_lines(&(m->fmtext->fmtext)));
 }
 
@@ -504,5 +529,5 @@
   owl_fmtext_init_null(&b);
   
-  owl_fmtext_truncate_lines(&(m->fmtext), aline, bline-aline+1, &a);
+  owl_fmtext_truncate_lines(&(m->fmtext->fmtext), aline, bline-aline+1, &a);
   owl_fmtext_truncate_cols(&a, acol, bcol, &b);
   if (fgcolor!=OWL_COLOR_DEFAULT) {
@@ -698,5 +723,5 @@
   owl_message_format(m); /* is this necessary? */
   
-  return (owl_fmtext_search(&(m->fmtext), string));
+  return (owl_fmtext_search(&(m->fmtext->fmtext), string));
 }
 
@@ -989,4 +1014,4 @@
   owl_list_free_simple(&(m->attributes));
  
-  owl_fmtext_free(&(m->fmtext));
-}
+  owl_message_invalidate_format(m);
+}
Index: owl.h
===================================================================
--- owl.h	(revision d08162aefc38f762a74ce2318c26d3a31372170c)
+++ owl.h	(revision a387d12ee4e32845e2a021fb4ecd3cf11d6c18a8)
@@ -249,4 +249,5 @@
 typedef struct _owl_fmtext {
   int textlen;
+  int bufflen;
   char *textbuff;
   char *fmbuff;
@@ -329,4 +330,6 @@
 } owl_pair;
 
+struct _owl_fmtext_cache;
+
 typedef struct _owl_message {
   int id;
@@ -335,6 +338,5 @@
   ZNotice_t notice;
 #endif
-  owl_fmtext fmtext;              /* this is now only a CACHED copy */
-  int invalid_format;             /* indicates whether fmtext needs to be regenerated */
+  struct _owl_fmtext_cache * fmtext;
   int delete;
   char *hostname;
@@ -344,4 +346,12 @@
   char *zwriteline;
 } owl_message;
+
+#define OWL_FMTEXT_CACHE_SIZE 1000
+/* We cache the saved fmtexts for the last bunch of messages we
+   rendered */
+typedef struct _owl_fmtext_cache {
+    owl_message * message;
+    owl_fmtext fmtext;
+} owl_fmtext_cache;
 
 typedef struct _owl_style {
