diff --git a/src/attr.hh b/src/attr.hh
index 7288ed94..fda19b22 100644
--- a/src/attr.hh
+++ b/src/attr.hh
@@ -37,7 +37,12 @@
 #define VTE_ATTR_FRAGMENT_MASK         (VTE_ATTR_MASK(VTE_ATTR_FRAGMENT_SHIFT, VTE_ATTR_FRAGMENT_BITS))
 #define VTE_ATTR_FRAGMENT              (1U << VTE_ATTR_FRAGMENT_SHIFT)
 
-#define VTE_ATTR_BOLD_SHIFT            (VTE_ATTR_FRAGMENT_SHIFT + VTE_ATTR_FRAGMENT_BITS)
+#define VTE_ATTR_SPACING_MARK_SHIFT    (VTE_ATTR_FRAGMENT_SHIFT + VTE_ATTR_FRAGMENT_BITS)
+#define VTE_ATTR_SPACING_MARK_BITS     (1)
+#define VTE_ATTR_SPACING_MARK_MASK     (VTE_ATTR_MASK(VTE_ATTR_SPACING_MARK_SHIFT, VTE_ATTR_SPACING_MARK_BITS))
+#define VTE_ATTR_SPACING_MARK          (1U << VTE_ATTR_SPACING_MARK_SHIFT)
+
+#define VTE_ATTR_BOLD_SHIFT            (VTE_ATTR_SPACING_MARK_SHIFT + VTE_ATTR_SPACING_MARK_BITS)
 #define VTE_ATTR_BOLD_BITS             (1)
 #define VTE_ATTR_BOLD_MASK             (VTE_ATTR_MASK(VTE_ATTR_BOLD_SHIFT, VTE_ATTR_BOLD_BITS))
 #define VTE_ATTR_BOLD                  (1U << VTE_ATTR_BOLD_SHIFT)
diff --git a/src/cell.hh b/src/cell.hh
index db2042d0..16339ff4 100644
--- a/src/cell.hh
+++ b/src/cell.hh
@@ -126,6 +126,7 @@ typedef struct _VTE_GNUC_PACKED VteCellAttr {
 
         CELL_ATTR_UINT(columns, COLUMNS)
         CELL_ATTR_BOOL(fragment, FRAGMENT)
+        CELL_ATTR_BOOL(spacing_mark, SPACING_MARK)
         CELL_ATTR_BOOL(bold, BOLD)
         CELL_ATTR_BOOL(italic, ITALIC)
         CELL_ATTR_UINT(underline, UNDERLINE)
diff --git a/src/vte.cc b/src/vte.cc
index c8708048..48b455ad 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -2861,6 +2861,7 @@ Terminal::insert_char(gunichar c,
         attr = m_defaults.attr;
         attr.copy_colors(m_color_defaults.attr);
 	attr.set_columns(columns);
+        attr.set_spacing_mark(g_unichar_ismark(c));
 
 	{
 		VteCell *pcell = _vte_row_data_get_writable (row, col);
@@ -8827,8 +8828,9 @@ Terminal::draw_rows(VteScreen *screen_,
                                                      VTE_ATTR_OVERLINE_MASK) &&
                                  !nhyperlink) ||
                             cell->attr.fragment() ||
+                            cell->attr.spacing_mark() ||
                             cell->attr.invisible()) {
-                                /* Skip empty or fragment cell. */
+                                /* Skip empty or fragment or spacing mark cell. */
                                 continue;
                         }
 
@@ -8863,6 +8865,19 @@ Terminal::draw_rows(VteScreen *screen_,
                                 item_count = 0;
                         }
 
+                        /* Combine with subsequent spacing marks. */
+                        vteunistr c = cell->c;
+                        j = col + cell->attr.columns();
+                        while (j < m_column_count) {
+                                cell = _vte_row_data_get (row_data, j);
+                                if (cell && cell->attr.spacing_mark() && !cell->attr.fragment()) {
+                                        c = _vte_unistr_append_unistr (c, cell->c);
+                                        j += cell->attr.columns();
+                                } else {
+                                        break;
+                                }
+                        }
+
                         attr = nattr;
                         fore = nfore;
                         back = nback;
@@ -8871,8 +8886,8 @@ Terminal::draw_rows(VteScreen *screen_,
                         hilite = nhilite;
 
                         g_assert_cmpint (item_count, <, m_column_count);
-                        items[item_count].c = cell->c;
-                        items[item_count].columns = cell->attr.columns();
+                        items[item_count].c = c;
+                        items[item_count].columns = j - col;
                         items[item_count].x = col * column_width;
                         items[item_count].y = y;
                         item_count++;
diff --git a/src/vteunistr.cc b/src/vteunistr.cc
index 2e412e3e..69c47fe0 100644
--- a/src/vteunistr.cc
+++ b/src/vteunistr.cc
@@ -140,6 +140,19 @@ _vte_unistr_append_unichar (vteunistr s, gunichar c)
 	return ret;
 }
 
+vteunistr
+_vte_unistr_append_unistr (vteunistr s, vteunistr t)
+{
+        g_return_val_if_fail (s < unistr_next, s);
+        g_return_val_if_fail (t < unistr_next, s);
+        if (G_UNLIKELY (t >= VTE_UNISTR_START)) {
+                s = _vte_unistr_append_unistr (s, DECOMP_FROM_UNISTR (t).prefix);
+                return _vte_unistr_append_unichar (s, DECOMP_FROM_UNISTR (t).suffix);
+        } else {
+                return _vte_unistr_append_unichar (s, t);
+        }
+}
+
 gunichar
 _vte_unistr_get_base (vteunistr s)
 {
diff --git a/src/vteunistr.h b/src/vteunistr.h
index 04aa9fb6..9bde6b2c 100644
--- a/src/vteunistr.h
+++ b/src/vteunistr.h
@@ -57,6 +57,19 @@ typedef guint32 vteunistr;
 vteunistr
 _vte_unistr_append_unichar (vteunistr s, gunichar c);
 
+/**
+ * _vte_unistr_append_unistr:
+ * @s: a #vteunistr
+ * @t: another #vteunistr to append to @s
+ *
+ * Creates a vteunistr value for the string @s followed by the
+ * string @t.
+ *
+ * Returns: the new #vteunistr value
+ **/
+vteunistr
+_vte_unistr_append_unistr (vteunistr s, vteunistr t);
+
 gunichar
 _vte_unistr_get_base (vteunistr s);
 
