[vte/wip/egmont/bidi: 9/29] emulation: Track BiDi parameters



commit 31ad1eb8152a0e02e0944519bf8285b884bac7d5
Author: Egmont Koblinger <egmont gmail com>
Date:   Fri May 31 19:03:56 2019 +0200

    emulation: Track BiDi parameters
    
    https://gitlab.gnome.org/GNOME/vte/issues/53

 src/debug.cc         |   1 +
 src/debug.h          |   1 +
 src/modes-ecma.hh    |  18 +++++++-
 src/modes-private.hh |  32 ++++++++++++++
 src/modes.hh         |   4 +-
 src/parser-cmd.hh    |   4 +-
 src/parser-csi.hh    |   4 +-
 src/ring.cc          |  11 +++--
 src/ring.hh          |   9 ++--
 src/vte.cc           |  94 +++++++++++++++++++++++++++++++++++++--
 src/vteinternal.hh   |  15 +++++++
 src/vterowdata.cc    |   3 ++
 src/vterowdata.hh    |   3 +-
 src/vteseq.cc        | 122 ++++++++++++++++++++++++++++++++++++++++++++-------
 14 files changed, 286 insertions(+), 35 deletions(-)
---
diff --git a/src/debug.cc b/src/debug.cc
index 5d88833b..afbd7413 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -57,6 +57,7 @@ _vte_debug_init(void)
     { "hyperlink",    VTE_DEBUG_HYPERLINK    },
     { "modes",        VTE_DEBUG_MODES        },
     { "emulation",    VTE_DEBUG_EMULATION    },
+    { "bidi",         VTE_DEBUG_BIDI         },
   };
 
   _vte_debug_flags = g_parse_debug_string (g_getenv("VTE_DEBUG"),
diff --git a/src/debug.h b/src/debug.h
index 41c3665d..92d9d0f9 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -64,6 +64,7 @@ typedef enum {
         VTE_DEBUG_HYPERLINK     = 1 << 24,
         VTE_DEBUG_MODES         = 1 << 25,
         VTE_DEBUG_EMULATION     = 1 << 26,
+        VTE_DEBUG_BIDI          = 1 << 27,
 } VteDebugFlags;
 
 void _vte_debug_init(void);
diff --git a/src/modes-ecma.hh b/src/modes-ecma.hh
index 617d2985..3c862be7 100644
--- a/src/modes-ecma.hh
+++ b/src/modes-ecma.hh
@@ -38,6 +38,20 @@
  */
 MODE(IRM,  4)
 
+/*
+ * BDSM - Bi-Directional Support Mode
+ *
+ * Reset state is explicit mode, set state is implicit mode
+ *
+ * References: ECMA-48
+ *             ECMA TR/53
+ *             Terminal-wg/bidi
+ *
+ * Default in ECMA: reset
+ * Default in Terminal-wg/bidi and VTE: set
+ */
+MODE(BDSM, 8)
+
 /*
  * SRM - local echo send/receive mode
  * If reset, characters entered by the keyboard are shown on the
@@ -59,8 +73,8 @@ MODE_FIXED(CRM,   3, ALWAYS_RESET)
 MODE_FIXED(SRTM,  5, ALWAYS_RESET)
 MODE_FIXED(ERM,   6, ALWAYS_RESET)
 MODE_FIXED(VEM,   7, ALWAYS_RESET)
-MODE_FIXED(BDSM,  8, ALWAYS_RESET)
-MODE_FIXED(DCSM,  9, ALWAYS_RESET)
+/* DCSM defaults to RESET in ECMA, forced to SET in Terminal-wg/bidi */
+MODE_FIXED(DCSM,  9, ALWAYS_SET)
 MODE_FIXED(HEM,  10, ALWAYS_RESET)
 MODE_FIXED(PUM,  11, ALWAYS_RESET) /* ECMA-48 § F.4.1 Deprecated */
 MODE_FIXED(FEAM, 13, ALWAYS_RESET)
diff --git a/src/modes-private.hh b/src/modes-private.hh
index eb313823..7fa7049c 100644
--- a/src/modes-private.hh
+++ b/src/modes-private.hh
@@ -142,6 +142,38 @@ MODE(XTERM_READLINE_BRACKETED_PASTE, 2004)
 
 MODE(URXVT_MOUSE_EXT, 1015)
 
+/* VTE */
+
+/*
+ * Whether box drawing characters in the U+2500..U+257F range
+ * are to be mirrored in RTL context.
+ *
+ * The (temporary) choice of number 2500 is a misuse of hex 2500
+ * as a decimal number, but is supposed to be easily memorable.
+ *
+ * Reference: Terminal-wg/bidi
+ */
+MODE(VTE_BOX_DRAWING_MIRROR, 2500)
+
+/*
+ * Whether BiDi paragraph direction is autodetected.
+ *
+ * The number choice is temporary.
+ *
+ * Reference: Terminal-wg/bidi
+ */
+MODE(VTE_BIDI_AUTO, 2501)
+
+/*
+ * Whether to swap the Left and Right arrow keys if the cursor
+ * stands over an RTL paragraphs.
+ *
+ * The number choice is not necessarily final.
+ *
+ * Reference: Terminal-wg/bidi
+ */
+MODE(VTE_BIDI_SWAP_ARROW_KEYS, 1243)
+
 /* Not supported modes: */
 
 /* DEC */
diff --git a/src/modes.hh b/src/modes.hh
index 47d0b415..af218622 100644
--- a/src/modes.hh
+++ b/src/modes.hh
@@ -170,7 +170,8 @@ public:
 #undef MODE
 #undef MODE_FIXED
 
-        constexpr ECMA() : Self{eSRM} { }
+        constexpr ECMA() : Self{eBDSM,
+                                eSRM} { }
 
 }; // class ECMA
 
