diff --git a/manual/luatex-callbacks.tex b/manual/luatex-callbacks.tex
index ddeeb05b1b49916057391734bee115ef39881a93..62a37c5bce1b1b3e46ee08cecb6314afc36bf09c 100644
--- a/manual/luatex-callbacks.tex
+++ b/manual/luatex-callbacks.tex
@@ -852,6 +852,17 @@ end
 This callback replaces the code that prints \LUATEX's when a file is closed like
 the \type {)} for regular files.
 
+\subsection{\type {call_edit}}
+
+\startfunctioncall
+function(filename,linenumber)
+end
+\stopfunctioncall
+
+This callback replaces the call to an external editor when \quote{E} is pressed 
+in reply to an error message. Processing will end immediately after the callback
+returns control to the main program.
+
 \section{PDF-related callbacks}
 
 \subsection{\type {finish_pdffile}}
diff --git a/manual/luatex.pdf b/manual/luatex.pdf
index cdc2b22a5a2db413a496e9f804898555aa8fa215..a757b4395a0ace0633a81203785f8a888f0c633b 100644
Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ
diff --git a/source/texk/web2c/luatexdir/lua/lcallbacklib.c b/source/texk/web2c/luatexdir/lua/lcallbacklib.c
index 6bdaca016fd3215f44cadf7c9dc75b1b477fa804..812ad437b1ae50d79571da075c80d55f1cc17290 100644
--- a/source/texk/web2c/luatexdir/lua/lcallbacklib.c
+++ b/source/texk/web2c/luatexdir/lua/lcallbacklib.c
@@ -72,6 +72,7 @@ static const char *const callbacknames[] = {
     "process_rule",
     "insert_local_par",
     "contribute_filter",
+    "call_edit",
     NULL
 };
 
diff --git a/source/texk/web2c/luatexdir/luatex.c b/source/texk/web2c/luatexdir/luatex.c
index 7e06c9388857cf10c466010c373f1ecec161b9e4..5d91ccbbbc49006002c0f14b441ab23b05a132f8 100644
--- a/source/texk/web2c/luatexdir/luatex.c
+++ b/source/texk/web2c/luatexdir/luatex.c
@@ -61,10 +61,6 @@ const char *engine_name = my_name;     /* the name of this engine */
 #include <signal.h>             /* Catch interrupts.  */
 
 
