diff --git a/manual/luatex-languages.tex b/manual/luatex-languages.tex
index 990a8dcc038d568ccf74fe8cc6686ab5bd8cfc38..54a7b390d5ffac254c3eba712a693703ba6be912 100644
--- a/manual/luatex-languages.tex
+++ b/manual/luatex-languages.tex
@@ -263,7 +263,82 @@ The word end is determined as follows:
 \NC adjust    \NC when hyphenationbounds 2 or 3 \NC \NR
 \stoptabulate
 
-(Future versions of \LUATEX\ might provide more granularity.)
+% (Future versions of \LUATEX\ might provide more granularity.)
+
+In traditional \TEX\ ligature building and hyphenation are interwoven with the
+line break mechanism. In \LUATEX\ these phases are isolated. As a consequence we
+deal differently with (a sequence of) explicit hyphens. We already have added
+some control over aspects of the hyphenation and yet another one concerns
+automatic hyphens (e.g.\ \type {-} characters in the input).
+
+When \type {\automatichyphenmode} has a value of 0, a hyphen will be turned into
+an automatic discretionary. The snippets before and after it will not be
+hyphenated. A side effect is that a leading hyphen can lead to a split but one
+will seldom run into that situation. Setting a pre and post character makes this
+more prominent. A value of 1 will prevent this side effect and a value of 2 will
+not turn the hyphen into a discretionary. Experiments with other options, like
+permitting hyphenation, of the words on both sides were discarded.
+
+\startbuffer[a]
+before-after \par
+before--after \par
+before---after \par
+\stopbuffer
+
+\startbuffer[b]
+-before \par
+after- \par
+--before \par
+after-- \par
+---before \par
+after--- \par
+\stopbuffer
+
+\startbuffer[c]
+before-after \par
+before--after \par
+before---after \par
+\stopbuffer
+
+We show three samples:
+
+Input A: \typebuffer[a]
+Input B: \typebuffer[b]
+Input C: \typebuffer[c]
+
+\startbuffer[demo]
+\startcombination[nx=4,ny=3,location=top]
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[a]}} {A~0~6em}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[a]}} {A~0~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone   \hsize2pt \getbuffer[a]}} {A~1~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo   \hsize2pt \getbuffer[a]}} {A~2~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[b]}} {B~0~6em}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[b]}} {B~0~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone   \hsize2pt \getbuffer[b]}} {B~1~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo   \hsize2pt \getbuffer[b]}} {B~2~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize6em \getbuffer[c]}} {C~0~6em}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\zerocount \hsize2pt \getbuffer[c]}} {C~0~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plusone   \hsize2pt \getbuffer[c]}} {C~1~2pt}
+    {\framed[align=normal,strut=no,top=\vskip.5ex,bottom=\vskip.5ex]{\automatichyphenmode\plustwo   \hsize2pt \getbuffer[c]}} {C~2~2pt}
+\stopcombination
+\stopbuffer
+
+\startplacefigure[reference=automatic:1,title={The automatic modes \type {0} (default), \type {1} and \type {2}, with a \type {\hsize}
+of 6em and 2pt (which triggers a linebreak).}]
+    \dontcomplain \tt \getbuffer[demo]
+\stopplacefigure
+
+\startplacefigure[reference=automatic:2,title={The automatic modes \type {0} (default), \type {1} and \type {2}, with \type
+{\preexhyphenchar} and \type {\postexhyphenchar} set to characters \type {A} and \type {B}.}]
+    \postexhyphenchar`A\relax
+    \preexhyphenchar `B\relax
+    \dontcomplain \tt \getbuffer[demo]
+\stopplacefigure
+
+As with primitive companions of other single character commands, the \type {\-}
+command has a more verbose primitive version in \type {\explicitdiscretionary}
+and the normally intercepted in the hyphenator character \type {-} (or whatever
+is configured) is available as \type {\automaticdiscretionary}.
 
 \section{The main control loop}
 
diff --git a/manual/luatex-nodes.tex b/manual/luatex-nodes.tex
index 21f1789e5a99b08462d7b78c7b516a2876fec246..d3c2c06dae1a3bb51a4354cb144ebeb10517f3ed 100644
--- a/manual/luatex-nodes.tex
+++ b/manual/luatex-nodes.tex
@@ -301,11 +301,15 @@ a \type {userskip} with subtype zero).
 
 \starttabulate[|lT|l|p|]
 \NC \rmbf field  \NC \bf type \NC \bf explanation \NC \NR
-\NC subtype      \NC number   \NC not used \NC \NR
+\NC subtype      \NC number   \NC \showsubtypes{penalty} \NC \NR
 \NC attr         \NC node     \NC list of attributes \NC \NR
 \NC penalty      \NC number   \NC the penalty value \NC \NR
 \stoptabulate
 
+The subtypes are just informative and \TEX\ itself doesn't use them. When you
+run into an \type {linebreakpenalty} you need to keep in mind that it's a
+accumulation of \type {club}, \type{widow} and other relevant penalties.
+
 \subsubsection[glyphnodes]{glyph nodes}
 
 \starttabulate[|lT|l|p|]
@@ -1705,6 +1709,13 @@ tail node.
     node.slide(<node> n)
 \stopfunctioncall
 
+After some callbacks automatic sliding takes place. This feature can be turned
+off with \type {node.fix_node_lists(false)} but you better make sure then that
+you don't mess up lists. In most cases \TEX\ itself only uses \type {next}
+pointers but your other callbacks might expect proper \type {prev} pointers too.
+Future versions of \LUATEX\ can add more checking but this will not influence
+usage.
+
 \subsubsection{\type {node.check_discretionary} and \type {node.check_discretionaries}}
 
 When you fool around with disc nodes you need to be aware of the fact that they
diff --git a/manual/luatex-tex.tex b/manual/luatex-tex.tex
index 650f3ca056db95185732b5c2b9c25e2c7c6f9a47..fac1af39353a0809729542d727ce3cb525605f63 100644
--- a/manual/luatex-tex.tex
+++ b/manual/luatex-tex.tex
@@ -161,7 +161,7 @@ The current list is:
 \NC pool_ptr           \NC string pool index \NC \NR
 \NC pool_size          \NC current size allocated for string characters \NC \NR
 \NC save_size          \NC save stack size \NC \NR
-\NC shell_escape       \NC \type {0} means disabled, \type {1} means anything is permitted and \type {2} is restricted   \NC \NR
+\NC shell_escape       \NC \type {0} means disabled, \type {1} means anything is permitted and \type {2} is restricted  \NC \NR
 \NC safer_option       \NC \type {1} means safer is enforced \NC \NR
 \NC kpse_used          \NC \type {1} means that kpse is used \NC \NR
 \NC stack_size         \NC input stack size \NC \NR
diff --git a/manual/luatex.pdf b/manual/luatex.pdf
index 006bfc7856ebcbc182574062de7e8c5b984448ac..277bf24122390d3909133f74766222663d38f1de 100644
Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ
diff --git a/manual/luatex.tex b/manual/luatex.tex
index 1ccc9b7a59a39552d9eaac9a2a7bafcd5174e6a6..1613b920b206b2b2c5a64f9b3369792a370c5db0 100644
--- a/manual/luatex.tex
+++ b/manual/luatex.tex
@@ -29,8 +29,8 @@
 \dontcomplain
 
 \startdocument
-  [status=intermediate release,
-   version=1.0.4]
+  [status=release,
+   version=1.0.5]
 
 \component luatex-titlepage
 