@@ -226,6 +227,7 @@ public:
 
         constexpr Private() : Self{eDEC_AUTOWRAP,
                                    eDEC_TEXT_CURSOR,
+                                   eVTE_BIDI_SWAP_ARROW_KEYS,
                                    eXTERM_ALTBUF_SCROLL,
                                    eXTERM_META_SENDS_ESCAPE} { }
 
diff --git a/src/parser-cmd.hh b/src/parser-cmd.hh
index 6fcaacc2..c562d7c0 100644
--- a/src/parser-cmd.hh
+++ b/src/parser-cmd.hh
@@ -104,11 +104,13 @@ _VTE_CMD(RM_DEC) /* reset mode dec */
 _VTE_CMD(RM_ECMA) /* reset mode ecma */
 _VTE_CMD(SCORC) /* SCO restore cursor */
 _VTE_CMD(SCOSC) /* SCO save cursor */
+_VTE_CMD(SCP) /* select character path */
 _VTE_CMD(SD) /* scroll down */
 _VTE_CMD(SD_OR_XTERM_IHMT) /* scroll down or xterm initiate highlight mouse tracking */
 _VTE_CMD(SGR) /* select graphics rendition */
 _VTE_CMD(SM_DEC) /* set mode dec */
 _VTE_CMD(SM_ECMA) /* set mode ecma */
+_VTE_CMD(SPD) /* select presentation directions */
 _VTE_CMD(SS2) /* single shift 2 */
 _VTE_CMD(SS3) /* single shift 3 */
 _VTE_CMD(SUB) /* substitute */
@@ -276,7 +278,6 @@ _VTE_NOP(RLOGIN_MML) /* RLogin music macro language */
 _VTE_NOP(SACS) /* set additional character separation */
 _VTE_NOP(SAPV) /* select alternative presentation variants */
 _VTE_NOP(SCO) /* select character orientation */
-_VTE_NOP(SCP) /* select character path */
 _VTE_NOP(SCS) /* set character spacing */
 _VTE_NOP(SDS) /* start directed string */
 _VTE_NOP(SEE) /* select editing extent */
@@ -289,7 +290,6 @@ _VTE_NOP(SL) /* scroll left */
 _VTE_NOP(SLS) /* set line spacing */
 _VTE_NOP(SOH) /* start of heading */
 _VTE_NOP(SPA) /* start of protected area */
-_VTE_NOP(SPD) /* select presentation directions */
 _VTE_NOP(SPH) /* set page home */
 _VTE_NOP(SPI) /* spacing increment */
 _VTE_NOP(SPL) /* set page limit */