-/* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
-   Unfortunately there's no way to get the banner into this code, so
-   just repeat the text.  */
-#define edit_var "TEXEDIT"
 
 /* Shell escape.
 
diff --git a/source/texk/web2c/luatexdir/luatex_svnversion.h b/source/texk/web2c/luatexdir/luatex_svnversion.h
index bef33fd6cdaf731b952407c2dbd829dc4602d29a..4e8e09752805256625103566cf71be7bc0c6f133 100644
--- a/source/texk/web2c/luatexdir/luatex_svnversion.h
+++ b/source/texk/web2c/luatexdir/luatex_svnversion.h
@@ -1 +1 @@
-#define luatex_svn_revision -1
+#define luatex_svn_revision 6128
diff --git a/source/texk/web2c/luatexdir/luatexcallbackids.h b/source/texk/web2c/luatexdir/luatexcallbackids.h
index 4a02f05d058e785b932f610482364a3f947dfa83..cfd865b896a84d9a9e73c1ea339c3b9476850731 100644
--- a/source/texk/web2c/luatexdir/luatexcallbackids.h
+++ b/source/texk/web2c/luatexdir/luatexcallbackids.h
@@ -66,6 +66,7 @@ typedef enum {
     process_rule_callback,
     insert_local_par_callback,
     contribute_filter_callback,
+    call_edit_callback,
     total_callbacks
 } callback_callback_types;
 
diff --git a/source/texk/web2c/luatexdir/tex/errors.w b/source/texk/web2c/luatexdir/tex/errors.w
index 1af16ec58ef41ea8092cf103672927a8b4b1f6c8..5dfdc8d6a8c1ca46d77e1b82dc9148f6d563d471 100644
--- a/source/texk/web2c/luatexdir/tex/errors.w
+++ b/source/texk/web2c/luatexdir/tex/errors.w
@@ -24,6 +24,7 @@ luafflib.c
 
 @ @c
 #include "ptexlib.h"
+#define edit_var "TEXEDIT"
 
 @ When something anomalous is detected, \TeX\ typically does something like this:
 $$\vbox{\halign{#\hfil\cr
@@ -232,6 +233,147 @@ void jump_out(void)
     close_files_and_terminate();
     do_final_end();
 }
+@ Here is the function that calls the editor, if one is defined. This
+is loosely based on a similar function in kpathsea, but the calling
+convention is quite different.
+
+@c
+static const_string edit_value = EDITOR;
+
+__attribute__ ((noreturn))
+static void luatex_calledit (int baseptr, int linenumber)
+{
+  char *temp, *command, *fullcmd;
+  char c;
+  int sdone, ddone, i;
+  char *filename = makecstring(input_stack[base_ptr].name_field);
+  int fnlength = strlen(filename);
+
+#ifdef WIN32
+  char *fp, *ffp, *env, editorname[256], buffer[256];
+  int cnt = 0;
+  int dontchange = 0;
+#endif
+
+  sdone = ddone = 0;
+
+  /* Close any open input files, since we're going to kill the job.  */
+  close_files_and_terminate();
+
+  /* Replace the default with the value of the appropriate environment
+     variable or config file value, if it's set.  */
+  temp = kpse_var_value (edit_var);
+  if (temp != NULL)
+    edit_value = temp;
+
+  /* Construct the command string.  The `11' is the maximum length an
+     integer might be.  */
+  command = xmalloc (strlen (edit_value) + fnlength + 11);
+
+  /* So we can construct it as we go.  */
+  temp = command;
+
+#ifdef WIN32
+  fp = editorname;
+  if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
+        && IS_DIR_SEP (*(edit_value + 2)))
+      || (*edit_value == '"' && isalpha(*(edit_value + 1))
+        && *(edit_value + 2) == ':'
+        && IS_DIR_SEP (*(edit_value + 3)))
+     )
+    dontchange = 1;
+#endif
+
+  while ((c = *edit_value++) != 0)
+    {
+      if (c == '%')
+        {
+          switch (c = *edit_value++)
+            {
+            case 'd':
+              if (ddone)
+                FATAL1 ("call_edit: `%%d' appears twice in editor command: `%s'", edit_value);
+              sprintf (temp, "%ld", (long int)linenumber);
+              while (*temp != '\0')
+                temp++;
+              ddone = 1;
+              break;
+
+            case 's':
+              if (sdone)
+                FATAL1 ("call_edit: `%%s' appears twice in editor command: `%s'", edit_value);
+              for (i =0; i < fnlength; i++)
+                *temp++ = filename[i];
+              sdone = 1;
+              break;
+
+            case '\0':
+              *temp++ = '%';
+              /* Back up to the null to force termination.  */
+              edit_value--;
+              break;
+
+            default:
+              *temp++ = '%';
+              *temp++ = c;
+              break;
+            }
+        }
+      else {
+#ifdef WIN32
+        if (dontchange)
+          *temp++ = c;
+        else { if(Isspace(c) && cnt == 0) {
+            cnt++;
+            temp = command;
+            *temp++ = c;
+            *fp = '\0';
+          } else if(!Isspace(c) && cnt == 0) {
+            *fp++ = c;
+          } else {
+            *temp++ = c;
+          }
+        }
+#else
+        *temp++ = c;
+#endif
+      }
+    }
+
+  *temp = 0;
+
+#ifdef WIN32
+  if (dontchange == 0) {
+    if(editorname[0] == '.' ||
+       editorname[0] == '/' ||
+       editorname[0] == '\\') {
+      fprintf(stderr, "%s is not allowed to execute.\n", editorname);
+      do_final_end();
+    }
+    env = (char *)getenv("PATH");
+    if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
+      if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
+        fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
+        do_final_end();
+      }
+    }
+    fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
+    strcpy(fullcmd, "\"");
+    strcat(fullcmd, buffer);
+    strcat(fullcmd, "\"");
+    strcat(fullcmd, command);
+  } else
+#endif
+  fullcmd = command;
+
+  /* Execute the command.  */
+  if (system (fullcmd) != 0)
+    fprintf (stderr, "! Trouble executing `%s'.\n", command);
+
+  /* Quit, since we found an error.  */
+  do_final_end ();
+}
+
 
 @ @c
 void error(void)
@@ -325,12 +467,18 @@ void error(void)
 #endif
             case 'E':
                 if (base_ptr > 0) {
-                    tprint_nl("You want to edit file ");
-                    print(input_stack[base_ptr].name_field);
-                    tprint(" at line ");
-                    print_int(line);
-                    interaction = scroll_mode;
-                    jump_out();
+                    int callback_id = callback_defined(call_edit_callback);
+                    if (callback_id>0) {
+                        (void)run_callback(callback_id, "Sd->", makecstring(input_stack[base_ptr].name_field), line);
+                        jump_out(); /* should not be reached */
+                    } else {
+                        tprint_nl("You want to edit file ");
+                        print(input_stack[base_ptr].name_field);
+                        tprint(" at line ");
+                        print_int(line);
+                        interaction = scroll_mode;
+                        luatex_calledit(base_ptr, line);
+                    }
                 }
                 break;
             case 'H':