diff --git a/source/texk/web2c/luatexdir/font/luafont.w b/source/texk/web2c/luatexdir/font/luafont.w
index 4e874d9becb896585da678362505845b75366417..d7a5c5f904d3c4f6ff5970724e36c767fc417df4 100644
--- a/source/texk/web2c/luatexdir/font/luafont.w
+++ b/source/texk/web2c/luatexdir/font/luafont.w
@@ -1995,8 +1995,9 @@ halfword handle_ligaturing(halfword head, halfword tail)
         vlink(tail) = null;
     }
 
-    /* |if (fix_node_lists)| */
-    fix_node_list(head);
+    if (fix_node_lists) {
+        fix_node_list(head);
+    }
 
     prev = head;
     cur = vlink(prev);
@@ -2184,7 +2185,9 @@ static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callb
         luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
         return tail;
     }
-    fix_node_list(head);
+    if (fix_node_lists) {
+        fix_node_list(head);
+    }
     lua_settop(Luas, top);
     return tail;
 }
diff --git a/source/texk/web2c/luatexdir/lang/hyphen.w b/source/texk/web2c/luatexdir/lang/hyphen.w
index 8e13896090d769a68b025dba26403c1a7bf58d84..35befb743debbf7e34b4429727f7a3edc25b6d8d 100644
--- a/source/texk/web2c/luatexdir/lang/hyphen.w
+++ b/source/texk/web2c/luatexdir/lang/hyphen.w
@@ -776,6 +776,8 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
 }
 
 @ @c
+extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan);
+
 void hnj_hyphen_hyphenate(HyphenDict * dict,
                           halfword first1,
                           halfword last1,
@@ -791,9 +793,9 @@ void hnj_hyphen_hyphenate(HyphenDict * dict,
     char *hyphens = hnj_malloc(hyphen_len + 1);
 
     /* Add a '.' to beginning and end to facilitate matching */
-    set_vlink(begin_point, first1);
-    set_vlink(end_point, get_vlink(last1));
-    set_vlink(last1, end_point);
+    vlink(begin_point) = first1;
+    vlink(end_point) = vlink(last1);
+    vlink(last1) = end_point;
 
     for (char_num = 0; char_num < hyphen_len; char_num++) {
         hyphens[char_num] = '0';
@@ -801,16 +803,16 @@ void hnj_hyphen_hyphenate(HyphenDict * dict,
     hyphens[hyphen_len] = 0;
 
     /* now, run the finite state machine */
-    for (char_num = 0, here = begin_point; here != get_vlink(end_point);
-         here = get_vlink(here)) {
+    for (char_num = 0, here = begin_point; here != vlink(end_point);
+         here = vlink(here)) {
 
         int ch;
         if (here == begin_point || here == end_point) {
             ch = '.';
         } else {
-            ch = get_hj_code(char_lang(here),get_character(here));
+            ch = get_hj_code(char_lang(here),character(here));
             if (ch <= 32) {
-                ch = get_character(here);
+                ch = character(here);
             }
         }
         while (state != -1) {
@@ -857,14 +859,14 @@ void hnj_hyphen_hyphenate(HyphenDict * dict,
     }
 
     /* restore the correct pointers */
-    set_vlink(last1, get_vlink(end_point));
+    vlink(last1) = vlink(end_point);
 
     /* pattern is \.{\^.\^w\^o\^r\^d\^.\^}   |word_len|=4, |ext_word_len|=6, |hyphens|=7
      * check      \.{    \^ \^ \^    }   so drop first two and stop after |word_len-1|
      */
-    for (here = first1, char_num = 2; here != left; here = get_vlink(here))
+    for (here = first1, char_num = 2; here != left; here = vlink(here))
         char_num++;
-    for (; here != right; here = get_vlink(here)) {
+    for (; here != right; here = vlink(here)) {
         if (hyphens[char_num] & 1)
             here = insert_syllable_discretionary(here, lan);
         char_num++;
diff --git a/source/texk/web2c/luatexdir/lang/texlang.h b/source/texk/web2c/luatexdir/lang/texlang.h
index 5e7a046195f2c092253b36bcd0d43a6a1de1c31e..0fa11d4c82f79f7b2905298c92965d904c12452a 100644
--- a/source/texk/web2c/luatexdir/lang/texlang.h
+++ b/source/texk/web2c/luatexdir/lang/texlang.h
@@ -67,7 +67,7 @@ extern int get_post_exhyphen_char(int lan);
 extern void set_hyphenation_min(int lan, int val);
 extern int get_hyphenation_min(int lan);
 
-extern halfword compound_word_break(halfword t, int clang);
+/* extern halfword compound_word_break(halfword t, int clang); */
 
 extern void dump_language_data(void);
 extern void undump_language_data(void);
@@ -82,5 +82,7 @@ extern void new_post_exhyphen_char(void);
 extern void new_hyphenation_min(void);
 extern void new_hj_code(void);
 
+extern void set_disc_field(halfword f, halfword t);
+extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan);
 
 #endif
diff --git a/source/texk/web2c/luatexdir/lang/texlang.w b/source/texk/web2c/luatexdir/lang/texlang.w
index bd519af632ab8192a136c0ce982805ebcc717be8..337d2eca51dfebcfc08bc7806e177c8380d309ad 100644
--- a/source/texk/web2c/luatexdir/lang/texlang.w
+++ b/source/texk/web2c/luatexdir/lang/texlang.w
@@ -60,7 +60,8 @@ struct tex_language *new_language(int n)
         lang->post_exhyphen_char = 0;
         lang->hyphenation_min = -1;
         if (saving_hyph_codes_par) {
-            hj_codes_from_lc_codes(l); /* for now, we might just use specific value for whatever task */
+            /* for now, we might just use specific value for whatever task */
+            hj_codes_from_lc_codes(l);
         }
         return lang;
     } else {
@@ -198,10 +199,10 @@ void load_tex_patterns(int curlang, halfword head)
 const char *clean_hyphenation(int id, const char *buff, char **cleaned)
 {
     int items = 0;
-    unsigned char word[MAX_WORD_LEN + 1]; /* work buffer for bytes */
-    unsigned uword[MAX_WORD_LEN + 1] = { 0 };  /* work buffer for unicode */
-    int u = 0; /* unicode buffer value */
-    int i = 0; /* index into buffer */
+    unsigned char word[MAX_WORD_LEN + 1];     /* work buffer for bytes */
+    unsigned uword[MAX_WORD_LEN + 1] = { 0 }; /* work buffer for unicode */
+    int u = 0;                                /* unicode buffer value */
+    int i = 0;                                /* index into buffer */
     char *uindex = (char *)word;
     const char *s = buff;
 
@@ -218,12 +219,12 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned)
     /* now convert the input to unicode */
     word[i] = '\0';
     utf2uni_strcpy(uword, (const char *)word);
-
     /* build the new word string */
     i = 0;
     while (uword[i]>0) {
         u = uword[i++];
-        if (u == '-') {        /* skip */
+        if (u == '-') {
+            /* skip */
         } else if (u == '=') {
             STORE_CHAR(id,'-');
         } else if (u == '{') {
@@ -253,7 +254,7 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned)
             if (u == '}') {
                 items++;
             }
-            if (items != 3) {   /* syntax error */
+            if (items != 3) {
                 *cleaned = NULL;
                 tex_error("exception syntax error", NULL);
                 return s;
@@ -322,51 +323,61 @@ void load_tex_hyphenation(int curlang, halfword head)
 }
 
 @ @c
-halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty)
+static halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty)
 {
-    halfword g, n;
+    halfword g;
     int f;
-    n = new_node(disc_node, syllable_disc);
-    disc_penalty(n) = penalty;
-    try_couple_nodes(n, vlink(t));
-    couple_nodes(t, n);
-    if (replace != null)
+    halfword d = new_node(disc_node, syllable_disc);
+    int attr = node_attr(t) ;
+    disc_penalty(d) = penalty;
+    if (t == replace) {
+        /* prev disc next-next */
+        try_couple_nodes(d, vlink(t));
+        try_couple_nodes(alink(t), d);
+        alink(t) = null;
+        vlink(t) = null;
+        replace = t ;
+    } else {
+        /* prev disc next */
+        try_couple_nodes(d, vlink(t));
+        couple_nodes(t, d);
+    }
+    if (replace != null) {
         f = font(replace);
-    else
-        f = get_cur_font();     /* for compound words following explicit hyphens */
+    } else {
+        /* For compound words following explicit hyphens. */
+        f = get_cur_font();
+    }
     for (g = pre; g != null; g = vlink(g)) {
         font(g) = f;
-        if (node_attr(t) != null) {
+        if (attr != null) {
             delete_attribute_ref(node_attr(g));
-            node_attr(g) = node_attr(t);
-            attr_list_ref(node_attr(t)) += 1;
+            node_attr(g) = attr;
+            attr_list_ref(attr) += 1;
         }
     }
     for (g = post; g != null; g = vlink(g)) {
         font(g) = f;
-        if (node_attr(t) != null) {
+        if (attr != null) {
             delete_attribute_ref(node_attr(g));
-            node_attr(g) = node_attr(t);
-            attr_list_ref(node_attr(t)) += 1;
+            node_attr(g) = attr;
+            attr_list_ref(attr) += 1;
         }
     }
-    for (g = replace; g != null; g = vlink(g)) {
-        if (node_attr(t) != null) {
+    if (attr != null) {
+        for (g = replace; g != null; g = vlink(g)) {
             delete_attribute_ref(node_attr(g));
-            node_attr(g) = node_attr(t);
-            attr_list_ref(node_attr(t)) += 1;
+            node_attr(g) = attr;
+            attr_list_ref(attr) += 1;
         }
+        delete_attribute_ref(node_attr(d));
+        node_attr(d) = attr;
+        attr_list_ref(attr) += 1;
     }
-    if (node_attr(t) != null) {
-        delete_attribute_ref(node_attr(vlink(t)));
-        node_attr(vlink(t)) = node_attr(t);
-        attr_list_ref(node_attr(t)) += 1;
-    }
-    t = vlink(t);
-    set_disc_field(pre_break(t), pre);
-    set_disc_field(post_break(t), post);
-    set_disc_field(no_break(t), replace);
-    return t;
+    set_disc_field(pre_break(d), pre);
+    set_disc_field(post_break(d), post);
+    set_disc_field(no_break(d), replace);
+    return d;
 }
 
 halfword insert_syllable_discretionary(halfword t, lang_variables * lan)
@@ -413,43 +424,38 @@ halfword insert_syllable_discretionary(halfword t, lang_variables * lan)
 }
 
 @ @c
-halfword compound_word_break(halfword t, int clang)
+static halfword insert_character(halfword t, int c)
+{
+    halfword p;
+    p = new_node(glyph_node, 0);
+    set_to_character(p);
+    character(p) = c;
+    if (t != null) {
+        couple_nodes(t, p);
+    }
+    return p;
+}
+
+static halfword compound_word_break(halfword t, int clang)
 {
     halfword disc = null;
     halfword pre = null;
     halfword pos = null;
     halfword pre_exhyphen_char = get_pre_exhyphen_char(clang);
     halfword post_exhyphen_char = get_post_exhyphen_char(clang);
-    if (pre_exhyphen_char > 0)
+    if (pre_exhyphen_char > 0) {
         pre = insert_character(null,pre_exhyphen_char);
+    } else {
+        pre = insert_character(null,ex_hyphen_char_par);
+    }
     if (post_exhyphen_char > 0)
         pos = insert_character(null,post_exhyphen_char);
-    disc = insert_discretionary(t,pre,pos,null,ex_hyphen_penalty_par);
+    disc = insert_discretionary(t,pre,pos,t,ex_hyphen_penalty_par);
     subtype(disc) = automatic_disc;
     set_automatic_disc_penalty(disc);
     return disc;
 }
 
-halfword insert_complex_discretionary(halfword t, lang_variables * lan,
-                                      halfword pre, halfword pos,
-                                      halfword replace)
-{
-    (void) lan;
-    return insert_discretionary(t,pre,pos,replace,hyphen_penalty_par);
-}
-
-halfword insert_character(halfword t, int c)
-{
-    halfword p;
-    p = new_node(glyph_node, 0);
-    set_to_character(p);
-    character(p) = c;
-    if (t != null) {
-        couple_nodes(t, p);
-    }
-    return p;
-}
-
 @ @c
 void set_disc_field(halfword f, halfword t)
 {
@@ -713,6 +719,20 @@ there was not the best idea ever.
 
 */
 
+/*
+    We only accept an explicit hyphen when there is a preceding glyph and we skip a sequence of
+    explicit hyphens as that normally indicates a -- or --- ligature in which case we can in a
+    worse case usage get bad node lists later on due to messed up ligature building as these
+    dashes are ligatures in base fonts. This is a side effect of the separating the hyphenation,
+    ligaturing and kerning steps. A test is cmr with ------.
+
+    A font handler can collapse successive hyphens but it's not nice to put the burden there. A
+    somewhat messy border case is ---- but in LuaTeX we don't treat -- and --- special. Also,
+    traditional TeX will break a line at -foo but this can be disabled by setting the automatic
+    mode to 1.
+
+*/
+
 static halfword find_next_wordstart(halfword r, halfword first_language, halfword strict_bound)
 {
     register int l;
@@ -757,27 +777,31 @@ static halfword find_next_wordstart(halfword r, halfword first_language, halfwor
             if (is_simple_character(r)) {
                 chr = character(r) ;
                 if (chr == ex_hyphen_char_par) {
-                    /*
-                        We only accept an explicit hyphen when there is a preceding glyph and
-                        we skip a sequence of explicit hyphens as that normally indicates a
-                        -- or --- ligature in which case we can in a worse case usage get bad
-                        node lists later on due to messed up ligature building as these dashes
-                        are ligatures in base fonts. This is a side effect of the separating the
-                        hyphenation, ligaturing and kerning steps. A test is cmr with ------.
-                    */
                     t = vlink(r) ;
-                    if ((start_ok == 0) && (t!=null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) {
-                        compound_word_break(r, char_lang(r));
-                        start_ok = 1 ;
+                    if ((automatic_hyphen_mode_par == 0) && (t != null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) {
+                        /* we have no word yet and the next character is a non hyphen */
+                        r = compound_word_break(r, char_lang(r));
                     } else {
-                        start_ok = 0;
+                        /* we jump over the sequence of hyphens */
+                        while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
+                            r = t ;
+                            t = vlink(r) ;
+                        }
+                        if (t == null) {
+                            /* we reached the end of the list so we have no word start */
+                            return null;
+                        }
                     }
+                    /* we need a restart */
+                    start_ok = 0;
                 } else if (start_ok && (char_lang(r)>=first_language) && ((l = get_hj_code(char_lang(r),chr)) > 0)) {
                     if (char_uchyph(r) || l == chr || l <= 32) {
                         return r;
                     } else {
                         start_ok = 0;
                     }
+                } else {
+                    /* go on */
                 }
             }
             break;
@@ -839,18 +863,23 @@ void hnj_hyphenation(halfword head, halfword tail)
     halfword strict_bound = hyphenation_bounds_par;
     halfword s, r = head, wordstart = null, save_tail1 = null, left = null, right = null;
 
-    /* this first movement assures two things:
-     \item{a)} that we won't waste lots of time on something that has been
-      handled already (in that case, none of the glyphs match |simple_character|).
-     \item{b)} that the first word can be hyphenated. if the movement was
-     not explicit, then the indentation at the start of a paragraph
-     list would make |find_next_wordstart()| look too far ahead.
-     */
+    /*
+        This first movement assures two things:
+
+        \item{a)} that we won't waste lots of time on something that has been handled already
+        (in that case, none of the glyphs match |simple_character|).
+
+        \item{b)} that the first word can be hyphenated. if the movement was not explicit,
+        then the indentation at the start of a paragraph list would make |find_next_wordstart()|
+        look too far ahead.
+    */
 
     while (r != null && (type(r) != glyph_node || !is_simple_character(r))) {
         r = vlink(r);
     }
-    /* this will make |r| a glyph node with subtype character */
+    /*
+        This will make |r| a glyph node with subtype character.
+    */
     r = find_next_wordstart(r,first_language,strict_bound);
     if (r == null)
         return;
@@ -860,15 +889,17 @@ void hnj_hyphenation(halfword head, halfword tail)
     s = new_penalty(0,word_penalty);
     couple_nodes(tail, s);
 
-    while (r != null) {         /* could be while(1), but let's be paranoid */
+    while (r != null) { /* could be while(1), but let's be paranoid */
         int clang, lhmin, rhmin, hmin;
         halfword hyf_font;
         halfword end_word = r;
         wordstart = r;
         assert(is_simple_character(wordstart));
         hyf_font = font(wordstart);
-        if (hyphen_char(hyf_font) < 0)  /* for backward compat */
+        if (hyphen_char(hyf_font) < 0) {
+            /* For backward compatibility: */
             hyf_font = 0;
+        }
         clang = char_lang(wordstart);
         lhmin = char_lhmin(wordstart);
         rhmin = char_rhmin(wordstart);
@@ -889,6 +920,7 @@ void hnj_hyphenation(halfword head, halfword tail)
               ) {
             if (character(r) == ex_hyphen_char_par) {
                 explicit_hyphen = true;
+                break;
             }
             wordlen++;
             if (lchar <= 32) {
@@ -911,12 +943,27 @@ void hnj_hyphenation(halfword head, halfword tail)
                 lchar = character(r) ;
             }
             hy = uni2string(hy, (unsigned) lchar);
-            /* this should not be needed  any more */
-            /*if (vlink(r)!=null) alink(vlink(r))=r; */
             end_word = r;
             r = vlink(r);
         }
-        if (     valid_wordend(r,strict_bound)
+        if (explicit_hyphen == true) {
+            /* we are not at the start, so we only need to look ahead */
+            halfword t = vlink(r) ;
+            if ((automatic_hyphen_mode_par == 0 || automatic_hyphen_mode_par == 1) && (t != null) && ((type(t) == glyph_node) && (character(t) != ex_hyphen_char_par))) {
+                /* we have a word already but the next character may not be a hyphen too */
+                r = compound_word_break(r, char_lang(r));
+            } else {
+                /* we jump over the sequence of hyphens */
+                while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
+                    r = t ;
+                    t = vlink(r) ;
+                }
+                if (t == null) {
+                    /* we reached the end of the list and will quit the loop later */
+                    r = null;
+                }
+            }
+        } else if (     valid_wordend(r,strict_bound)
               && clang >= first_language
               && wordlen >= lhmin + rhmin
               && (hmin <= 0 || wordlen >= hmin)
@@ -924,35 +971,10 @@ void hnj_hyphenation(halfword head, halfword tail)
               && (lang = tex_languages[clang]) != NULL
            ) {
             *hy = 0;
-            if (    lang->exceptions != 0
-                 && (replacement = hyphenation_exception(lang->exceptions, utf8word)) != NULL
-               ) {
-#ifdef VERBOSE
-                formatted_warning("hyphenation","replacing %s (c=%d) by %s", utf8word, clang, replacement);
-#endif
+            if (lang->exceptions != 0 && (replacement = hyphenation_exception(lang->exceptions, utf8word)) != NULL) {
+                /* handle the exception and go on to the next word */
                 do_exception(wordstart, r, replacement);
                 free(replacement);
-            } else if (explicit_hyphen == true) {
-                /*
-                    insert an explicit discretionary after each of the last in a
-                    set of explicit hyphens
-                */
-                halfword rr = r;
-#ifdef VERBOSE
-                formatted_warning("hyphenation","explicit hyphen(s) found in %s (c=%d)", utf8word, clang);
-#endif
-                while (rr != wordstart) {
-                if (is_simple_character(rr)) {
-                        if (character(rr) == ex_hyphen_char_par) {
-                            compound_word_break(rr, clang);
-                            while (character(alink(rr)) == ex_hyphen_char_par)
-                                rr = alink(rr);
-                            if (rr == wordstart)
-                                break;
-                        }
-                    }
-                    rr = alink(rr);
-                }
             } else if (lang->patterns != NULL) {
                 left = wordstart;
                 for (i = lhmin; i > 1; i--) {
@@ -960,10 +982,7 @@ void hnj_hyphenation(halfword head, halfword tail)
                     while (!is_simple_character(left)) {
                         left = vlink(left);
                     }
-                    /*
-                    if (!left)
-                        break ;
-                    */
+                    /* if (!left) break; */
                     /* what is left overruns right .. a bit messy */
                 }
                 right = r;
@@ -972,20 +991,10 @@ void hnj_hyphenation(halfword head, halfword tail)
                     while (!is_simple_character(right)) {
                         right = alink(right);
                     }
-                    /*
-                    if (!right)
-                        break ;
-                    */
+                    /* if (!right) break; */
                     /* what is right overruns left .. a bit messy */
                 }
-                /* maybe an extra check ... */
-                /* |if (left && right) {| */
-#ifdef VERBOSE
-                    formatted_warning("hyphenation","hyphenate %s (c=%d,l=%d,r=%d) from %c to %c",
-                        utf8word, clang, lhmin, rhmin, character(left), character(right));
-#endif
-                    (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata);
-                /* |}| */
+                (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata);
             }
         }
         explicit_hyphen = false;
@@ -1026,7 +1035,7 @@ void new_hyphenation(halfword head, halfword tail)
     }
 }
 
-@ dumping and undumping languages
+@ Dumping and undumping languages.
 
 @c
 #define dump_string(a)                \
@@ -1139,20 +1148,19 @@ void new_hyph_exceptions(void)
     flush_list(def_ref);
 }
 
-@ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a
-procedure named |new_patterns|.
+@ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a procedure named
+|new_patterns|.
 
 @c
 void new_patterns(void)
-{                               /* initializes the hyphenation pattern data */
+{
     (void) scan_toks(false, true);
     load_tex_patterns(language_par, def_ref);
     flush_list(def_ref);
 }
 
-@ `\.{\\prehyphenchar}', sets the |pre_break| character, and
-`\.{\\posthyphenchar}' the |post_break| character. Their respective defaults are
-ascii hyphen ("-") and zero (nul).
+@ `\.{\\prehyphenchar}', sets the |pre_break| character, and `\.{\\posthyphenchar}' the
+|post_break| character. Their respective defaults are ascii hyphen ("-") and zero (nul).
 
 @c
 void new_pre_hyphen_char(void)
@@ -1169,9 +1177,8 @@ void new_post_hyphen_char(void)
     set_post_hyphen_char(language_par, cur_val);
 }
 
-@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and
-`\.{\\postexhyphenchar}' the |post_break| character. Their defaults are both zero
-(nul).
+@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and `\.{\\postexhyphenchar}' the
+|post_break| character. Their defaults are both zero (nul).
 
 @c
 void new_pre_exhyphen_char(void)
diff --git a/source/texk/web2c/luatexdir/lua/liolibext.c b/source/texk/web2c/luatexdir/lua/liolibext.c
index e910139c2ce5c0cf74b10fbde3df963eb3e07c62..2e09c4541d40ad5c2313f4f2e039706d9e6cfa9c 100644
--- a/source/texk/web2c/luatexdir/lua/liolibext.c
+++ b/source/texk/web2c/luatexdir/lua/liolibext.c
@@ -29,11 +29,9 @@
 #endif
 #include "lualib.h"
 
-
-
 #ifdef LuajitTeX
 /* luajit has its own way for io, which is a mix of    */
-/* lua 5.1 and lua 5.2 . We use the stock luajit.      */    
+/* lua 5.1 and lua 5.2 . We use the stock luajit.      */
 #else
 /*
 ** {======================================================
@@ -61,7 +59,6 @@
 
 /* }====================================================== */
 
-
 #if defined(LUA_USE_POSIX)
 
 #define l_fseek(f,o,w)          fseeko(f,o,w)
@@ -92,9 +89,6 @@
 
 #endif/* #ifdef LuajitTeX */
 
-
-
-
 static FILE *tofile (lua_State *L) {
 #ifdef LuajitTeX
     FILE **f = luaL_checkudata(L,1,LUA_FILEHANDLE);
@@ -110,6 +104,8 @@ static FILE *tofile (lua_State *L) {
 #endif
 }
 
+#define uchar(c) ((unsigned char)(c))
+
 /*
     HH: A few helpers to avoid reading numbers as strings. For now we put them in their
     own namespace. We also have a few helpers that can make io functions tex friendly.
@@ -125,6 +121,19 @@ static int readcardinal1(lua_State *L) {
     return 1;
 }
 
+static int readcardinal1_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p]);
+        lua_pushinteger(L, a);
+    }
+    return 1;
+}
+
 static int readcardinal2(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -137,6 +146,20 @@ static int readcardinal2(lua_State *L) {
     return 1;
 }
 
+static int readcardinal2_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+1 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p]);
+        lua_pushinteger(L, 0x100 * a + b);
+    }
+    return 1;
+}
+
 static int readcardinal3(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -150,6 +173,21 @@ static int readcardinal3(lua_State *L) {
     return 1;
 }
 
+static int readcardinal3_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+2 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p++]);
+        int c = uchar(s[p]);
+        lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+    }
+    return 1;
+}
+
 static int readcardinal4(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -164,6 +202,22 @@ static int readcardinal4(lua_State *L) {
     return 1;
 }
 
+static int readcardinal4_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+3 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p++]);
+        int c = uchar(s[p++]);
+        int d = uchar(s[p]);
+        lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d);
+    }
+    return 1;
+}
+
 static int readinteger1(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -176,6 +230,22 @@ static int readinteger1(lua_State *L) {
     return 1;
 }
 
+static int readinteger1_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushinteger(L, a - 0x100);
+        else
+            lua_pushinteger(L, a);
+    }
+    return 1;
+}
+
 static int readinteger2(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -189,6 +259,23 @@ static int readinteger2(lua_State *L) {
     return 1;
 }
 
+static int readinteger2_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+1 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushinteger(L, 0x100 * a + b - 0x10000);
+        else
+            lua_pushinteger(L, 0x100 * a + b);
+    }
+    return 1;
+}
+
 static int readinteger3(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -203,6 +290,24 @@ static int readinteger3(lua_State *L) {
     return 1;
 }
 
+static int readinteger3_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+2 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p++]);
+        int c = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
+        else
+            lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+    }
+    return 1;
+}
+
 static int readinteger4(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -218,6 +323,25 @@ static int readinteger4(lua_State *L) {
     return 1;
 }
 
+static int readinteger4_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+3 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p++]);
+        int c = uchar(s[p++]);
+        int d = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000);
+        else
+            lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d);
+    }
+    return 1;
+}
+
 static int readfixed2(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -225,9 +349,26 @@ static int readfixed2(lua_State *L) {
     if (b == EOF)
         lua_pushnil(L);
     else if (a >= 0x80)
-        lua_pushinteger(L, a + b/0xFFFF - 0x100);
+        lua_pushinteger(L, (a - 0x100) + b/0x100);
     else
-        lua_pushinteger(L, a + b/0xFFFF);
+        lua_pushinteger(L, (a        ) + b/0x100);
+    return 1;
+}
+
+static int readfixed2_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+3 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushinteger(L, (a - 0x100) + b/0x100);
+        else
+            lua_pushinteger(L, (a        ) + b/0x100);
+    }
     return 1;
 }
 
@@ -240,15 +381,34 @@ static int readfixed4(lua_State *L) {
     if (d == EOF)
         lua_pushnil(L);
     else if (a >= 0x80)
-        lua_pushnumber(L, (0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000)/65536.0);
+        lua_pushnumber(L, (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000);
     else
-        lua_pushnumber(L, (0x1000000 * a + 0x10000 * b + 0x100 * c + d)/65536.0);
+        lua_pushnumber(L, (0x100 * a + b          ) + (0x100 * c + d)/0x10000);
     /* from ff */
     /* int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d; */
     /* lua_pushnumber(L,(real) (n>>16) + ((n&0xffff)/65536.0)); */
     return 1;
 }
 
+static int readfixed4_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+3 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p++]);
+        int c = uchar(s[p++]);
+        int d = uchar(s[p]);
+        if (a >= 0x80)
+            lua_pushnumber(L, (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000);
+        else
+            lua_pushnumber(L, (0x100 * a + b          ) + (0x100 * c + d)/0x10000);
+    }
+    return 1;
+}
+
 static int read2dot14(lua_State *L) {
     FILE *f = tofile(L);
     int a = getc(f);
@@ -263,6 +423,21 @@ static int read2dot14(lua_State *L) {
     return 1;
 }
 
+static int read2dot14_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    if (p < 0 || p+1 >= l) {
+        lua_pushnil(L);
+    } else {
+        int a = uchar(s[p++]);
+        int b = uchar(s[p]);
+        int n = 0x100 * a + b;
+        lua_pushnumber(L,(real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0));
+    }
+    return 1;
+}
+
 static int getposition(lua_State *L) {
     FILE *f = tofile(L);
     long p = ftell(f);
@@ -317,6 +492,28 @@ static int readbytetable(lua_State *L) {
     return 1;
 }
 
+static int readbytetable_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    int n = lua_tointeger(L,3);
+    if (p < 0 || p >= l) {
+        lua_pushnil(L);
+    } else {
+        int i ;
+        if (p + n >= l) {
+            n = l - p ;
+        }
+        lua_createtable(L, n, 0);
+        for (i=1;i<=n;i++) {
+            int a = uchar(s[p++]);
+            lua_pushinteger(L, a);
+            lua_rawseti(L,-2,i);
+        }
+    }
+    return 1;
+}
+
 static int readbytes(lua_State *L) {
     FILE *f = tofile(L);
     int n = lua_tointeger(L,2);
@@ -332,6 +529,27 @@ static int readbytes(lua_State *L) {
     return n;
 }
 
+static int readbytes_s(lua_State *L) {
+    size_t l;
+    const char *s = luaL_checklstring(L, 1, &l);
+    size_t p = luaL_checkinteger(L, 2) - 1;
+    int n = lua_tointeger(L,3);
+    if (p < 0 || p >= l) {
+        return 0;
+    } else {
+        int i ;
+        if (p + n >= l) {
+            n = l - p ;
+        }
+        lua_createtable(L, n, 0);
+        for (i=1;i<=n;i++) {
+            int a = uchar(s[p++]);
+            lua_pushinteger(L, a);
+        }
+        return n;
+    }
+}
+
 static int recordfilename(lua_State *L)
 {
     const char *fname = luaL_checkstring(L, 1);
@@ -448,7 +666,35 @@ static const luaL_Reg fiolib[] = {
     {NULL, NULL}
 };
 
+static const luaL_Reg siolib[] = {
+    { "readcardinal1",   readcardinal1_s },
+    { "readcardinal2",   readcardinal2_s },
+    { "readcardinal3",   readcardinal3_s },
+    { "readcardinal4",   readcardinal4_s },
+    { "readinteger1",    readinteger1_s },
+    { "readinteger2",    readinteger2_s },
+    { "readinteger3",    readinteger3_s },
+    { "readinteger4",    readinteger4_s },
+    { "readfixed2",      readfixed2_s },
+    { "readfixed4",      readfixed4_s },
+    { "read2dot14",      read2dot14_s },
+    { "readbytes",       readbytes_s },
+    { "readbytetable",   readbytetable_s },
+    /* done */
+    {NULL, NULL}
+};
+
+/*
+    The sio helpers are experimental and might be handy at some point. Speed-wise
+    there is no gain over file access because with ssd and caching we basically
+    operate in memory too. We keep them as complement to the file ones. I did
+    consider using an userdata object for the position etc but some simple tests
+    demonstrated that there is no real gain and the current ones permits to wrap
+    up whatever interface one likes.
+*/
+
 int luaopen_fio(lua_State *L) {
     luaL_register(L, "fio", fiolib);
+    luaL_register(L, "sio", siolib);
     return 1;
 }
diff --git a/source/texk/web2c/luatexdir/lua/lnodelib.c b/source/texk/web2c/luatexdir/lua/lnodelib.c
index 49929fa27926e5c1db04dfd2f75f6ddc7c328f20..eeb93b3a09b7b38b67300c8e5211ac6eb3e1f4d4 100644
--- a/source/texk/web2c/luatexdir/lua/lnodelib.c
+++ b/source/texk/web2c/luatexdir/lua/lnodelib.c
@@ -268,6 +268,19 @@ static int get_valid_node_subtype_id(lua_State * L, int n)
     return i;
 }
 
+/* enable fixer ... more fixers can be added in the future */
+
+static int lua_nodelib_fix_node_lists(lua_State * L)
+{
+    if (lua_type(L, -1) == LUA_TBOOLEAN) {
+        fix_node_lists = lua_toboolean(L,-1);
+    } else if (lua_type(L, -1) == LUA_TNUMBER) {
+        fix_node_lists = lua_tointeger(L,-1);
+    }
+    return 0;
+}
+
+
 /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
 
 static int lua_nodelib_next(lua_State * L)
@@ -3198,7 +3211,7 @@ static int lua_nodelib_set_glue(lua_State * L)
             stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
             shrink_order(n)  = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
         }
-	return 0;
+        return 0;
     }
     return luaL_error(L, "glue (spec) expected");
 }
@@ -7588,6 +7601,99 @@ static int lua_nodelib_check_discretionary(lua_State * L) {
     return 0;
 }
 
+/* synctex but not */
+
+static int lua_nodelib_set_synctex_mode(lua_State * L)
+{
+    halfword mode = lua_tointeger(L, 1);
+    synctex_set_mode(mode);
+    return 0;
+}
+
+static int lua_nodelib_set_synctex_tag(lua_State * L)
+{
+    halfword tag = lua_tointeger(L, 1);
+    synctex_set_tag(tag);
+    return 0;
+}
+
+static int lua_nodelib_set_synctex_line(lua_State * L)
+{
+    halfword line = lua_tointeger(L, 1);
+    synctex_set_line(line);
+    return 0;
+}
+
+static int lua_nodelib_direct_set_synctex_fields(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    halfword tag = lua_tointeger(L, 2);
+    halfword line = lua_tointeger(L, 3);
+    if (n != null) {
+        switch (type(n)) {
+            case math_node:
+                if (tag)  synctex_tag_math(n)  = tag;
+                if (line) synctex_line_math(n) = line;
+                break;
+            case glue_node:
+                if (tag)  synctex_tag_glue(n)  = tag;
+                if (line) synctex_line_glue(n) = line;
+                break;
+            case kern_node:
+                if (tag)  synctex_tag_kern(n)  = tag;
+                if (line) synctex_line_kern(n) = line;
+                break;
+            case hlist_node:
+            case vlist_node:
+            case unset_node:
+                if (tag)  synctex_tag_box(n)  = tag;
+                if (line) synctex_line_box(n) = line;
+                break;
+            case rule_node:
+                if (tag)  synctex_tag_rule(n)  = tag;
+                if (line) synctex_line_rule(n) = line;
+                break;
+        }
+    }
+    return 0;
+}
+
+static int lua_nodelib_direct_get_synctex_fields(lua_State * L)
+{
+    halfword n = lua_tointeger(L, 1);
+    if (n != null) {
+        switch (type(n)) {
+            case math_node:
+                lua_pushinteger(L,synctex_tag_math(n));
+                lua_pushinteger(L,synctex_line_math(n));
+                break;
+            case glue_node:
+                lua_pushinteger(L,synctex_tag_glue(n));
+                lua_pushinteger(L,synctex_line_glue(n));
+                break;
+            case kern_node:
+                lua_pushinteger(L,synctex_tag_kern(n));
+                lua_pushinteger(L,synctex_line_kern(n));
+                break;
+            case hlist_node:
+            case vlist_node:
+            case unset_node:
+                lua_pushinteger(L,synctex_tag_box(n));
+                lua_pushinteger(L,synctex_line_box(n));
+                break;
+            case rule_node:
+                lua_pushinteger(L,synctex_tag_rule(n));
+                lua_pushinteger(L,synctex_line_rule(n));
+                break;
+        }
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+/* done */
+
 static const struct luaL_Reg nodelib_p[] = {
     {"__index",    lua_nodelib_get_property_t},
     {"__newindex", lua_nodelib_set_property_t},
@@ -7733,6 +7839,9 @@ static const struct luaL_Reg direct_nodelib_f[] = {
     {"check_discretionary", lua_nodelib_direct_check_discretionary},
     {"check_discretionaries", lua_nodelib_direct_check_discretionaries},
     /* done */
+    {"set_synctex_fields", lua_nodelib_direct_set_synctex_fields},
+    {"get_synctex_fields", lua_nodelib_direct_get_synctex_fields},
+    /* done */
     {NULL, NULL} /* sentinel */
 };
 
@@ -7824,6 +7933,13 @@ static const struct luaL_Reg nodelib_f[] = {
     {"check_discretionary", lua_nodelib_check_discretionary},
     {"check_discretionaries", lua_nodelib_check_discretionaries},
     /* done */
+    {"set_synctex_mode", lua_nodelib_set_synctex_mode},
+    {"set_synctex_tag", lua_nodelib_set_synctex_tag},
+    {"set_synctex_line", lua_nodelib_set_synctex_line},
+ /* {"set_synctex_fields", lua_nodelib_set_synctex_fields}, */
+ /* {"get_synctex_fields", lua_nodelib_get_synctex_fields}, */
+    /* done */
+    {"fix_node_lists", lua_nodelib_fix_node_lists},
     {NULL, NULL} /* sentinel */
 };
 
diff --git a/source/texk/web2c/luatexdir/lua/luanode.w b/source/texk/web2c/luatexdir/lua/luanode.w
index af15748bacd6392a217ea520da44347505c32870..c09cac1ff01b4ecef0c8bd89805110ea02070384 100644
--- a/source/texk/web2c/luatexdir/lua/luanode.w
+++ b/source/texk/web2c/luatexdir/lua/luanode.w
@@ -96,21 +96,18 @@ void lua_node_filter(int filterid, int extrainfo, halfword head_node, halfword *
     start_node = vlink(head_node);
     if (start_node != null) {
         /* maybe just always slide (harmless and fast) */
-        last_node = vlink(start_node);
         if (fix_node_lists) {
-            while (last_node != null) {
-                alink(last_node) = start_node;
-                start_node = last_node;
-                last_node = vlink(start_node);
-            }
+            /* slides and returns last node */
+            *tail_node = fix_node_list(start_node);
         } else {
+            last_node = vlink(start_node);
             while (last_node != null) {
                 start_node = last_node;
                 last_node = vlink(start_node);
             }
+            /* we're at the end now */
+            *tail_node = start_node;
         }
-        /* we're at the end now */
-        *tail_node = start_node;
     } else {
         /* we're already at the end */
         *tail_node = head_node;
diff --git a/source/texk/web2c/luatexdir/luatex.c b/source/texk/web2c/luatexdir/luatex.c
index 3eba56679b8d1e9e2d088b321f031c55cd0f9509..fac1851d9eafcbc15efd5c71500200b97511a1c7 100644
--- a/source/texk/web2c/luatexdir/luatex.c
+++ b/source/texk/web2c/luatexdir/luatex.c
@@ -29,9 +29,9 @@
 #define TeX
 
 int luatex_version = 100;        /* \.{\\luatexversion}  */
-int luatex_revision = '4';      /* \.{\\luatexrevision}  */
-int luatex_date_info = 2017033109;     /* the compile date is now hardwired :YEAR MONTH DAY HOUR*/
-const char *luatex_version_string = "1.0.4";
+int luatex_revision = '5';      /* \.{\\luatexrevision}  */
+int luatex_date_info = 2017033110;     /* the compile date is now hardwired :YEAR MONTH DAY HOUR*/
+const char *luatex_version_string = "1.0.5";
 const char *engine_name = my_name;     /* the name of this engine */
 
 #include <kpathsea/c-ctype.h>
diff --git a/source/texk/web2c/luatexdir/tex/commands.w b/source/texk/web2c/luatexdir/tex/commands.w
index 84235914c64a269e989dcd12f6e2611feeea99c1..27c5ac9cea644792abdfb32958209e5bbfc65a25 100644
--- a/source/texk/web2c/luatexdir/tex/commands.w
+++ b/source/texk/web2c/luatexdir/tex/commands.w
@@ -160,6 +160,7 @@ void initialize_commands(void)
     primitive_luatex("hyphenpenaltymode", assign_int_cmd, int_base + hyphen_penalty_mode_code, int_base);
     primitive_luatex("automatichyphenpenalty", assign_int_cmd, int_base + automatic_hyphen_penalty_code, int_base);
     primitive_luatex("explicithyphenpenalty", assign_int_cmd, int_base + explicit_hyphen_penalty_code, int_base);
+    primitive_luatex("automatichyphenmode", assign_int_cmd, int_base + automatic_hyphen_mode_code, int_base);
 
     /* Many of \TeX's primitives need no |equiv|, since they are identifiable
        by their |eq_type| alone. These primitives are loaded into the hash table
@@ -445,8 +446,10 @@ void initialize_commands(void)
     primitive_tex("unhcopy", un_hbox_cmd, copy_code, 0);
     primitive_tex("unvbox", un_vbox_cmd, box_code, 0);
     primitive_tex("unvcopy", un_vbox_cmd, copy_code, 0);
-    primitive_tex("-", discretionary_cmd, explicit_disc, 0);
+    primitive_tex("-", discretionary_cmd, explicit_disc, 0); /* good old tex */
     primitive_tex("discretionary", discretionary_cmd, discretionary_disc, 0);
+    primitive_luatex("explicitdiscretionary", discretionary_cmd, explicit_disc, 0);
+    primitive_luatex("automaticdiscretionary", discretionary_cmd, automatic_disc, 0);
     primitive_luatex("localleftbox", assign_local_box_cmd, 0, 0);
     primitive_luatex("localrightbox", assign_local_box_cmd, 1, 0);
 
diff --git a/source/texk/web2c/luatexdir/tex/dumpdata.w b/source/texk/web2c/luatexdir/tex/dumpdata.w
index aa0d1655d6dce960eee38bf71180f03efd350167..4f8b1fc896a08e9af5bd3ee09a686d474c983861 100644
--- a/source/texk/web2c/luatexdir/tex/dumpdata.w
+++ b/source/texk/web2c/luatexdir/tex/dumpdata.w
@@ -23,7 +23,7 @@
 
 /* we start with 907: the sum of the values of the bytes of "don knuth" */
 
-#define FORMAT_ID (907+28)
+#define FORMAT_ID (907+29)
 #if ((FORMAT_ID>=0) && (FORMAT_ID<=256))
 #error Wrong value for FORMAT_ID.
 #endif
diff --git a/source/texk/web2c/luatexdir/tex/equivalents.h b/source/texk/web2c/luatexdir/tex/equivalents.h
index d7ca036e25afa8caa832a79e3d0526b7c7396441..a853f55872c37c5a28ea786947e747758430a6c0 100644
--- a/source/texk/web2c/luatexdir/tex/equivalents.h
+++ b/source/texk/web2c/luatexdir/tex/equivalents.h
@@ -291,6 +291,7 @@ the |number_regs| \.{\\dimen} registers.
 #  define hyphen_penalty_mode_code 100
 #  define automatic_hyphen_penalty_code 101
 #  define explicit_hyphen_penalty_code 102
+#  define automatic_hyphen_mode_code 103
 
 #  define math_option_code (explicit_hyphen_penalty_code+1)
 
@@ -773,6 +774,7 @@ extern halfword last_cs_name;
 #define hyphen_penalty_mode_par            int_par(hyphen_penalty_mode_code)
 #define automatic_hyphen_penalty_par       int_par(automatic_hyphen_penalty_code)
 #define explicit_hyphen_penalty_par        int_par(explicit_hyphen_penalty_code)
+#define automatic_hyphen_mode_par          int_par(automatic_hyphen_mode_code)
 
 #define cur_lang_par                       int_par(cur_lang_code)
 #define cur_font_par                       equiv(cur_font_loc)
diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.w b/source/texk/web2c/luatexdir/tex/maincontrol.w
index 0baba872e8e90622fa2d8a8f6bb165d832259936..1d8b020cf0a2f1d19c4de3d6112f872a42d03bab 100644
--- a/source/texk/web2c/luatexdir/tex/maincontrol.w
+++ b/source/texk/web2c/luatexdir/tex/maincontrol.w
@@ -1759,18 +1759,42 @@ void append_discretionary(void)
     if (cur_chr == explicit_disc) {
         /* \- */
         c = get_pre_hyphen_char(cur_lang_par);
-        if (c != 0) {
+        if (c > 0) {
             vlink(pre_break(tail)) = new_char(equiv(cur_font_loc), c);
             alink(vlink(pre_break(tail))) = pre_break(tail);
             tlink(pre_break(tail)) = vlink(pre_break(tail));
         }
         c = get_post_hyphen_char(cur_lang_par);
-        if (c != 0) {
+        if (c > 0) {
             vlink(post_break(tail)) = new_char(equiv(cur_font_loc), c);
             alink(vlink(post_break(tail))) = post_break(tail);
             tlink(post_break(tail)) = vlink(post_break(tail));
         }
         set_explicit_disc_penalty(tail);
+    } else if (cur_chr == automatic_disc) {
+        /* - as done in hyphenator */
+        c = get_pre_exhyphen_char(cur_lang_par);
+        if (c <= 0) {
+            c = ex_hyphen_char_par;
+        }
+        if (c > 0) {
+            vlink(pre_break(tail)) = new_char(equiv(cur_font_loc), c);
+            alink(vlink(pre_break(tail))) = pre_break(tail);
+            tlink(pre_break(tail)) = vlink(pre_break(tail));
+        }
+        c = get_post_exhyphen_char(cur_lang_par);
+        if (c > 0) {
+            vlink(post_break(tail)) = new_char(equiv(cur_font_loc), c);
+            alink(vlink(post_break(tail))) = post_break(tail);
+            tlink(post_break(tail)) = vlink(post_break(tail));
+        }
+        c = ex_hyphen_char_par;
+        if (c > 0) {
+            vlink(no_break(tail)) = new_char(equiv(cur_font_loc), c);
+            alink(vlink(no_break(tail))) = no_break(tail);
+            tlink(no_break(tail)) = vlink(no_break(tail));
+        }
+        set_automatic_disc_penalty(tail);
     } else {
         /* \discretionary */
         if (scan_keyword("penalty")) {
diff --git a/source/texk/web2c/luatexdir/tex/texfileio.w b/source/texk/web2c/luatexdir/tex/texfileio.w
index 2281de12c4c858652b47a963712898c5e9ba46ec..c1610d10d904353743b98053ca593235b7e21e37 100644
--- a/source/texk/web2c/luatexdir/tex/texfileio.w
+++ b/source/texk/web2c/luatexdir/tex/texfileio.w
@@ -967,8 +967,9 @@ void start_input(void)
     update_terminal();
     istate = new_line;
     /* Prepare new file {\sl Sync\TeX} information */
-    synctexstartinput();        /* Give control to the {\sl Sync\TeX} controller */
-
+    if (synctex_par) {
+        synctexstartinput();        /* Give control to the {\sl Sync\TeX} controller */
+    }
     /* Read the first line of the new file */
     /* Here we have to remember to tell the |lua_input_ln| routine not to
        start with a |get|. If the file is empty, it is considered to
diff --git a/source/texk/web2c/luatexdir/tex/texnodes.h b/source/texk/web2c/luatexdir/tex/texnodes.h
index b838dd0a2f95570e01d5fd5575de8d8d3ae2b8be..bc21d52603313c653b272251fa13940c998e6606 100644
--- a/source/texk/web2c/luatexdir/tex/texnodes.h
+++ b/source/texk/web2c/luatexdir/tex/texnodes.h
@@ -23,19 +23,6 @@
 #ifndef __NODES_H__
 #  define __NODES_H__
 
-/* these are in texlang.c */
-
-#  define set_vlink(a,b)  vlink(a)=b
-#  define get_vlink(a)  vlink(a)
-#  define get_character(a)  character(a)
-
-extern halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty);
-extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan);
-extern halfword insert_word_discretionary(halfword t, lang_variables * lan);
-extern halfword insert_complex_discretionary(halfword t, lang_variables * lan, halfword pre, halfword post, halfword replace);
-extern halfword insert_character(halfword t, int n);
-extern void set_disc_field(halfword f, halfword t);
-
 #  define varmemcast(a) (memory_word *)(a)
 
 extern memory_word *volatile varmem;
@@ -928,7 +915,7 @@ extern halfword do_copy_node_list(halfword, halfword);
 extern halfword copy_node_list(halfword);
 extern halfword copy_node(const halfword);
 extern void check_node(halfword);
-extern void fix_node_list(halfword);
+extern halfword fix_node_list(halfword);
 extern int fix_node_lists;
 extern char *sprint_node_mem_usage(void);
 extern halfword raw_glyph_node(void);
@@ -1013,5 +1000,9 @@ extern int lua_properties_use_metatable ;
 
 extern halfword make_local_par_node(int mode);
 
+extern void synctex_set_mode(int mode);
+extern void synctex_set_tag(int tag);
+extern void synctex_set_line(int line);
+
 #endif
 
diff --git a/source/texk/web2c/luatexdir/tex/texnodes.w b/source/texk/web2c/luatexdir/tex/texnodes.w
index 7967006ec35986ec79b4a9754d2318f6c5675385..6a467e11545c42384ea61fe446e506fbc26727a1 100644
--- a/source/texk/web2c/luatexdir/tex/texnodes.w
+++ b/source/texk/web2c/luatexdir/tex/texnodes.w
@@ -827,6 +827,25 @@ static int copy_error(halfword p)
     return 0;
 }
 
+@ @c
+static halfword synctex_anyway_mode = 0;
+static halfword synctex_line_field = 0;
+
+void synctex_set_mode(int m)
+{
+    synctex_anyway_mode = m;
+};
+
+void synctex_set_tag(int t)
+{
+    cur_input.synctex_tag_field = t;
+};
+
+void synctex_set_line(int l)
+{
+    synctex_line_field = l;
+};
+
 @ @c
 halfword new_node(int i, int j)
 {
@@ -892,7 +911,32 @@ halfword new_node(int i, int j)
         default:
             break;
     }
-    if (synctex_par) {
+    if (synctex_anyway_mode) {
+        switch (i) {
+            case math_node:
+                synctex_tag_math(n) = cur_input.synctex_tag_field;
+                synctex_line_math(n) = (synctex_line_field) ? synctex_line_field : line;
+                break;
+            case glue_node:
+                synctex_tag_glue(n) = cur_input.synctex_tag_field;
+                synctex_line_glue(n) = (synctex_line_field) ? synctex_line_field : line;
+                break;
+            case kern_node:
+                synctex_tag_kern(n) = cur_input.synctex_tag_field;
+                synctex_line_kern(n) = (synctex_line_field) ? synctex_line_field : line;
+                break;
+            case hlist_node:
+            case vlist_node:
+            case unset_node:
+                synctex_tag_box(n) = cur_input.synctex_tag_field;
+                synctex_line_box(n) = (synctex_line_field) ? synctex_line_field : line;
+                break;
+            case rule_node:
+                synctex_tag_rule(n) = cur_input.synctex_tag_field;
+                synctex_line_rule(n) = (synctex_line_field) ? synctex_line_field : line;
+                break;
+        }
+    } else if (synctex_par) {
         /* handle synctex extension */
         switch (i) {
             case math_node:
@@ -1718,18 +1762,19 @@ void check_node(halfword p)
 }
 
 @ @c
-void fix_node_list(halfword head)
+halfword fix_node_list(halfword head)
 {
-    halfword p, q;
+    halfword next, tail;
     if (head == null)
-        return;
-    p = head;
-    q = vlink(p);
-    while (q != null) {
-        alink(q) = p;
-        p = q;
-        q = vlink(p);
+        return null;
+    tail = head;
+    next = vlink(head);
+    while (next != null) {
+        alink(next) = tail;
+        tail = next;
+        next = vlink(tail);
     }
+    return tail;
 }
 
 @ @c