diff --git a/src/parser-csi.hh b/src/parser-csi.hh
index 410d533f..53e1f1f8 100644
--- a/src/parser-csi.hh
+++ b/src/parser-csi.hh
@@ -59,7 +59,7 @@ _VTE_NOQ(SEE,                    CSI,    'Q',  NONE,  0, NONE     ) /* select ed
 _VTE_NOQ(PPR,                    CSI,    'Q',  NONE,  1, SPACE    ) /* page-position-relative */
 _VTE_NOQ(PPB,                    CSI,    'R',  NONE,  1, SPACE    ) /* page-position-backward */
 _VTE_SEQ(SU,                     CSI,    'S',  NONE,  0, NONE     ) /* scroll-up */
-_VTE_NOQ(SPD,                    CSI,    'S',  NONE,  1, SPACE    ) /* select presentation directions */
+_VTE_SEQ(SPD,                    CSI,    'S',  NONE,  1, SPACE    ) /* select presentation directions */
 _VTE_NOQ(XTERM_SGFX,             CSI,    'S',  WHAT,  0, NONE     ) /* xterm-sixel-graphics */
 _VTE_SEQ(SD_OR_XTERM_IHMT,       CSI,    'T',  NONE,  0, NONE     ) /* scroll-down or 
xterm-initiate-highlight-mouse-tracking */
 _VTE_NOQ(DTA,                    CSI,    'T',  NONE,  1, SPACE    ) /* dimension text area */
@@ -114,7 +114,7 @@ _VTE_NOQ(MC_DEC,                 CSI,    'i',  WHAT,  0, NONE     ) /* media-cop
 _VTE_NOQ(HPB,                    CSI,    'j',  NONE,  0, NONE     ) /* horizontal position backward */
 _VTE_NOQ(SPL,                    CSI,    'j',  NONE,  1, SPACE    ) /* set page limit */
 _VTE_NOQ(VPB,                    CSI,    'k',  NONE,  0, NONE     ) /* line position backward */
-_VTE_NOQ(SCP,                    CSI,    'k',  NONE,  1, SPACE    ) /* select character path */
+_VTE_SEQ(SCP,                    CSI,    'k',  NONE,  1, SPACE    ) /* select character path */
 _VTE_SEQ(RM_ECMA,                CSI,    'l',  NONE,  0, NONE     ) /* reset-mode-ecma */
 _VTE_SEQ(RM_DEC,                 CSI,    'l',  WHAT,  0, NONE     ) /* reset-mode-dec */
 _VTE_SEQ(SGR,                    CSI,    'm',  NONE,  0, NONE     ) /* select-graphics-rendition */
diff --git a/src/ring.cc b/src/ring.cc
index d7a3bde1..a121e3e8 100644
--- a/src/ring.cc
+++ b/src/ring.cc
@@ -373,6 +373,7 @@ Ring::freeze_row(row_t position,
        if (!row->attr.soft_wrapped)
                g_string_append_c (buffer, '\n');
        record.soft_wrapped = row->attr.soft_wrapped;
+       record.bidi_flags = row->attr.bidi_flags;
 
        _vte_stream_append(m_text_stream, buffer->str, buffer->len);
        append_row_record(&record, position);
@@ -435,6 +436,7 @@ Ring::thaw_row(row_t position,
                 g_string_truncate (buffer, buffer->len - 1);
        else
                row->attr.soft_wrapped = TRUE;
+       row->attr.bidi_flags = records[0].bidi_flags;
 
        p = buffer->str;
        end = p + buffer->len;
@@ -849,7 +851,7 @@ Ring::shrink(row_t max_len)
  * Return: the newly added row.
  */
 VteRowData*
-Ring::insert(row_t position)
+Ring::insert(row_t position, guint8 bidi_flags)
 {
        row_t i;
        VteRowData* row, tmp;
@@ -872,6 +874,7 @@ Ring::insert(row_t position)
 
        row = get_writable_index(position);
        _vte_row_data_clear (row);
+       row->attr.bidi_flags = bidi_flags;
        m_end++;
 
        maybe_freeze_one_row();
@@ -921,9 +924,9 @@ Ring::remove(row_t position)
  * Return: the newly added row.
  */
 VteRowData*
-Ring::append()
+Ring::append(guint8 bidi_flags)
 {
-       return insert(next());
+       return insert(next(), bidi_flags);
 }
 
 
@@ -1187,6 +1190,7 @@ Ring::rewrap(column_t columns,
                /* Find the boundaries of the next paragraph */
                gboolean prev_record_was_soft_wrapped = FALSE;
                gboolean paragraph_is_ascii = TRUE;
+               guint8 paragraph_bidi_flags = old_record.bidi_flags;
                gsize text_offset = paragraph_start_text_offset;
                RowRecord new_record;
                column_t col = 0;
@@ -1234,6 +1238,7 @@ Ring::rewrap(column_t columns,
                new_record.text_start_offset = text_offset;
                new_record.attr_start_offset = attr_offset;
                new_record.is_ascii = paragraph_is_ascii;
+               new_record.bidi_flags = paragraph_bidi_flags;
 
                while (paragraph_len > 0) {
                        /* Wrap one continuous run of identical attributes within the paragraph. */
diff --git a/src/ring.hh b/src/ring.hh
index 1b17ca7a..06ed22fe 100644
--- a/src/ring.hh
+++ b/src/ring.hh
@@ -85,8 +85,8 @@ public:
         row_t reset();
         void resize(row_t max_rows = kDefaultMaxRows);
         void shrink(row_t max_len = kDefaultMaxRows);
-        VteRowData* insert(row_t position);
-        VteRowData* append();
+        VteRowData* insert(row_t position, guint8 bidi_flags);
+        VteRowData* append(guint8 bidi_flags);
         void remove(row_t position);
         void drop_scrollback(row_t position);
         void set_visible_rows(row_t rows);
@@ -120,6 +120,7 @@ private:
                 size_t attr_start_offset;  /* offset of the first character's attributes */
                 int soft_wrapped: 1;      /* end of line is not '\n' */
                 int is_ascii: 1;          /* for rewrapping speedup: guarantees that line contains 32..126 
bytes only. Can be 0 even when ascii only. */
+                guint8 bidi_flags: 4;
         } RowRecord;
 
         static_assert(std::is_pod<RowRecord>::value, "Ring::RowRecord is not POD");
@@ -248,8 +249,8 @@ static inline auto _vte_ring_get_hyperlink_at_position (VteRing *ring, gulong po
 static inline long _vte_ring_reset (VteRing *ring) { return ring->reset(); }
 static inline void _vte_ring_resize (VteRing *ring, gulong max_rows) { ring->resize(max_rows); }
 static inline void _vte_ring_shrink (VteRing *ring, gulong max_len) { ring->shrink(max_len); }
-static inline VteRowData *_vte_ring_insert (VteRing *ring, gulong position) { return ring->insert(position); 
}
-static inline VteRowData *_vte_ring_append (VteRing *ring) { return ring->append(); }
+static inline VteRowData *_vte_ring_insert (VteRing *ring, gulong position, guint8 bidi_flags) { return 
ring->insert(position, bidi_flags); }
+static inline VteRowData *_vte_ring_append (VteRing *ring, guint8 bidi_flags) { return 
ring->append(bidi_flags); }
 static inline void _vte_ring_remove (VteRing *ring, gulong position) { ring->remove(position); }
 static inline void _vte_ring_drop_scrollback (VteRing *ring, gulong position) { 
ring->drop_scrollback(position); }
 static inline void _vte_ring_set_visible_rows (VteRing *ring, gulong rows) { ring->set_visible_rows(rows); }
diff --git a/src/vte.cc b/src/vte.cc
index b02b673d..a76ffd1c 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -139,11 +139,11 @@ Terminal::ring_insert(vte::grid::row_t position,
         bool const not_default_bg = (m_fill_defaults.attr.back() != VTE_DEFAULT_BG);
 
        while (G_UNLIKELY (_vte_ring_next (ring) < position)) {
-               row = _vte_ring_append (ring);
+               row = _vte_ring_append (ring, get_bidi_flags());
                 if (not_default_bg)
                         _vte_row_data_fill (row, &m_fill_defaults, m_column_count);
        }
-       row = _vte_ring_insert (ring, position);
+       row = _vte_ring_insert (ring, position, get_bidi_flags());
         if (fill && not_default_bg)
                 _vte_row_data_fill (row, &m_fill_defaults, m_column_count);
        return row;
@@ -487,7 +487,8 @@ Terminal::set_hard_wrapped(vte::grid::row_t row)
         row_data->attr.soft_wrapped = false;
 }
 
-/* Sets the line ending to soft wrapped (overflow to the next line). */
+/* Sets the line ending to soft wrapped (overflow to the next line).
+ * Also makes sure that the joined new paragraph receives the first one's bidi flags. */
 void
 Terminal::set_soft_wrapped(vte::grid::row_t row)
 {
@@ -497,7 +498,24 @@ Terminal::set_soft_wrapped(vte::grid::row_t row)
         VteRowData *row_data = find_row_data_writable(row);
         g_assert(row_data != nullptr);
 
+        if (row_data->attr.soft_wrapped)
+                return;
+
         row_data->attr.soft_wrapped = true;
+
+        /* Each paragraph has to have consistent bidi flags across all of its rows.
+         * Spread the first paragraph's flags across the second one (if they differ). */
+        guint8 bidi_flags = row_data->attr.bidi_flags;
+        vte::grid::row_t i = row + 1;
+        row_data = find_row_data_writable(i);
+        if (row_data != nullptr && row_data->attr.bidi_flags != bidi_flags) {
+                do {
+                        row_data->attr.bidi_flags = bidi_flags;
+                        if (!row_data->attr.soft_wrapped)
+                                break;
+                        row_data = find_row_data_writable(++i);
+                } while (row_data != nullptr);
+        }
 }
 
 /* Determine the width of the portion of the preedit string which lies
@@ -2894,6 +2912,8 @@ Terminal::insert_char(gunichar c,
                        row = ensure_row();
                         set_soft_wrapped(m_screen->cursor.row);
                         cursor_down(false);
+                        ensure_row();
+                        apply_bidi_attributes(m_screen->cursor.row, row->attr.bidi_flags, VTE_BIDI_ALL);
                } else {
                        /* Don't wrap, stay at the rightmost column. */
                         col = m_screen->cursor.col =
@@ -3030,6 +3050,72 @@ not_inserted:
         m_line_wrapped = line_wrapped;
 }
 
+guint8
+Terminal::get_bidi_flags()
+{
+        return (m_modes_ecma.BDSM() ? VTE_BIDI_IMPLICIT : 0) |
+               (m_bidi_rtl ? VTE_BIDI_RTL : 0) |
+               (m_modes_private.VTE_BIDI_AUTO() ? VTE_BIDI_AUTO : 0) |
+               (m_modes_private.VTE_BOX_DRAWING_MIRROR() ? VTE_BIDI_BOX_MIRROR : 0);
+}
+
+/* Apply the specified BiDi parameters on the paragraph beginning at the specified line. */
+void
+Terminal::apply_bidi_attributes(vte::grid::row_t row, guint8 bidi_flags, guint8 bidi_flags_mask)
+{
+        VteRowData *rowdata;
+
+        bidi_flags &= bidi_flags_mask;
+
+        while (true) {
+                rowdata = _vte_ring_index_writable (m_screen->row_data, row);
+                if (rowdata == nullptr)
+                        return;
+
+                _vte_debug_print(VTE_DEBUG_BIDI,
+                                 "Applying BiDi parameters on row %ld.\n", row);
+
+                rowdata->attr.bidi_flags &= ~bidi_flags_mask;
+                rowdata->attr.bidi_flags |= bidi_flags;
+
+                invalidate_row(row);
+                if (!rowdata->attr.soft_wrapped)
+                        return;
+                row++;
+        }
+}
+
+/* Apply the current BiDi parameters covered by bidi_flags_mask on the current paragraph
+ * if the cursor is at the first position of this paragraph. */
+void
+Terminal::maybe_apply_bidi_attributes(guint8 bidi_flags_mask)
+{
+        _vte_debug_print(VTE_DEBUG_BIDI,
+                         "Maybe applying BiDi parameters on current paragraph.\n");
+
+        if (m_screen->cursor.col != 0) {
+                _vte_debug_print(VTE_DEBUG_BIDI,
+                                 "No, cursor not in first column.\n");
+                return;
+        }
+
+        auto row = m_screen->cursor.row;
+
+        if (row > _vte_ring_delta (m_screen->row_data)) {
+                const VteRowData *rowdata = _vte_ring_index (m_screen->row_data, row - 1);
+                if (rowdata != nullptr && rowdata->attr.soft_wrapped) {
+                        _vte_debug_print(VTE_DEBUG_BIDI,
+                                         "No, we're not after a hard wrap.\n");
+                        return;
+                }
+        }
+
+        _vte_debug_print(VTE_DEBUG_BIDI,
+                         "Yes, applying.\n");
+
+        apply_bidi_attributes (row, get_bidi_flags(), bidi_flags_mask);
+}
+
 static void
 reaper_child_exited_cb(VteReaper *reaper,
                        int ipid,
@@ -9946,6 +10032,8 @@ Terminal::reset(bool clear_tabstops,
         /* Reset the saved cursor. */
         save_cursor(&m_normal_screen);
         save_cursor(&m_alternate_screen);
+        /* BiDi */
+        m_bidi_rtl = FALSE;
        /* Cause everything to be redrawn (or cleared). */
        invalidate_all();
 
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 7d4815e0..d1878f9a 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -86,6 +86,14 @@ enum {
         VTE_SGR_COLOR_SPEC_LEGACY = 5
 };
 
+enum {
+        VTE_BIDI_IMPLICIT   = 1 << 0,
+        VTE_BIDI_RTL        = 1 << 1,
+        VTE_BIDI_AUTO       = 1 << 2,
+        VTE_BIDI_BOX_MIRROR = 1 << 3,
+        VTE_BIDI_ALL        = (1 << 4) - 1,
+};
+
 struct vte_regex_and_flags {
         VteRegex *regex;
         guint32 match_flags;
@@ -608,6 +616,9 @@ public:
         const char *m_hyperlink_hover_uri; /* data is owned by the ring */
         long m_hyperlink_auto_id;
 
+        /* BiDi parameters outside of ECMA and DEC private modes */
+        guint m_bidi_rtl : 1;
+
 public:
 
         // FIXMEchpe inline!
@@ -660,6 +671,10 @@ public:
         void invalidate_match_span();
         void invalidate_all();
 
+        guint8 get_bidi_flags();
+        void apply_bidi_attributes(vte::grid::row_t row, guint8 bidi_flags, guint8 bidi_flags_mask);
+        void maybe_apply_bidi_attributes(guint8 bidi_flags_mask);
+
         void reset_update_rects();
         bool invalidate_dirty_rects_and_process_updates();
         void time_process_incoming();
diff --git a/src/vterowdata.cc b/src/vterowdata.cc
index 88edba1a..107a1f1b 100644
--- a/src/vterowdata.cc
+++ b/src/vterowdata.cc
@@ -82,7 +82,10 @@ _vte_cells_free (VteCells *cells)
 void
 _vte_row_data_init (VteRowData *row)
 {
+       // FIXME pass the bidi attrs to this method?
+//     guint8 bidi_flags_save = row->attr.bidi_flags;
        memset (row, 0, sizeof (*row));
+//     row->attr.bidi_flags = bidi_flags_save;
 }
 
 void
diff --git a/src/vterowdata.hh b/src/vterowdata.hh
index 9d4b2767..12cbf311 100644
--- a/src/vterowdata.hh
+++ b/src/vterowdata.hh
@@ -36,7 +36,8 @@ G_BEGIN_DECLS
  */
 
 typedef struct _VteRowAttr {
-       guint8 soft_wrapped: 1;
+        guint8 soft_wrapped  : 1;
+        guint8 bidi_flags    : 4;
 } VteRowAttr;
 static_assert(sizeof (VteRowAttr) == 1, "VteRowAttr has wrong size");
 
diff --git a/src/vteseq.cc b/src/vteseq.cc
index d12ee329..1a80ea74 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -315,6 +315,7 @@ Terminal::clear_current_line()
                /* Add enough cells to the end of the line to fill out the row. */
                 _vte_row_data_fill (rowdata, &m_fill_defaults, m_column_count);
                 set_hard_wrapped(m_screen->cursor.row);
+                rowdata->attr.bidi_flags = get_bidi_flags();
                /* Repaint this row. */
                 invalidate_row(m_screen->cursor.row);
        }
@@ -342,6 +343,7 @@ Terminal::clear_above_current()
                        /* Add new cells until we fill the row. */
                         _vte_row_data_fill (rowdata, &m_fill_defaults, m_column_count);
                         set_hard_wrapped(i);
+                        rowdata->attr.bidi_flags = get_bidi_flags();
                        /* Repaint the row. */
                         invalidate_row(i);
                }
@@ -469,6 +471,13 @@ Terminal::set_mode_ecma(vte::parser::Sequence const& seq,
                         continue;
 
                 m_modes_ecma.set(mode, set);
+
+                if (mode == m_modes_ecma.eBDSM) {
+                        _vte_debug_print(VTE_DEBUG_BIDI,
+                                         "BiDi %s mode\n",
+                                         set ? "implicit" : "explicit");
+                        maybe_apply_bidi_attributes(VTE_BIDI_IMPLICIT);
+                }
         }
 }
 
@@ -597,6 +606,20 @@ Terminal::set_mode_private(int mode,
                         feed_focus_event_initial();
                 break;
 
+        case vte::terminal::modes::Private::eVTE_BOX_DRAWING_MIRROR:
+                _vte_debug_print(VTE_DEBUG_BIDI,
+                                 "BiDi box drawing mirroring %s\n",
+                                 set ? "enabled" : "disabled");
+                maybe_apply_bidi_attributes(VTE_BIDI_BOX_MIRROR);
+                break;
+
+        case vte::terminal::modes::Private::eVTE_BIDI_AUTO:
+                        _vte_debug_print(VTE_DEBUG_BIDI,
+                                         "BiDi dir autodetection %s\n",
+                                         set ? "enabled" : "disabled");
+                maybe_apply_bidi_attributes(VTE_BIDI_AUTO);
+                break;
+
         default:
                 break;
         }
@@ -745,6 +768,8 @@ Terminal::clear_below_current()
                         _vte_row_data_fill(rowdata, &m_fill_defaults, m_column_count);
                }
                 set_hard_wrapped(i);
+               if (i > m_screen->cursor.row)
+                        rowdata->attr.bidi_flags = get_bidi_flags();
                /* Repaint this row. */
                 invalidate_row(i);
        }
@@ -1023,6 +1048,7 @@ Terminal::line_feed()
 {
         ensure_cursor_is_onscreen();
         cursor_down(true);
+        maybe_apply_bidi_attributes(VTE_BIDI_ALL);
 }
 
 void
@@ -4746,7 +4772,7 @@ Terminal::DECSTBM(vte::parser::Sequence const& seq)
        } else {
                /* Maybe extend the ring -- bug 710483 */
                 while (_vte_ring_next(m_screen->row_data) < m_screen->insert_delta + m_row_count)
-                        _vte_ring_insert(m_screen->row_data, _vte_ring_next(m_screen->row_data));
+                        _vte_ring_insert(m_screen->row_data, _vte_ring_next(m_screen->row_data), 
get_bidi_flags());
        }
 
         home_cursor();
@@ -4955,8 +4981,11 @@ Terminal::DL(vte::parser::Sequence const& seq)
          * DL - delete-line
          * Delete lines starting from the active line (presentation).
          *
-         * This function is affected by the DCSM, TSM and VEM modes,
-         * and the SLH and SEE functions.
+         * Depending on DCSM, this function works on the presentation
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
+         *
+         * Also affected by TSM and VEM modes, and the SLH and SEE
+         * functions.
          *
          * Arguments:
          *  args[0]: number of lines to delete
@@ -4965,6 +4994,7 @@ Terminal::DL(vte::parser::Sequence const& seq)
          *   args[0]: 1
          *
          * References: ECMA-48 § 8.3.32
+         *             Terminal-wg/bidi
          */
 #if 0
         unsigned int num = 1;
@@ -5291,9 +5321,10 @@ Terminal::EA(vte::parser::Sequence const& seq)
          * ERM is reset, erases all areas.
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.37
+         *             Terminal-wg/bidi
          */
 
         switch (seq.collect1(0)) {
@@ -5324,9 +5355,10 @@ Terminal::ECH(vte::parser::Sequence const& seq)
          * ERM is reset, erases all characters.
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.38
+         *             Terminal-wg/bidi
          */
 #if 0
         unsigned int num = 1;
@@ -5375,10 +5407,11 @@ Terminal::ED(vte::parser::Sequence const& seq)
          * ERM is reset, erases all characters.
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.39
          *             VT525
+         *             Terminal-wg/bidi
          */
 
         erase_in_display(seq);
@@ -5406,9 +5439,10 @@ Terminal::EF(vte::parser::Sequence const& seq)
          * ERM is reset, erases all characters.
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.40
+         *             Terminal-wg/bidi
          */
 }
 
@@ -5435,10 +5469,11 @@ Terminal::EL(vte::parser::Sequence const& seq)
          * ERM is reset, erases all characters.
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.41
          *             VT525
+         *             Terminal-wg/bidi
          */
 
         erase_in_line(seq);
@@ -5890,12 +5925,13 @@ Terminal::ICH(vte::parser::Sequence const& seq)
          *   args[0]: 1
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
 
          * Also affected by HEM mode, and the SLH, and SEE functions.
          *
          * References: ECMA-48 §8.3.64
          *             VT525
+         *             Terminal-wg/bidi
          */
 #if 0
         unsigned int num = 1;
@@ -5973,12 +6009,13 @@ Terminal::IL(vte::parser::Sequence const& seq)
          *   args[0]: 1
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * Also affected by the TSM and VEM modes,
          * and the SLH and SEE functions.
          *
          * References: ECMA-48 § 8.3.67
+         *             Terminal-wg/bidi
          */
 #if 0
         unsigned int num = 1;
@@ -6906,19 +6943,43 @@ Terminal::SCP(vte::parser::Sequence const& seq)
          *
          * Arguments:
          *   args[0]: path
+         *     0 in Terminal-wg/bidi and VTE = terminal's default
          *     1 = LTR or TTB (for horizontal/vertical line orientation)
          *     2 = RTL or BTT (for horizontal/vertical line orientation)
          *   args[1]: effect
-         *     0 = implementation-defined
+         *     0 in ECMA = implementation-defined
+         *     0 in Terminal-wg/bidi and VTE = see Terminal-wg/bidi
          *     1 = ...
          *     2 = ...
          *
          * Defaults:
-         *   args[0]: no default
-         *   args[1]: no default
+         *   args[0] in ECMA: no default
+         *   args[1] in ECMA: no default
+         *   args[0] in Terminal-wg/bidi: 0
+         *   args[1] in Terminal-wg/bidi: 0
          *
          * References: ECMA-48 § 8.3.111
+         *             Terminal-wg/bidi
          */
+
+        auto const param = seq.collect1(0);
+        switch (param) {
+        case 1:
+                m_bidi_rtl = FALSE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: switch to LTR\n");
+                break;
+        case 2:
+                m_bidi_rtl = TRUE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: switch to RTL\n");
+                break;
+        default:
+                /* FIXME switch to the emulator's default */
+                m_bidi_rtl = FALSE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: default direction restored\n");
+                break;
+        }
+
+        maybe_apply_bidi_attributes(VTE_BIDI_RTL);
 }
 
 void
@@ -7260,9 +7321,10 @@ Terminal::SLH(vte::parser::Sequence const& seq)
          *   args[0]: no default
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.122
+         *             Terminal-wg/bidi
          */
 }
 
@@ -7279,9 +7341,10 @@ Terminal::SLL(vte::parser::Sequence const& seq)
          *   args[0]: no default
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.123
+         *             Terminal-wg/bidi
          */
 }
 
@@ -7386,7 +7449,30 @@ Terminal::SPD(vte::parser::Sequence const& seq)
          *   args[1]: 0
          *
          * References: ECMA-48 § 8.3.130
+         *             Terminal-wg/bidi
          */
+
+        auto const param = seq.collect1(0);
+        switch (param) {
+        case -1:
+        case 0:
+                m_bidi_rtl = FALSE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: switch to LTR\n");
+                break;
+        case 3:
+                m_bidi_rtl = TRUE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: switch to RTL\n");
+                break;
+        default:
+                /* FIXME switch to the emulator's default */
+                m_bidi_rtl = FALSE;
+                _vte_debug_print(VTE_DEBUG_BIDI, "BiDi: default direction restored\n");
+                break;
+        }
+
+        maybe_apply_bidi_attributes(VTE_BIDI_RTL);
+
+        /* FIXME maybe apply to all the onscreen lines? */
 }
 
 void
@@ -7402,9 +7488,10 @@ Terminal::SPH(vte::parser::Sequence const& seq)
          *   args[0]: no default
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.131
+         *             Terminal-wg/bidi
          */
 }
 
@@ -7440,9 +7527,10 @@ Terminal::SPL(vte::parser::Sequence const& seq)
          *   args[0]: no default
          *
          * Depending on DCSM, this function works on the presentation
-         * or data position.
+         * or data position. Terminal-wg/bidi forces DCSM to DATA.
          *
          * References: ECMA-48 § 8.3.133
+         *             Terminal-wg/bidi
          */
 }
 


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