From ef68a3dd8ff259200ca7f088eecc9ce35e7ffe8f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 1 May 2016 03:35:26 +0200
Subject: Handled all width measures per view in a dedicated manager.

---
 ChangeLog                      |   28 +
 src/glibext/Makefile.am        |    6 +-
 src/glibext/gbufferline.c      | 1006 ++++++++---------
 src/glibext/gbufferline.h      |   50 +-
 src/glibext/gbufferview.c      | 1330 ++++++++++++++++++++++
 src/glibext/gbufferview.h      |  112 ++
 src/glibext/gcodebuffer.c      | 2425 ++++++++++------------------------------
 src/glibext/gcodebuffer.h      |   89 +-
 src/glibext/gwidthtracker.c    |  830 ++++++++++++++
 src/glibext/gwidthtracker.h    |   85 ++
 src/gtkext/gtkbufferview-int.h |    2 +-
 src/gtkext/gtkbufferview.c     |    8 +-
 src/gtkext/gtkbufferview.h     |    2 +-
 13 files changed, 3506 insertions(+), 2467 deletions(-)
 create mode 100644 src/glibext/gbufferview.c
 create mode 100644 src/glibext/gbufferview.h
 create mode 100644 src/glibext/gwidthtracker.c
 create mode 100644 src/glibext/gwidthtracker.h

diff --git a/ChangeLog b/ChangeLog
index 13320d9..605fa0a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+16-05-01  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/glibext/Makefile.am:
+	Add the 'gbufferview.[ch]' and 'gwidthtracker.[ch]' files to libglibext_la_SOURCES
+
+	* src/glibext/gbufferline.c:
+	* src/glibext/gbufferline.h:
+	Move and clean code.
+
+	* src/glibext/gbufferview.c:
+	* src/glibext/gbufferview.h:
+	New entries: extract all buffer view related functions into a separate file.
+
+	* src/glibext/gcodebuffer.c:
+	* src/glibext/gcodebuffer.h:
+	Move and clean code.
+
+	* src/glibext/gwidthtracker.c:
+	* src/glibext/gwidthtracker.h:
+	New entries: handle all width measures per view in a dedicated manager.
+
+	* src/gtkext/gtkbufferview-int.h:
+	* src/gtkext/gtkbufferview.c:
+	Remove the useless reference to the current buffer.
+
+	* src/gtkext/gtkbufferview.h:
+	Update the included header name.
+
 16-04-29  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/gtkext/gtkbufferview.c:
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index 192587d..a88b7d9 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -11,10 +11,12 @@ libglibext_la_SOURCES =					\
 	gbinportion.h gbinportion.c			\
 	gbufferline.h gbufferline.c			\
 	gbuffersegment.h gbuffersegment.c	\
+	gbufferview.h gbufferview.c			\
 	gcodebuffer.h gcodebuffer.c			\
 	gnhash.h gnhash.c					\
-	signal.h signal.c					\
-	proto.h
+	gwidthtracker.h gwidthtracker.c		\
+	proto.h								\
+	signal.h signal.c
 
 libglibext_la_LDFLAGS = 
 
diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c
index 65e73d0..7e518cc 100644
--- a/src/glibext/gbufferline.c
+++ b/src/glibext/gbufferline.c
@@ -911,304 +911,6 @@ void g_buffer_line_fill_for_instr(GBufferLine *line, MemoryDataSize psize, Memor
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line       = ligne à venir consulter.                        *
-*                max_widths = largeurs de colonne à respecter.                *
-*                display    = règles d'affichage des colonnes modulables.     *
-*                base       = position jusqu'au segment trouvé. [OUT]         *
-*                offset     = position à la colonne visée. [OUT]              *
-*                dir        = direction d'un éventuel déplacement en cours.   *
-*                force      = accepte les segments en bordure au pire.        *
-*                                                                             *
-*  Description : Donne le segment présent à une abscisse donnée.              *
-*                                                                             *
-*  Retour      : Segment trouvé ou NULL si hors borne.                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const gint max_widths[BLC_COUNT], const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force)
-{
-    GBufferSegment *result;                 /* Trouvaille à retourner      */
-    BufferLineColumn last;                  /* Dernière colonne remplie    */
-    gint last_base;                         /* Dernière abscisse associée  */
-    BufferLineColumn i;                     /* Boucle de parcours          */
-    gint width;                             /* Largeur d'une colonne donnée*/
-
-    gint limit;
-
-    gint consumed;                          /* Distance vers le segment    */
-    gint old_base;                          /* Somme de toutes les largeurs*/
-
-    result = NULL;
-
-    *base = 0;
-
-    last = BLC_COUNT;
-
-    //sum = 0;
-
-    printf("---------------\n");
-
-    /* On cible déjà la colonne idéale */
-
-    for (i = 0; i < BLC_COUNT; i++)
-    {
-        printf(" @ (%d) x=%d  width=%d  max=%d  display ? %d\n",
-               i, *offset, get_column_width(&line->columns[i]), max_widths[i], i < BLC_DISPLAY ? display[i] : true);
-
-
-        if (i < BLC_DISPLAY && !display[i]) continue;
-
-        /* Mémorisation de la dernière colonne contenant quelque chose... */
-        if (get_column_width(&line->columns[i]) > 0)
-        {
-            last = i;
-            last_base = *base;
-        }
-
-        if (i < line->merge_start)
-        {
-            width = g_buffer_line_compute_max_width(line, i, max_widths);
-
-            if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2;
-            else limit = width;
-
-            if (*offset <= limit) break;
-            else
-            {
-                *offset -= width + COL_MARGIN;
-                *base += width + COL_MARGIN;
-            }
-
-        }
-        else
-        {
-            width = get_column_width(&line->columns[i]);
-
-            if (*offset <= width) break;
-            else
-            {
-                *offset -= width;
-                *base += width;
-            }
-
-        }
-
-
-    }
-
-    printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT);
-
-
-    printf("                      last seen = %u\n", last);
-
-
-
-
-
-    if (i < BLC_COUNT)
-    {
-
-        printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i]));
-
-        if (get_column_width(&line->columns[i]) > 0)
-        {
-            /**
-             * Si la position était au milieu d'une marge, la sélection a pu pousser
-             * jusqu'à la colonne suivante, plus proche.
-             * Relativment à la base de cette dernière, la position est donc devenue négative.
-             */
-            if (*offset < 0) *offset = 0;
-
-            result = get_segment_at(&line->columns[i], offset, dir, &consumed);
-            *base += consumed;
-        }
-
-        /* La position fournie tombe dans une colonne vide ! */
-        else
-        {
-            if (force || get_column_width(&line->columns[i]) == 0)
-            {
-                result = NULL;
-                *offset = 0;
-
-                old_base = *base;
-
-                for (i++; i < BLC_COUNT && result == NULL; i++)
-                {
-                    printf(" -- update to col %u  -- x = %d\n", i, *offset);
-
-                    if ((i - 1) < line->merge_start)
-                    {
-                        width = g_buffer_line_compute_max_width(line, i - 1, max_widths);
-                        *base += (width + COL_MARGIN);
-                    }
-                    else
-                        *base += get_column_width(&line->columns[i - 1]);
-
-                    result = get_first_segment(&line->columns[i]);
-
-                }
-
-                printf(" -- final x = %d (result=%p)\n", *offset, result);
-
-                if (result == NULL)
-                {
-                    *base = old_base;
-                    goto use_right_border;
-                }
-
-            }
-
-        }
-
-    }
-
-    else /* if (i == BLC_COUNT) */
-    {
-        if (force && last != BLC_COUNT)
-        {
- use_right_border:
-
-            result = get_last_segment(&line->columns[last]);
-            *base = last_base;
-            *offset = get_column_width(&line->columns[last]);
-
-        }
-        else
-            result = NULL;
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line    = ligne à venir consulter.                           *
-*                target  = segment dont un voisin est à retourner.            *
-*                max_widths = largeurs de colonne à respecter.                *
-*                display = règles d'affichage des colonnes modulables.        *
-*                dir     = orientation des recherches.                        *
-*                offset  = décalage pour amener à l'extrémité nouvelle. [OUT] *
-*                                                                             *
-*  Description : Fournit le segment voisin d'un autre segment identifié.      *
-*                                                                             *
-*  Retour      : Segment trouvé dans la ligne ou NULL.                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBufferSegment *target, const gint max_widths[BLC_COUNT], const bool *display, GdkScrollDirection dir, gint *offset)
-{
-    GBufferSegment *result;                 /* Trouvaille à retourner      */
-    BufferLineColumn i;                     /* Boucle de parcours #1       */
-    bool displayed;                         /* Confort de lecture          */
-    BufferLineColumn k;                     /* Boucle de parcours #2       */
-
-    result = NULL;
-
-    /* Recherche dans la colonne de départ */
-
-    for (i = 0; i < BLC_COUNT; i++)
-        if (column_has_segment(&line->columns[i], target, NULL))
-            break;
-
-    if (i == BLC_COUNT) return NULL;
-
-    result = find_near_segment(&line->columns[i], target, dir);
-    if (result != NULL) return result;
-
-    /* Recherche dans la direction des colonnes voisines */
-
-    if (result == NULL)
-        switch (dir)
-        {
-            case GDK_SCROLL_LEFT:
-
-                /* Si on a atteint la première colonne sans trouver... */
-                if (i == 0) break;
-
-                /* On s'assure que la colonne précédente est visible et peuplée */
-                for (; i > BLC_FIRST && result == NULL; i--)
-                {
-                    displayed = (i <= BLC_DISPLAY ? display[i - 1] : true);
-
-                    if (displayed)
-                        result = get_last_segment(&line->columns[i - 1]);
-
-                }
-
-                break;
-
-            case GDK_SCROLL_RIGHT:
-
-                /* Si on a atteint la dernière colonne sans trouver... */
-                /*if (i == BLC_COUNT) break;*/
-
-                /* On s'assure que la colonne suivante est visible et peuplée */
-                for (; (i + 1) < BLC_COUNT && result == NULL; i++)
-                {
-                    displayed = ((i + 1) < BLC_DISPLAY ? display[i + 1] : true);
-
-                    if (displayed)
-                        result = get_first_segment(&line->columns[i + 1]);
-
-                }
-
-                break;
-
-        default:
-            break;
-
-    }
-
-    /* Calcul de la position finale */
-
-    if (result != NULL)
-    {
-        *offset = 0;
-
-        for (k = 0; k < i; k++)
-        {
-            displayed = (k < BLC_DISPLAY ? display[k] : true);
-
-            if (displayed)
-            {
-                *offset += g_buffer_line_compute_max_width(line, k, max_widths);
-                if (k < line->merge_start) *offset += COL_MARGIN;
-            }
-
-        }
-
-        switch (dir)
-        {
-            case GDK_SCROLL_LEFT:
-                *offset += get_column_width(&line->columns[i]);
-                break;
-
-            case GDK_SCROLL_RIGHT:
-                /**offset += 0;*/
-                break;
-
-            default:
-                break;
-
-        }
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
 *  Paramètres  : line   = ligne à venir consulter.                            *
 *                column = indice de la colonne visée par les recherches.      *
 *                                                                             *
@@ -1424,17 +1126,129 @@ char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, Bu
 
     }
 
-    return result;
+    return result;
+
+}
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line  = ligne à venir modifier.                              *
+*                first = première colonne à parcourir.                        *
+*                end   = colonne de fin de parcours.                          *
+*                                                                             *
+*  Description : Supprime du texte représenté par une ligne de tampon.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, BufferLineColumn end)
+{
+    BufferLineColumn i;                     /* Boucle de parcours #1       */
+
+    assert(first < end);
+
+    for (i = first; i < end; i++)
+        reset_column(&line->columns[i]);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line = ligne à venir consulter.                              *
+*                                                                             *
+*  Description : Fournit la colonne à partir de laquelle une fusion opère.    *
+*                                                                             *
+*  Retour      : Début de la première (et unique) zone globale.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
+{
+    return line->merge_start;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line  = ligne à venir compléter.                             *
+*                start = début de la première (et unique) zone globale.       *
+*                                                                             *
+*  Description : Définit la colonne à partir de laquelle la fusion opère.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start)
+{
+    if (start == BLC_LAST_USED)
+        line->merge_start = line->last_used;
+    else
+        line->merge_start = start;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line = ligne à venir compléter.                              *
+*                flag = propriété à intégrer.                                 *
+*                                                                             *
+*  Description : Ajoute une propriété particulière à une ligne donnée.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag)
+{
+    if ((line->flags & flag) == 0)
+    {
+        g_signal_emit_by_name(line, "flip-flag", line->flags, flag);
+
+        line->flags |= flag;
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line = ligne à venir consulter.                              *
+*                                                                             *
+*  Description : Renseigne sur les propriétés particulières liées à une ligne.*
+*                                                                             *
+*  Retour      : Propriétés intégrées.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line)
+{
+    return line->flags;
 
 }
 
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line  = ligne à venir modifier.                              *
-*                first = première colonne à parcourir.                        *
-*                end   = colonne de fin de parcours.                          *
+*  Paramètres  : line = ligne à venir compléter.                              *
+*                flag = propriété à supprimer.                                *
 *                                                                             *
-*  Description : Supprime du texte représenté par une ligne de tampon.        *
+*  Description : Retire une propriété particulière à une ligne donnée.        *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -1442,24 +1256,27 @@ char *g_buffer_line_get_text(const GBufferLine *line, BufferLineColumn first, Bu
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, BufferLineColumn end)
+void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag)
 {
-    BufferLineColumn i;                     /* Boucle de parcours #1       */
+    if ((line->flags & flag) != 0)
+    {
+        g_signal_emit_by_name(line, "flip-flag", line->flags, flag);
 
-    assert(first < end);
+        line->flags &= ~flag;
 
-    for (i = first; i < end; i++)
-        reset_column(&line->columns[i]);
+    }
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line    = ligne à venir consulter/compléter.                 *
-*                manager = ligne de départ d'un groupe de ligne.              *
+*  Paramètres  : line    = ligne de texte à manipuler.                        *
+*                ctx     = éléments à disposition pour l'exportation.         *
+*                type    = type d'exportation attendue.                       *
+*                display = règles d'affichage des colonnes modulables.        *
 *                                                                             *
-*  Description : Retient les largeurs d'une ligne si maximales.               *
+*  Description : Exporte la ligne de texte représentée.                       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -1467,40 +1284,99 @@ void g_buffer_line_delete_text(GBufferLine *line, BufferLineColumn first, Buffer
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager)
+void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display)
 {
     BufferLineColumn i;                     /* Boucle de parcours          */
-    GBufferLine *old;                       /* Ancienne ligne associée     */
-    gint merged_width;                      /* Largeur cumulée avant fusion*/
-    gint width;                             /* Largeur d'une colonne       */
+    int col_span;                           /* Fusion de colonnes ?        */
 
-    /* Réinitialisation ? */
+    switch (type)
+    {
+        case BET_HTML:
+            dprintf(ctx->fd, "\t<TR>\n");
+            break;
+        default:
+            break;
+    }
 
-    if (line == manager)
+    for (i = 0; i < BLC_COUNT; i++)
     {
-        assert(line->flags & BLF_WIDTH_MANAGER);
+        if (i < BLC_DISPLAY && !display[i]) continue;
+
+        switch (type)
+        {
+            case BET_TEXT:
+                if (i > 0) dprintf(ctx->fd, "%s", ctx->sep);
+                break;
+            default:
+                break;
+        }
+
+        /**
+         * Pour la signification des différentes valeurs assignées,
+         * se référer au code de export_segments_of_column().
+         *
+         * En gros :
+         *   - 1  = rien de spécial.
+         *   - >1 = il s'agit de la première cellule fusionnée de la ligne.
+         *   - 0  = fusion déjà faite, on ne peut que rajouter du contenu dedans.
+         *   - <1 = il s'agit de la dernière cellule fusionnée de la ligne.
+         *
+         * On considère qu'une fusion ne peut pas se réaliser sur la dernière
+         * cellule uniquement (ce qui a du sens : c'est inutile).
+         */
+
+        if (i < line->merge_start)
+            col_span = 1;
 
-        for (i = 0; i < BLC_COUNT; i++)
-            line->max_widths[i] = 0;
+        else if (i == line->merge_start)
+            col_span = BLC_COUNT - i;
+
+        else
+            col_span = ((i + 1) == BLC_COUNT ? -1 : 0);
 
-        line->merged_width = 0;
+        export_segments_of_column(&line->columns[i], ctx, type, col_span);
 
     }
-    else
+
+    switch (type)
     {
-        assert((line->flags & BLF_WIDTH_MANAGER) == 0);
+        case BET_TEXT:
+            dprintf(ctx->fd, "\n");
+            break;
+        case BET_HTML:
+            dprintf(ctx->fd, "</TR>\n");
+            break;
+        default:
+            break;
+    }
 
-        old = line->manager;
+}
 
-        g_object_ref(G_OBJECT(manager));
-        line->manager = manager;
 
-        if (old != NULL)
-            g_object_unref(G_OBJECT(old));
 
-    }
+/*----------------------------------------------------------------------------------- */
+/*                         MANIPULATION DES LARGEURS REQUISES                         */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line    = ligne à venir consulter.                           *
+*                summary = largeurs maximales à faire évoluer.                *
+*                                                                             *
+*  Description : Fait remonter les largeurs requises par une ligne donnée.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    /* Mises à jour */
+void g_buffer_line_collect_widths(GBufferLine *line, line_width_summary *summary)
+{
+    gint merged_width;                      /* Largeur cumulée avant fusion*/
+    BufferLineColumn i;                     /* Boucle de parcours          */
+    gint width;                             /* Largeur d'une colonne       */
 
     merged_width = 0;
 
@@ -1509,7 +1385,7 @@ void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager)
         width = get_column_width(&line->columns[i]);
 
         if (i < line->merge_start)
-            manager->max_widths[i] = MAX(manager->max_widths[i], width);
+            summary->max_widths[i] = MAX(summary->max_widths[i], width);
 
         if (i >= BLC_DISPLAY)
         {
@@ -1523,31 +1399,36 @@ void g_buffer_line_update_max_widths(GBufferLine *line, GBufferLine *manager)
     }
 
     if (line->merge_start != BLC_COUNT)
-        manager->merged_width = MAX(manager->merged_width, merged_width);
+        summary->merged_width = MAX(summary->merged_width, merged_width);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line         = ligne à venir consulter.                      *
+*  Paramètres  : line    = ligne à venir consulter.                           *
+*                index   = indice de la colonne visée.                        *
+*                summary = résumé des largeurs maximales.                     *
 *                                                                             *
-*  Description : Renvoie la ligne comptabilisant les largeurs pour un groupe. *
+*  Description : Fournit la largeur d'une colonne finalement appliquée.       *
 *                                                                             *
-*  Retour      : Ligne considérée comme la gestionnaire d'un ensemble.        *
+*  Retour      : Largeur globale ou spécifique, selon l'indice communiqué.    *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_line_get_width_manager(GBufferLine *line)
+gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const line_width_summary *summary)
 {
-    GBufferLine *result;                    /* Gestionnaire à retourner    */
+    gint result;                            /* Largeur à retourner         */
+
+    assert(index < BLC_COUNT);
+
+    if (index >= line->merge_start)
+        result = get_column_width(&line->columns[index]);
 
-    if (line->flags & BLF_WIDTH_MANAGER)
-        result = line;
     else
-        result = line->manager;
+        result = summary->max_widths[index];
 
     return result;
 
@@ -1556,72 +1437,173 @@ GBufferLine *g_buffer_line_get_width_manager(GBufferLine *line)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line         = ligne à venir consulter.                      *
-*                max_widths   = tableau résumant les largeurs maximales. [OUT]*
-*                merged_width = largeur maximale en cas de fusion. |OUT]      *
+*  Paramètres  : line    = ligne à venir consulter.                           *
+*                summary = résumé des largeurs maximales.                     *
+*                display = règles d'affichage des colonnes modulables.        *
+*                base    = position jusqu'au segment trouvé. [OUT]            *
+*                offset  = position à la colonne visée. [OUT]                 *
+*                dir     = direction d'un éventuel déplacement en cours.      *
+*                force   = accepte les segments en bordure au pire.           *
 *                                                                             *
-*  Description : Filtre des largeurs de lignes et ne garde que les maximales. *
+*  Description : Donne le segment présent à une abscisse donnée.              *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Segment trouvé ou NULL si hors borne.                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_line_apply_max_widths(GBufferLine *line, gint *max_widths, gint *merged_width)
+GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *line, const line_width_summary *summary, const bool *display, gint *base, gint *offset, GdkScrollDirection dir, bool force)
 {
-    GBufferLine *manager;                   /* Gestionnaire de groupe      */
+    GBufferSegment *result;                 /* Trouvaille à retourner      */
+    BufferLineColumn last;                  /* Dernière colonne remplie    */
+    gint last_base;                         /* Dernière abscisse associée  */
     BufferLineColumn i;                     /* Boucle de parcours          */
+    gint width;                             /* Largeur d'une colonne donnée*/
+
+    gint limit;
+
+    gint consumed;                          /* Distance vers le segment    */
+    gint old_base;                          /* Somme de toutes les largeurs*/
+
+    result = NULL;
+
+    *base = 0;
+
+    last = BLC_COUNT;
+
+    //sum = 0;
+
+    printf("---------------\n");
 
-    manager = g_buffer_line_get_width_manager(line);
+    /* On cible déjà la colonne idéale */
 
     for (i = 0; i < BLC_COUNT; i++)
-        max_widths[i] = MAX(manager->max_widths[i], max_widths[i]);
+    {
+        printf(" @ (%d) x=%d  width=%d  max=%d  display ? %d\n",
+               i, *offset, get_column_width(&line->columns[i]), summary->max_widths[i], i < BLC_DISPLAY ? display[i] : true);
 
-    *merged_width = MAX(manager->merged_width, *merged_width);
 
-}
+        if (i < BLC_DISPLAY && !display[i]) continue;
 
+        /* Mémorisation de la dernière colonne contenant quelque chose... */
+        if (get_column_width(&line->columns[i]) > 0)
+        {
+            last = i;
+            last_base = *base;
+        }
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line       = ligne à venir consulter.                        *
-*                index      = indice de la colonne visée.                     *
-*                max_widths = tableau résumant les largeurs maximales.        *
-*                                                                             *
-*  Description : Fournit la largeur d'une colonne finalement appliquée.       *
-*                                                                             *
-*  Retour      : Largeur globale ou spécifique, selon l'indice communiqué.    *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        if (i < line->merge_start)
+        {
+            width = g_buffer_line_compute_max_width(line, i, summary);
 
-gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths)
-{
-    gint result;                            /* Largeur à retourner         */
-    //GBufferLine *manager;                   /* Gestionnaire de groupe      */
+            if ((i + 1) < BLC_COUNT) limit = width + COL_MARGIN / 2;
+            else limit = width;
 
-    assert(index < BLC_COUNT);
+            if (*offset <= limit) break;
+            else
+            {
+                *offset -= width + COL_MARGIN;
+                *base += width + COL_MARGIN;
+            }
 
-    if (index >= line->merge_start)
-        result = get_column_width(&line->columns[index]);
+        }
+        else
+        {
+            width = get_column_width(&line->columns[i]);
 
-    else
+            if (*offset <= width) break;
+            else
+            {
+                *offset -= width;
+                *base += width;
+            }
+
+        }
+
+
+    }
+
+    printf(" -- get segment at -- found index %u (max=%u)\n", i, BLC_COUNT);
+
+
+    printf("                      last seen = %u\n", last);
+
+
+
+
+
+    if (i < BLC_COUNT)
     {
-        if (index < BLC_ASSEMBLY)
-            result = max_widths[index];
 
-        else
+        printf(" -- width @ %u : %d\n", i, get_column_width(&line->columns[i]));
+
+        if (get_column_width(&line->columns[i]) > 0)
+        {
+            /**
+             * Si la position était au milieu d'une marge, la sélection a pu pousser
+             * jusqu'à la colonne suivante, plus proche.
+             * Relativment à la base de cette dernière, la position est donc devenue négative.
+             */
+            if (*offset < 0) *offset = 0;
+
+            result = get_segment_at(&line->columns[i], offset, dir, &consumed);
+            *base += consumed;
+        }
+
+        /* La position fournie tombe dans une colonne vide ! */
+        else
+        {
+            if (force || get_column_width(&line->columns[i]) == 0)
+            {
+                result = NULL;
+                *offset = 0;
+
+                old_base = *base;
+
+                for (i++; i < BLC_COUNT && result == NULL; i++)
+                {
+                    printf(" -- update to col %u  -- x = %d\n", i, *offset);
+
+                    if ((i - 1) < line->merge_start)
+                    {
+                        width = g_buffer_line_compute_max_width(line, i - 1, summary);
+                        *base += (width + COL_MARGIN);
+                    }
+                    else
+                        *base += get_column_width(&line->columns[i - 1]);
+
+                    result = get_first_segment(&line->columns[i]);
+
+                }
+
+                printf(" -- final x = %d (result=%p)\n", *offset, result);
+
+                if (result == NULL)
+                {
+                    *base = old_base;
+                    goto use_right_border;
+                }
+
+            }
+
+        }
+
+    }
+
+    else /* if (i == BLC_COUNT) */
+    {
+        if (force && last != BLC_COUNT)
         {
-            //manager = g_buffer_line_get_width_manager(line);
+ use_right_border:
 
-            if (line->flags & BLF_WIDTH_MANAGER)
-                result = line->max_widths[index];
-            else
-                result = line->manager->max_widths[index];
+            result = get_last_segment(&line->columns[last]);
+            *base = last_base;
+            *offset = get_column_width(&line->columns[last]);
 
         }
+        else
+            result = NULL;
 
     }
 
@@ -1632,126 +1614,134 @@ gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn i
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line = ligne à venir consulter.                              *
+*  Paramètres  : line    = ligne à venir consulter.                           *
+*                target  = segment dont un voisin est à retourner.            *
+*                summary = résumé des largeurs maximales.                     *
+*                display = règles d'affichage des colonnes modulables.        *
+*                dir     = orientation des recherches.                        *
+*                offset  = décalage pour amener à l'extrémité nouvelle. [OUT] *
 *                                                                             *
-*  Description : Fournit la colonne à partir de laquelle une fusion opère.    *
+*  Description : Fournit le segment voisin d'un autre segment identifié.      *
 *                                                                             *
-*  Retour      : Début de la première (et unique) zone globale.               *
+*  Retour      : Segment trouvé dans la ligne ou NULL.                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
+GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *line, GBufferSegment *target, const line_width_summary *summary, const bool *display, GdkScrollDirection dir, gint *offset)
 {
-    return line->merge_start;
+    GBufferSegment *result;                 /* Trouvaille à retourner      */
+    BufferLineColumn i;                     /* Boucle de parcours #1       */
+    bool displayed;                         /* Confort de lecture          */
+    BufferLineColumn k;                     /* Boucle de parcours #2       */
 
-}
+    result = NULL;
 
+    /* Recherche dans la colonne de départ */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line  = ligne à venir compléter.                             *
-*                start = début de la première (et unique) zone globale.       *
-*                                                                             *
-*  Description : Définit la colonne à partir de laquelle la fusion opère.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    for (i = 0; i < BLC_COUNT; i++)
+        if (column_has_segment(&line->columns[i], target, NULL))
+            break;
 
-void g_buffer_line_start_merge_at(GBufferLine *line, BufferLineColumn start)
-{
-    if (start == BLC_LAST_USED)
-        line->merge_start = line->last_used;
-    else
-        line->merge_start = start;
+    if (i == BLC_COUNT) return NULL;
 
-}
+    result = find_near_segment(&line->columns[i], target, dir);
+    if (result != NULL) return result;
 
+    /* Recherche dans la direction des colonnes voisines */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line = ligne à venir compléter.                              *
-*                flag = propriété à intégrer.                                 *
-*                                                                             *
-*  Description : Ajoute une propriété particulière à une ligne donnée.        *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    if (result == NULL)
+        switch (dir)
+        {
+            case GDK_SCROLL_LEFT:
 
-void g_buffer_line_add_flag(GBufferLine *line, BufferLineFlags flag)
-{
-    if ((line->flags & flag) == 0)
-    {
-        g_signal_emit_by_name(line, "flip-flag", line->flags, flag);
+                /* Si on a atteint la première colonne sans trouver... */
+                if (i == 0) break;
 
-        line->flags |= flag;
+                /* On s'assure que la colonne précédente est visible et peuplée */
+                for (; i > BLC_FIRST && result == NULL; i--)
+                {
+                    displayed = (i <= BLC_DISPLAY ? display[i - 1] : true);
 
-    }
+                    if (displayed)
+                        result = get_last_segment(&line->columns[i - 1]);
 
-}
+                }
 
+                break;
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line = ligne à venir consulter.                              *
-*                                                                             *
-*  Description : Renseigne sur les propriétés particulières liées à une ligne.*
-*                                                                             *
-*  Retour      : Propriétés intégrées.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+            case GDK_SCROLL_RIGHT:
 
-BufferLineFlags g_buffer_line_get_flags(const GBufferLine *line)
-{
-    return line->flags;
+                /* Si on a atteint la dernière colonne sans trouver... */
+                /*if (i == BLC_COUNT) break;*/
 
-}
+                /* On s'assure que la colonne suivante est visible et peuplée */
+                for (; (i + 1) < BLC_COUNT && result == NULL; i++)
+                {
+                    displayed = ((i + 1) < BLC_DISPLAY ? display[i + 1] : true);
 
+                    if (displayed)
+                        result = get_first_segment(&line->columns[i + 1]);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line = ligne à venir compléter.                              *
-*                flag = propriété à supprimer.                                *
-*                                                                             *
-*  Description : Retire une propriété particulière à une ligne donnée.        *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+                }
 
-void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag)
-{
-    if ((line->flags & flag) != 0)
+                break;
+
+        default:
+            break;
+
+    }
+
+    /* Calcul de la position finale */
+
+    if (result != NULL)
     {
-        g_signal_emit_by_name(line, "flip-flag", line->flags, flag);
+        *offset = 0;
 
-        line->flags &= ~flag;
+        for (k = 0; k < i; k++)
+        {
+            displayed = (k < BLC_DISPLAY ? display[k] : true);
+
+            if (displayed)
+            {
+                *offset += g_buffer_line_compute_max_width(line, k, summary);
+                if (k < line->merge_start) *offset += COL_MARGIN;
+            }
+
+        }
+
+        switch (dir)
+        {
+            case GDK_SCROLL_LEFT:
+                *offset += get_column_width(&line->columns[i]);
+                break;
+
+            case GDK_SCROLL_RIGHT:
+                /**offset += 0;*/
+                break;
+
+            default:
+                break;
+
+        }
 
     }
 
+    return result;
+
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line       = ligne de texte à manipuler.                     *
-*                cairo      = contexte graphique à utiliser pour les pinceaux.*
-*                max_widths = largeurs de colonne à respecter.                *
-*                x_init     = abscisse du point d'impression de départ.       *
-*                y          = ordonnée du point d'impression.                 *
-*                display    = règles d'affichage des colonnes modulables.     *
-*                list       = liste de contenus à mettre en évidence.         *
+*  Paramètres  : line    = ligne de texte à manipuler.                        *
+*                cairo   = contexte graphique à utiliser pour les pinceaux.   *
+*                summary = résumé des largeurs maximales.                     *
+*                x_init  = abscisse du point d'impression de départ.          *
+*                y       = ordonnée du point d'impression.                    *
+*                display = règles d'affichage des colonnes modulables.        *
+*                list    = liste de contenus à mettre en évidence.            *
 *                                                                             *
 *  Description : Imprime la ligne de texte représentée.                       *
 *                                                                             *
@@ -1761,7 +1751,7 @@ void g_buffer_line_remove_flag(GBufferLine *line, BufferLineFlags flag)
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths[BLC_COUNT], gint x_init, gint y, const bool *display, const segcnt_list *list)
+void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const line_width_summary *summary, gint x_init, gint y, const bool *display, const segcnt_list *list)
 {
     GBufferLineClass *class;                /* Stockage de briques de base */
     bool has_src_surface;                   /* Note une présence définie   */
@@ -1801,7 +1791,7 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths
 
         if (i < line->merge_start)
         {
-            max_width = g_buffer_line_compute_max_width(line, i, max_widths);
+            max_width = g_buffer_line_compute_max_width(line, i, summary);
 
             x += max_width + COL_MARGIN;
 
@@ -1810,87 +1800,3 @@ void g_buffer_line_draw(GBufferLine *line, cairo_t *cairo, const gint max_widths
     }
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line    = ligne de texte à manipuler.                        *
-*                ctx     = éléments à disposition pour l'exportation.         *
-*                type    = type d'exportation attendue.                       *
-*                display = règles d'affichage des colonnes modulables.        *
-*                                                                             *
-*  Description : Exporte la ligne de texte représentée.                       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_buffer_line_export(GBufferLine *line, buffer_export_context *ctx, BufferExportType type, const bool *display)
-{
-    BufferLineColumn i;                     /* Boucle de parcours          */
-    int col_span;                           /* Fusion de colonnes ?        */
-
-    switch (type)
-    {
-        case BET_HTML:
-            dprintf(ctx->fd, "\t<TR>\n");
-            break;
-        default:
-            break;
-    }
-
-    for (i = 0; i < BLC_COUNT; i++)
-    {
-        if (i < BLC_DISPLAY && !display[i]) continue;
-
-        switch (type)
-        {
-            case BET_TEXT:
-                if (i > 0) dprintf(ctx->fd, "%s", ctx->sep);
-                break;
-            default:
-                break;
-        }
-
-        /**
-         * Pour la signification des différentes valeurs assignées,
-         * se référer au code de export_segments_of_column().
-         *
-         * En gros :
-         *   - 1  = rien de spécial.
-         *   - >1 = il s'agit de la première cellule fusionnée de la ligne.
-         *   - 0  = fusion déjà faite, on ne peut que rajouter du contenu dedans.
-         *   - <1 = il s'agit de la dernière cellule fusionnée de la ligne.
-         *
-         * On considère qu'une fusion ne peut pas se réaliser sur la dernière
-         * cellule uniquement (ce qui a du sens : c'est inutile).
-         */
-
-        if (i < line->merge_start)
-            col_span = 1;
-
-        else if (i == line->merge_start)
-            col_span = BLC_COUNT - i;
-
-        else
-            col_span = ((i + 1) == BLC_COUNT ? -1 : 0);
-
-        export_segments_of_column(&line->columns[i], ctx, type, col_span);
-
-    }
-
-    switch (type)
-    {
-        case BET_TEXT:
-            dprintf(ctx->fd, "\n");
-            break;
-        case BET_HTML:
-            dprintf(ctx->fd, "</TR>\n");
-            break;
-        default:
-            break;
-    }
-
-}
diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h
index e4c2da5..6b213e3 100644
--- a/src/glibext/gbufferline.h
+++ b/src/glibext/gbufferline.h
@@ -114,12 +114,6 @@ void g_buffer_line_fill_mrange(GBufferLine *, MemoryDataSize, MemoryDataSize);
 /* Construit le tronc commun d'une ligne d'instruction. */
 void g_buffer_line_fill_for_instr(GBufferLine *, MemoryDataSize, MemoryDataSize, const GBinContent *, phys_t);
 
-/* Donne le segment présent à une abscisse donnée. */
-GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const gint [BLC_COUNT], const bool *, gint *, gint *, GdkScrollDirection, bool);
-
-/* Fournit le segment voisin d'un autre segment identifié. */
-GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const gint [BLC_COUNT], const bool *, GdkScrollDirection, gint *);
-
 /* Recherche le premier créateur enregistré dans des segments. */
 GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn);
 
@@ -138,18 +132,6 @@ char *g_buffer_line_get_text(const GBufferLine *, BufferLineColumn, BufferLineCo
 /* Supprime du texte représenté par une ligne de tampon. */
 void g_buffer_line_delete_text(GBufferLine *, BufferLineColumn, BufferLineColumn);
 
-/* Retient les largeurs d'une ligne si maximales. */
-void g_buffer_line_update_max_widths(GBufferLine *, GBufferLine *);
-
-/* Renvoie la ligne comptabilisant les largeurs pour un groupe. */
-GBufferLine *g_buffer_line_get_width_manager(GBufferLine *);
-
-/* Filtre des largeurs de lignes et ne garde que les maximales. */
-void g_buffer_line_apply_max_widths(GBufferLine *, gint *, gint *);
-
-/* Fournit la largeur d'une colonne finalement appliquée. */
-gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const gint *);
-
 /* Fournit la colonne à partir de laquelle une fusion opère. */
 BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *);
 
@@ -165,9 +147,6 @@ BufferLineFlags g_buffer_line_get_flags(const GBufferLine *);
 /* Retire une propriété particulière à une ligne donnée. */
 void g_buffer_line_remove_flag(GBufferLine *, BufferLineFlags);
 
-/* Imprime la ligne de texte représentée. */
-void g_buffer_line_draw(GBufferLine *, cairo_t *, const gint [BLC_COUNT], gint, gint, const bool *, const segcnt_list *);
-
 /* Exporte la ligne de texte représentée. */
 void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportType, const bool *);
 
@@ -184,4 +163,33 @@ void g_buffer_line_export(GBufferLine *, buffer_export_context *, BufferExportTy
 
 
 
+/* ----------------------- MANIPULATION DES LARGEURS REQUISES ----------------------- */
+
+
+/* Mémorisation des largeurs pour un groupe de lignes */
+typedef struct _line_width_summary
+{
+    gint max_widths[BLC_COUNT];             /* Taille cachée des colonnes  */
+    gint merged_width;                      /* Largeur cumulée avant fusion*/
+
+} line_width_summary;
+
+
+/* Fait remonter les largeurs requises par une ligne donnée. */
+void g_buffer_line_collect_widths(GBufferLine *, line_width_summary *);
+
+/* Fournit la largeur d'une colonne finalement appliquée. */
+gint g_buffer_line_compute_max_width(const GBufferLine *, BufferLineColumn, const line_width_summary *);
+
+/* Donne le segment présent à une abscisse donnée. */
+GBufferSegment *g_buffer_line_get_segment_at(const GBufferLine *, const line_width_summary *, const bool *, gint *, gint *, GdkScrollDirection, bool);
+
+/* Fournit le segment voisin d'un autre segment identifié. */
+GBufferSegment *g_buffer_line_find_near_segment(const GBufferLine *, GBufferSegment *, const line_width_summary *, const bool *, GdkScrollDirection, gint *);
+
+/* Imprime la ligne de texte représentée. */
+void g_buffer_line_draw(GBufferLine *, cairo_t *, const line_width_summary *, gint, gint, const bool *, const segcnt_list *);
+
+
+
 #endif  /* _GLIBEXT_GBUFFERLINE_H */
diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c
new file mode 100644
index 0000000..214b212
--- /dev/null
+++ b/src/glibext/gbufferview.c
@@ -0,0 +1,1330 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gbufferview.c - affichage d'une vue particulière d'un tampon de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gbufferview.h"
+
+
+
+/* Vue d'un tampon pour code désassemblé (instance) */
+struct _GBufferView
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    GCodeBuffer *buffer;                    /* Tampon de code visualisé    */
+
+    vmpa2t start;                           /* Première ligne intégrée     */
+    vmpa2t end;                             /* Dernière ligne intégrée     */
+
+    size_t first;                           /* Indice de la première ligne */
+    size_t last;                            /* Indice de la dernière ligne */
+
+    union
+    {
+        const GWidthTracker *ext_tracker;   /* Suivi externe des largeurs  */
+        GWidthTracker *int_tracker;         /* Suivi interne des largeurs  */
+        GWidthTracker *tracker;             /* Suivi pour usage interne    */
+    };
+
+    bool unrestricted;                      /* Validité des informations   */
+
+    segcnt_list *highlighted;               /* Segments mis en évidence    */
+    bool external;                          /* Note l'origine de la liste  */
+
+};
+
+/* Vue d'un tampon pour code désassemblé (classe) */
+struct _GBufferViewClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+    gint line_height;                       /* Hauteur maximale des lignes */
+    gint left_margin;                       /* Marge gauche + espace       */
+    gint left_text;                         /* Début d'impression du code  */
+
+    /* Signaux */
+
+    void (* need_redraw) (GBufferView *);
+
+};
+
+
+/* Procède à l'initialisation d'une classe de vue de tampon. */
+static void g_buffer_view_class_init(GBufferViewClass *);
+
+/* Procède à l'initialisation d'une vue d'un tampon pour code. */
+static void g_buffer_view_init(GBufferView *);
+
+/* Supprime toutes les références externes. */
+static void g_buffer_view_dispose(GBufferView *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_buffer_view_finalize(GBufferView *);
+
+/* Accompagne une variation de la quantité de lignes du tampon. */
+static void on_buffer_size_changed(const GCodeBuffer *, bool, size_t, size_t, GBufferView *);
+
+/* Réagit à un changement de contenu d'une ligne donnée. */
+static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *);
+
+
+
+/* Détermine le type de la vue d'un tampon pour code désassemblé. */
+G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe de composant GTK à initialiser.               *
+*                                                                             *
+*  Description : Procède à l'initialisation d'une classe de vue de tampon.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_buffer_view_class_init(GBufferViewClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize;
+
+    class->line_height = 17;
+    class->left_margin = 2 * class->line_height;
+    class->left_text = 2.5 * class->line_height;
+
+
+    g_signal_new("need-redraw",
+                 G_TYPE_BUFFER_VIEW,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GBufferViewClass, need_redraw),
+                 NULL, NULL,
+                 g_cclosure_marshal_VOID__OBJECT,
+                 G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GLib à initialiser.                         *
+*                                                                             *
+*  Description : Procède à l'initialisation d'une vue d'un tampon pour code.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_buffer_view_init(GBufferView *view)
+{
+    view->unrestricted = true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_buffer_view_dispose(GBufferView *view)
+{
+    g_object_unref(G_OBJECT(view->buffer));
+
+    G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_buffer_view_finalize(GBufferView *view)
+{
+    if (!view->external)
+        exit_segment_content_list(view->highlighted);
+
+    G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = tampon à représenter à l'écran.                     *
+*                widget = composant GTK de destination pour le rendu.         *
+*                                                                             *
+*  Description : Crée une nouvelle vue d'un tampon pour code désassemblé.     *
+*                                                                             *
+*  Retour      : Composant GTK créé.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted)
+{
+    GBufferView *result;                    /* Composant à retourner       */
+
+    result = g_object_new(G_TYPE_BUFFER_VIEW, NULL);
+
+    g_object_ref(G_OBJECT(buffer));
+    result->buffer = buffer;
+
+    g_buffer_view_restrict(result, NULL, NULL);
+
+    g_code_buffer_register_view_callback(buffer,
+                                         (buffer_size_changed_cb)on_buffer_size_changed,
+                                         G_OBJECT(result));
+
+    g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result);
+
+    if (highlighted != NULL)
+        result->highlighted = highlighted;
+    else
+        result->highlighted = init_segment_content_list();
+
+    result->external = (highlighted != NULL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = tampon de lignes cohérentes à manipuler.            *
+*                added  = indication sur la variation de la taille du tampon. *
+*                index  = indice de la première ligne à traiter.              *
+*                count  = nombre de lignes à traiter.                         *
+*                view   = vue active du tampon de lignes concerné.            *
+*                                                                             *
+*  Description : Accompagne une variation de la quantité de lignes du tampon. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_buffer_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count, GBufferView *view)
+{
+    size_t i;                               /* Boucle de parcours          */
+    GBufferLine *line;                      /* Ligne à manipuler           */
+    const vmpa2t *addr;                     /* Localisation de ligne       */
+
+    /**
+     * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon.
+     * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée.
+     */
+
+    if (added)
+    {
+        if (view->unrestricted)
+            view->last += count;
+
+        else
+        {
+            /* Avant la zone représentée ? */
+            if (index < view->first)
+            {
+                view->first += count;
+                view->last += count;
+            }
+
+            /* Juste avant la zone représentée ? */
+            else if (view->first == index)
+                for (i = 0; i < count; i++)
+                {
+                    line = g_code_buffer_find_line_by_index(buffer, index + i);
+                    addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+                    if (cmp_vmpa(&view->start, addr) == 0)
+                    {
+                        view->first++;
+                        view->last++;
+                    }
+                    else
+                        break;
+
+                }
+
+            /* Dans la zone représentée ? */
+            else if (view->first < index && index <= view->last)
+                view->last += count;
+
+            /* Juste après la vue représentée ? */
+            else if ((view->last + 1) == index)
+                for (i = 0; i < count; i++)
+                {
+                    line = g_code_buffer_find_line_by_index(buffer, index + i);
+                    addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+                    if (cmp_vmpa(&view->end, addr) == 0)
+                        view->last++;
+                    else
+                        break;
+
+                }
+
+            g_width_tracker_update_added(view->int_tracker, index, count);
+
+        }
+
+    }
+
+    else
+    {
+        if (view->unrestricted)
+            view->last -= count;
+
+        else
+        {
+            /* Avant la zone représentée ? */
+            if (index <= view->first)
+            {
+                view->first -= count;
+                view->last -= count;
+            }
+
+            /* Dans la zone représentée ? */
+            else if (view->first < index && index <= view->last)
+                view->last -= count;
+
+        }
+
+        g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1);
+
+    }
+
+    g_signal_emit_by_name(view, "need-redraw");
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer  = tampon de lignes cohérentes à manipuler.           *
+*                line    = ligne dont la définition vient d'évoluer.          *
+*                segment = éventuel segment qui vient d'évoluer ou NULL.      *
+*                view    = vue active du tampon de lignes concerné.           *
+*                                                                             *
+*  Description : Réagit à un changement de contenu d'une ligne donnée.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view)
+{
+    const vmpa2t *addr;                     /* Localisation de ligne       */
+
+    addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+    if (cmp_vmpa(&view->start, addr) <= 0 && cmp_vmpa(addr, &view->end) <= 0)
+        g_signal_emit_by_name(view, "need-redraw");
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view  = visualisateur à mettre à jour.                       *
+*                first = première ligne à imprimer.                           *
+*                last  = première ligne hors cadre.                           *
+*                                                                             *
+*  Description : Restreint le champ d'application de l'affichage.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end)
+{
+    const GWidthTracker *template;          /* Suivi déjà en place         */
+
+    if (!view->unrestricted)
+        g_object_unref(G_OBJECT(view->int_tracker));
+
+    view->unrestricted = (start == NULL || end == NULL);
+
+    template = g_code_buffer_get_width_tracker(view->buffer);
+
+    if (view->unrestricted)
+    {
+        view->first = 0;
+        view->last = g_code_buffer_count_lines(view->buffer) - 1;
+
+        view->ext_tracker = template;
+
+    }
+
+    else
+    {
+        copy_vmpa(&view->start, start);
+        copy_vmpa(&view->end, end);
+
+        view->first = g_code_buffer_get_index_from_address(view->buffer, start, true);
+        view->last = g_code_buffer_get_index_from_address(view->buffer, end, false);
+
+        view->ext_tracker = g_width_tracker_new_restricted(template, view->first, view->last);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view  = visualisateur à mettre à jour.                       *
+*                first = première ligne à imprimer ou NULL. [OUT]             *
+*                last  = première ligne hors cadre ou NULL. [OUT]             *
+*                                                                             *
+*  Description : Indique le champ d'application de l'affichage.               *
+*                                                                             *
+*  Retour      : true si des restrictions particulières sont en place.        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end)
+{
+    if (!view->unrestricted)
+    {
+        if (start != NULL) copy_vmpa(start, &view->start);
+        if (end != NULL) copy_vmpa(end, &view->end);
+    }
+
+    return !view->unrestricted;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = visualisateur à consulter.                            *
+*                                                                             *
+*  Description : Fournit le tampon de code lié à un visualisateur donné.      *
+*                                                                             *
+*  Retour      : Tampon de code associé au gestionnaire d'affichage.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view)
+{
+    g_object_ref(G_OBJECT(view->buffer));
+
+    return view->buffer;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = visualisation à consulter.                            *
+*                                                                             *
+*  Description : Fournit la hauteur d'impression d'une ligne visualisée.      *
+*                                                                             *
+*  Retour      : Hauteur de ligne en pixel.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_buffer_view_get_line_height(GBufferView *view)
+{
+    return G_BUFFER_VIEW_GET_CLASS(view)->line_height;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = visualisation à consulter.                         *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Fournit la largeur requise par une visualisation.            *
+*                                                                             *
+*  Retour      : Dimension calculée.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_buffer_view_get_width(GBufferView *view, const bool *display)
+{
+    gint result;                            /* Taille à retourner          */
+
+    result = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+    result += g_width_tracker_get_width(view->tracker, display);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = visualisation à consulter.                         *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Fournit la largeur requise pour dépasser les marges gauches. *
+*                                                                             *
+*  Retour      : Dimension calculée.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_buffer_view_get_margin(GBufferView *view, const bool *display)
+{
+    gint result;                            /* Taille à retourner          */
+
+    result = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+    result += g_width_tracker_get_margin(view->tracker, display);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = visualisation à consulter.                            *
+*                                                                             *
+*  Description : Fournit la hauteur requise par une visualisation.            *
+*                                                                             *
+*  Retour      : Dimension calculée.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_buffer_view_get_height(const GBufferView *view)
+{
+    gint result;                            /* Taille à retourner          */
+
+    result = G_BUFFER_VIEW_GET_CLASS(view)->line_height;
+
+    result *= (view->last - view->first + 1);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
+*                x       = abscisse de la zone principale à traiter.          *
+*                y       = ordonnée de la zone principale à traiter.          *
+*                display = règles d'affichage des colonnes modulables.        *
+*                caret   = position du curseur à construire. [OUT]            *
+*                                                                             *
+*  Description : Calcule la position idéale de curseur pour un point donné.   *
+*                                                                             *
+*  Retour      : Adresse si une a pu être déterminée, NULL sinon.             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret)
+{
+    gint remaining;                         /* Copie de travail modifiable */
+    size_t index;                           /* Indice de ligne de tampon   */
+    GBufferLine *line;                      /* Ligne à la position courante*/
+    GBufferSegment *segment;                /* Segment présent sur la place*/
+    GBufferViewClass *class;                /* Classe pour les vues        */
+
+    remaining = x;
+
+    line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment);
+
+    if (line == NULL) return NULL;
+    if (segment == NULL) printf(" -- no segment\n");
+    if (segment == NULL) return NULL;
+
+
+
+
+
+    printf("\n[BASE]  orig = %d   tronc = %d   reste = %d   dernier = %d   largeur = %d\n",
+           x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining),
+           g_buffer_segment_get_width(segment));
+
+    printf("        '%s'\n", g_buffer_segment_get_text(segment, false));
+
+
+    class = G_BUFFER_VIEW_GET_CLASS(view);
+
+    caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining);
+
+    caret->y = (index - view->first) * class->line_height;
+
+    caret->width = 2;
+    caret->height = class->line_height;
+
+    return get_mrange_addr(g_buffer_line_get_range(line));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
+*                line    = ligne correspondant à la position.                 *
+*                index   = indice de cette même ligne dans le tampon.         *
+*                x       = abscisse de la zone principale à traiter.          *
+*                display = règles d'affichage des colonnes modulables.        *
+*                caret   = position du curseur à construire. [OUT]            *
+*                                                                             *
+*  Description : Calcule la position idéale de curseur pour un point donné.   *
+*                                                                             *
+*  Retour      : Adresse si une a pu être déterminée, NULL sinon.             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret)
+{
+    GBufferViewClass *class;                /* Classe pour les vues        */
+    gint offset;                            /* Point de travail modifiable */
+    const line_width_summary *summary;      /* Résumé concis des largeurs  */
+    gint base;                              /* Position absolue de segment */
+    GBufferSegment *segment;                /* Segment visé par le pointeur*/
+
+    class = G_BUFFER_VIEW_GET_CLASS(view);
+
+    offset = x;
+
+    offset -= class->left_text;
+    if (offset < 0) return NULL;
+
+    summary = g_width_tracker_get_width_summary(view->tracker);
+
+    segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, GDK_SCROLL_LEFT, true);
+    if (segment == NULL) return NULL;
+
+    caret->x = class->left_text + base + offset;
+
+    printf("caret Y : %zu -> %zu\n", view->first, index);
+
+    caret->y = (index - view->first) * class->line_height;
+
+    caret->width = 2;
+    caret->height = class->line_height;
+
+    return get_mrange_addr(g_buffer_line_get_range(line));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line    = ligne à venir consulter.                           *
+*                caret   = position du curseur à faire évoluer.               *
+*                ctrl    = indique la demande d'un parcours rapide.           *
+*                dir     = direction du parcours.                             *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Déplace le curseur au sein d'une vue de tampon.              *
+*                                                                             *
+*  Retour      : true si un déplacement a été effectué, false sinon.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
+{
+    bool result;                            /* Bilan à retourner           */
+    gint offset;                            /* Point de travail modifiable */
+    const line_width_summary *summary;      /* Résumé concis des largeurs  */
+    gint base;                              /* Position absolue de segment */
+    GBufferSegment *segment;                /* Segment visé par le pointeur*/
+
+
+
+    offset = caret->x;
+
+    offset -= G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+    if (offset < 0) return false;
+
+    summary = g_width_tracker_get_width_summary(view->tracker);
+
+    segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, dir, false);
+
+    if (segment == NULL) printf(" ===== NO SEG...\n");
+
+    if (segment == NULL) return false;
+
+
+    printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false));
+
+
+
+
+
+
+    //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT)
+        result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
+    //else
+        //result = true;
+
+    printf(" ====== MOVE 1 ? %d\n", result);
+
+    ///////////////////
+
+    if (!result)
+    {
+        base = 0;
+
+        segment = g_buffer_line_find_near_segment(line, segment, summary, display, dir, &offset);
+
+
+        printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL);
+
+        if (segment != NULL)
+        {
+
+            result = true;
+            //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
+
+            /*
+            if (result)
+                caret->x -= COL_MARGIN;
+            */
+
+            printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset);
+
+
+        }
+
+
+    }
+
+
+    if (result)
+        printf(" ====== NEW CARET: %d -> %d\n", caret->x, G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset);
+    else
+        printf(" ====== NO NEW CARET!\n");
+
+
+
+    if (result)
+        caret->x = G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
+*                caret   = position du curseur à faire évoluer.               *
+*                ctrl    = indique la demande d'un parcours rapide.           *
+*                dir     = direction du parcours.                             *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Déplace le curseur au sein d'une vue de tampon.              *
+*                                                                             *
+*  Retour      : Adresse si une a pu être déterminée, VMPA_INVALID sinon.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
+{
+    const vmpa2t *result;                   /* Actualisation à renvoyer    */
+    size_t index;                           /* Indice de ligne de tampon   */
+    GBufferLine *line;                      /* Ligne sous le pointeur      */
+
+
+    const line_width_summary *summary;      /* Résumé concis des largeurs  */
+    bool computed;                          /* Récursivité pris en compte  */
+    gint left_pos;                          /* Retour à la ligne           */
+    gint right_pos;                         /* Position d'extrème droite   */
+    BufferLineColumn i;                     /* Boucle de parcours          */
+    size_t first;                           /* Première ligne intégrée     */
+    size_t last;                            /* Dernière ligne intégrée     */
+
+
+
+
+    bool moved;                             /* Mémorisation d'une évolut°  */
+
+
+
+
+
+
+
+
+
+    result = NULL;
+
+
+
+    line = g_buffer_view_find_line_at(view, caret->y, &index);
+    if (line == NULL) return NULL;
+
+    summary = g_width_tracker_get_width_summary(view->tracker);
+
+    computed = false;
+
+    switch (dir)
+    {
+        case GDK_SCROLL_UP:
+        case GDK_SCROLL_DOWN:
+            break;
+        case GDK_SCROLL_LEFT:
+        case GDK_SCROLL_RIGHT:
+            left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+            if (display[BLC_PHYSICAL]) left_pos += summary->max_widths[BLC_PHYSICAL] + COL_MARGIN;
+            if (display[BLC_VIRTUAL]) left_pos += summary->max_widths[BLC_VIRTUAL] + COL_MARGIN;
+            if (display[BLC_BINARY]) left_pos += summary->max_widths[BLC_BINARY] + COL_MARGIN;
+            right_pos = left_pos;
+            for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++)
+                right_pos += summary->max_widths[i] + COL_MARGIN;
+
+            /*
+gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths)
+
+BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
+            */
+
+            left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+            break;
+        default:    /* GDK_SCROLL_SMOOTH */
+            break;
+    }
+
+    first = view->first;
+    last = view->last;
+
+    switch (dir)
+    {
+        case GDK_SCROLL_UP:
+
+            if (index > first)
+            {
+                line = g_code_buffer_find_line_by_index(view->buffer, index - 1);
+                result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret);
+            }
+
+            break;
+
+        case GDK_SCROLL_DOWN:
+
+            if (index < last)
+            {
+                line = g_code_buffer_find_line_by_index(view->buffer, index + 1);
+                result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret);
+            }
+
+            break;
+
+        case GDK_SCROLL_LEFT:
+
+            /*
+            line = g_buffer_view_find_line_at(view, caret->y, &index);
+            if (line == NULL) break;
+            */
+
+            moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_LEFT, display);
+
+            if (moved)
+                result = get_mrange_addr(g_buffer_line_get_range(line));
+
+            else if (index > first)
+            {
+                line = g_code_buffer_find_line_by_index(view->buffer, index - 1);
+                result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret);
+            }
+
+            break;
+
+        case GDK_SCROLL_RIGHT:
+
+            /*
+            line = g_buffer_view_find_line_at(view, caret->y, &index);
+            if (line == NULL) break;
+            */
+
+            moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_RIGHT, display);
+
+            if (moved)
+                result = get_mrange_addr(g_buffer_line_get_range(line));
+
+            else if (index < last)
+            {
+                line = g_code_buffer_find_line_by_index(view->buffer, index + 1);
+                result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret);
+            }
+
+            break;
+
+        default:    /* GDK_SCROLL_SMOOTH */
+            break;
+
+    }
+
+    /*
+    printf(" --- CARET ---   moved = %d   index = %d   result = %p\n",
+           moved, index, result);
+    */
+
+
+    /*
+    if (result && !computed)
+        result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL);
+    */
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = vue de tampon à mettre à jour.                        *
+*                                                                             *
+*  Description : Supprime toute mise en évidence de segments.                 *
+*                                                                             *
+*  Retour      : true si un besoin d'actualisation d'affichage se fait sentir.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_buffer_view_unhighlight_segments(GBufferView *view)
+{
+    bool result;                            /* Bilan d'action à renvoyer   */
+
+    result = reset_segment_content_list(view->highlighted);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
+*                x       = abscisse de la zone principale à traiter.          *
+*                y       = ordonnée de la zone principale à traiter.          *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Surligne tous les segments similaires à celui sous la souris.*
+*                                                                             *
+*  Retour      : true si un besoin d'actualisation d'affichage se fait sentir.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const bool *display)
+{
+    bool need_redraw;                       /* Besoin d'actualisation ?    */
+    GBufferSegment *segment;                /* Segment sélectionnable      */
+
+    if (view->highlighted != NULL)
+        need_redraw = g_buffer_view_unhighlight_segments(view);
+    else
+        need_redraw = false;
+
+    g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment);
+
+    if (segment)
+        need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment);
+
+    if (need_redraw)
+        g_signal_emit_by_name(view, "need-redraw");
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view     = visualisation à représenter.                      *
+*                cr       = contexte graphique dédié à la procédure.          *
+*                fake_x   = abscisse réelle du point 0 à l'écran.             *
+*                fake_y   = ordonnée réelle du point 0 à l'écran.             *
+*                area     = position et surface à traiter.                    *
+*                display  = règles d'affichage des colonnes modulables.       *
+*                selected = ordonnée d'une ligne sélectionnée ou NULL.        *
+*                                                                             *
+*  Description : Imprime la visualisation du tampon de code désassemblé.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected)
+{
+    GBufferViewClass *class;                /* Classe pour les vues        */
+    gint real_x;                            /* Abscisse réelle pour tampon */
+    gint real_y;                            /* Ordonnée réelle pour tampon */
+    size_t first;                           /* Première ligne visée        */
+    size_t last;                            /* Dernière ligne visée + 1    */
+    gint y;                                 /* Point de départ + décallage */
+    bool wait_selection;                    /* Sélection déjà passée ?     */
+    gint rel_selected;                      /* Position relative de sélect°*/
+    size_t i;                               /* Boucle de parcours          */
+    GBufferLine *line;                      /* Ligne à dessiner à l'écran  */
+    line_width_summary summary;             /* Résumé concis des largeurs  */
+
+    class = G_BUFFER_VIEW_GET_CLASS(view);
+
+    real_x = fake_x + class->left_text;
+    real_y = fake_y + area->y;
+
+    first = view->first;
+    first += (real_y / class->line_height);
+
+    last = first + (area->height / class->line_height);
+    if (area->height % class->line_height > 0) last++;
+
+    last = MIN(last, view->last);
+
+    y = area->y - (real_y % class->line_height);
+
+    wait_selection = true;
+
+    if (selected != NULL)
+        rel_selected = *selected - fake_y;
+
+    if (g_code_buffer_count_lines(view->buffer) > 0)
+        for (i = first; i <= last; i++)
+        {
+            /* Si sélection, on sousligne la ligne concernée */
+            if (wait_selection && selected != NULL && rel_selected == y)
+            {
+                cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05);
+
+                cairo_rectangle(cr, area->x, y, area->width, class->line_height);
+                cairo_fill(cr);
+
+                wait_selection = false;
+
+            }
+
+            line = g_code_buffer_find_line_by_index(view->buffer, i);
+
+            if (i == first || (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER))
+                g_width_tracker_get_local_width_summary(view->tracker, i, &summary);
+
+            g_buffer_line_draw(line, cr, &summary, real_x, y, display, view->highlighted);
+
+            y += class->line_height;
+
+        }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view  = visualisation à consulter.                           *
+*                addr  = adresse où retrouver la ligne recherchée.            *
+*                flags = propriétés à vérifier en tout ou partie.             *
+*                idx   = indice de la ligne trouvée ou NULL. [OUT]            *
+*                                                                             *
+*  Description : Retrouve une ligne au sein d'un tampon avec une adresse.     *
+*                                                                             *
+*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx)
+{
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
+    phys_t length;                          /* Taille de la vue            */
+    mrange_t vrange;                        /* Couverture de la vue        */
+    bool allowed;                           /* Rechercher validée ?        */
+
+    /* Vérification des bornes */
+
+    if (!view->unrestricted)
+    {
+        length = compute_vmpa_diff(&view->start, &view->end);
+
+        init_mrange(&vrange, &view->start, length);
+
+        allowed = mrange_contains_addr_inclusive(&vrange, addr);
+
+    }
+    else allowed = true;
+
+    /* Lancement des recherches ? */
+
+    if (allowed)
+        result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx);
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view  = visualisation à consulter.                           *
+*                index = indice de la ligne recherchée.                       *
+*                                                                             *
+*  Description : Retrouve une ligne au sein d'un tampon avec un indice.       *
+*                                                                             *
+*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index)
+{
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
+    bool allowed;                           /* Rechercher validée ?        */
+
+    /* Vérification des bornes */
+
+    allowed = (view->first <= index && index <= view->last);
+
+    /* Lancement des recherches ? */
+
+    if (allowed)
+        result = g_code_buffer_find_line_by_index(view->buffer, index);
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = visualisation à consulter.                            *
+*                y    = ordonnée comprise dans la ligne recherchée.           *
+*                idx  = indice de la ligne trouvée ou NULL. [OUT]             *
+*                                                                             *
+*  Description : Fournit la ligne présente à une ordonnée donnée.             *
+*                                                                             *
+*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx)
+{
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
+    gint lheight;                           /* Hauteur d'une ligne         */
+    size_t index;                           /* Indice attendu              */
+
+    lheight = g_buffer_view_get_line_height(view);
+    index = y / lheight;
+
+    index += view->first;
+
+    if (index <= view->last)
+        result = g_code_buffer_find_line_by_index(view->buffer, index);
+
+    if (result != NULL && idx != NULL)
+        *idx = index;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view    = visualisation à consulter.                         *
+*                x       = abscisse comprise dans le segment recherché. [OUT] *
+*                y       = ordonnée comprise dans la ligne recherchée.        *
+*                idx     = indice de la ligne trouvée ou NULL. [OUT]          *
+*                display = règles d'affichage des colonnes modulables.        *
+*                segment = portion de texte recherchée ou NULL. [OUT]         *
+*                                                                             *
+*  Description : Fournit la ligne et son segment présents à une position.     *
+*                                                                             *
+*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment)
+{
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
+    GBufferViewClass *class;                /* Classe pour les vues        */
+    const line_width_summary *summary;      /* Résumé concis des largeurs  */
+
+    /* Recherche d'une ligne correspondante */
+
+    result = g_buffer_view_find_line_at(view, y, idx);
+
+    /* Recherche du segment visé éventuel */
+
+    if (result != NULL && segment != NULL)
+    {
+        class = G_BUFFER_VIEW_GET_CLASS(view);
+
+        if (*x < class->left_text)
+            *segment = NULL;
+
+        else
+        {
+            summary = g_width_tracker_get_width_summary(view->tracker);
+
+            *x -= class->left_text;
+            *segment = g_buffer_line_get_segment_at(result, summary, display,
+                                                    (gint []) { 0 }, x, GDK_SCROLL_LEFT, true);
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à consulter.                            *
+*                addr = adresse à présenter à l'écran.                        *
+*                x    = position horizontale au sein du composant. [OUT]      *
+*                y    = position verticale au sein du composant. [OUT]        *
+*                code = s'arrête si possible à une ligne avec code.           *
+*                                                                             *
+*  Description : Indique la position d'affichage d'une adresse donnée.        *
+*                                                                             *
+*  Retour      : true si l'adresse fait partie du composant, false sinon.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_buffer_view_get_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code)
+{
+    bool result;                            /* Bilan à retourner           */
+    gint lheight;                           /* Hauteur d'une ligne         */
+    size_t i;                               /* Boucle de parcours          */
+    GBufferLine *line;                      /* Ligne à consulter           */
+    const mrange_t *range;                  /* Emplacement parcouru        */
+
+    result = false;
+
+    *x = 0;
+    *y = 0;
+
+    lheight = g_buffer_view_get_line_height(view);
+
+    for (i = view->first; i <= view->last; i++)
+    {
+        /**
+         * Si l'adresse recherchée est plus petite que l'adresse de départ,
+         * on va effectuer un parcours complet pour rien.
+         *
+         * On considère cependant que le seul cas où celà peut arriver
+         * est lorsque que des découpages en blocs sont impliqués.
+         *
+         * Les découpages conduisent alors à la formation de petites zones,
+         * rapides à parcourir.
+         */
+
+        line = g_code_buffer_find_line_by_index(view->buffer, i);
+        range = g_buffer_line_get_range(line);
+
+        result = mrange_contains_addr(range, addr);
+        if (result) break;
+
+        *y += lheight;
+
+    }
+
+    if (result && code)
+        for (; i <= view->last; i++)
+        {
+            line = g_code_buffer_find_line_by_index(view->buffer, i);
+
+            if (g_buffer_line_get_flags(line) & BLF_HAS_CODE) break;
+
+            if (i == view->last) break;
+
+            line = g_code_buffer_find_line_by_index(view->buffer, i + 1);
+
+            range = g_buffer_line_get_range(line);
+            if (!mrange_contains_addr(range, addr)) break;
+
+            *y += lheight;
+
+        }
+
+    return result;
+
+}
diff --git a/src/glibext/gbufferview.h b/src/glibext/gbufferview.h
new file mode 100644
index 0000000..90c20bb
--- /dev/null
+++ b/src/glibext/gbufferview.h
@@ -0,0 +1,112 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gbufferview.h - prototypes pour l'affichage d'une vue particulière d'un tampon de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_GBUFFERVIEW_H
+#define _GLIBEXT_GBUFFERVIEW_H
+
+
+#include <glib-object.h>
+
+
+#include "gcodebuffer.h"
+
+
+
+#define G_TYPE_BUFFER_VIEW              (g_buffer_view_get_type())
+#define G_BUFFER_VIEW(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView))
+#define G_BUFFER_VIEW_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass))
+#define G_IS_BUFFER_VIEW(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW))
+#define G_IS_BUFFER_VIEW_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW))
+#define G_BUFFER_VIEW_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass))
+
+
+/* Vue d'un tampon pour code désassemblé (instance) */
+typedef struct _GBufferView GBufferView;
+
+/* Vue d'un tampon pour code désassemblé (classe) */
+typedef struct _GBufferViewClass GBufferViewClass;
+
+
+/* Détermine le type de la vue d'un tampon pour code désassemblé. */
+GType g_buffer_view_get_type(void);
+
+/* Crée une nouvelle vue d'un tampon pour code désassemblé. */
+GBufferView *g_buffer_view_new(GCodeBuffer *, segcnt_list *);
+
+/* Restreint le champ d'application de l'affichage. */
+void g_buffer_view_restrict(GBufferView *, const vmpa2t *, const vmpa2t *);
+
+/* Indique le champ d'application de l'affichage. */
+bool g_buffer_view_get_restrictions(GBufferView *, vmpa2t *, vmpa2t *);
+
+/* Fournit le tampon de code lié à un visualisateur donné. */
+GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *);
+
+/* Fournit la hauteur d'impression d'une ligne visualisée. */
+gint g_buffer_view_get_line_height(GBufferView *);
+
+/* Fournit la largeur requise par une visualisation. */
+gint g_buffer_view_get_width(GBufferView *, const bool *);
+
+/* Fournit la largeur requise pour dépasser les marges gauches. */
+gint g_buffer_view_get_margin(GBufferView *, const bool *);
+
+/* Fournit la hauteur requise par une visualisation. */
+gint g_buffer_view_get_height(const GBufferView *);
+
+/* Calcule la position idéale de curseur pour un point donné. */
+const vmpa2t *g_buffer_view_compute_caret(GBufferView *, gint, gint, const bool *, GdkRectangle *);
+
+/* Calcule la position idéale de curseur pour un point donné. */
+const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *);
+
+/* Déplace le curseur au sein d'une vue de tampon. */
+const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkScrollDirection, const bool *);
+
+/* Supprime toute mise en évidence de segments. */
+bool g_buffer_view_unhighlight_segments(GBufferView *);
+
+/* Surligne tous les segments similaires à celui sous la souris. */
+bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const bool *);
+
+/* Imprime la visualisation du tampon de code désassemblé. */
+void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_rectangle_int_t *, const bool *, const gint *);
+
+/* Retrouve une ligne au sein d'un tampon avec une adresse. */
+GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *, const vmpa2t *, BufferLineFlags, size_t *);
+
+/* Retrouve une ligne au sein d'un tampon avec un indice. */
+GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *, size_t );
+
+/* Fournit la ligne présente à une ordonnée donnée. */
+GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *);
+
+/* Fournit la ligne et son segment présents à une position. */
+GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint, size_t *, const bool *, GBufferSegment **);
+
+/* Indique la position d'affichage d'une adresse donnée. */
+bool g_buffer_view_get_address_coordinates(GBufferView *, const vmpa2t *, gint *, gint *, bool);
+
+
+
+#endif  /* _GLIBEXT_GBUFFERVIEW_H */
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index 346ce70..c3c5a78 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -1,6 +1,6 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * gcodebuffer.h - prototypes pour l'affichage d'un fragment de code d'assemblage
+ * gcodebuffer.c - affichage d'un fragment de code d'assemblage
  *
  * Copyright (C) 2010-2014 Cyrille Bagard
  *
@@ -100,6 +100,15 @@ static void g_buffer_scan_process(GBufferScan *, GtkStatusStack *);
 /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */
 
 
+/* Suivi distant des évolutions */
+typedef struct _view_callback
+{
+    buffer_size_changed_cb size_changed;    /* Evolution de taille         */
+    GObject *data;                          /* Données à associer          */
+
+} view_callback;
+
+
 /* Tampon pour code désassemblé (instance) */
 struct _GCodeBuffer
 {
@@ -111,8 +120,13 @@ struct _GCodeBuffer
     size_t count;                           /* Quantité en cache           */
     size_t used;                            /* Quantité utilisée           */
 
+    GWidthTracker *tracker;                 /* Suivi des largeurs          */
+
     size_t indent;                          /* Indentation des lignes      */
 
+    view_callback *vcallbacks;              /* Vues à mettre à jour        */
+    size_t vcount;                          /* Quantité de ces vues        */
+
 };
 
 /* Tampon pour code désassemblé (classe) */
@@ -137,12 +151,6 @@ static void g_code_buffer_class_init(GCodeBufferClass *);
 /* Procède à l'initialisation d'un tampon pour code désassemblé. */
 static void g_code_buffer_init(GCodeBuffer *);
 
-/* Convertit une adresse en indice de ligne. */
-static size_t g_code_buffer_get_index_from_address(const GCodeBuffer *, const vmpa2t *, bool);
-
-/* Actualise les largeurs maximales par groupes de lignes. */
-static void g_code_buffer_update_line_max_widths(const GCodeBuffer *, size_t, size_t);
-
 /* Réagit à un changement de contenu d'une ligne donnée. */
 static void on_line_content_change(GBufferLine *, GBufferSegment *, GCodeBuffer *);
 
@@ -174,70 +182,11 @@ static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *);
 
 
 
-/* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */
-
-
-/* Vue d'un tampon pour code désassemblé (instance) */
-struct _GBufferView
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    GCodeBuffer *buffer;                    /* Tampon de code visualisé    */
-    vmpa2t *start;                          /* Première ligne intégrée     */
-    vmpa2t *end;                            /* Dernière ligne intégrée     */
-    size_t first_index;                     /* Indice de la première ligne */   /* FIXME : utiliser partout ? */
-    size_t last_index;                      /* Indice de la dernière ligne */   /* FIXME : idem */
-
-    gint line_height;                       /* Hauteur maximale des lignes */
-    gint left_margin;                       /* Marge gauche + espace       */
-    gint left_text;                         /* Début d'impression du code  */
-    gint max_widths[BLC_COUNT];             /* Taille cachée des colonnes  */
-    gint merged_width;                      /* Plus grande taille de fusion*/
-
-    segcnt_list *highlighted;               /* Segments mis en évidence    */
-    bool external;                          /* Note l'origine de la liste  */
-
-};
-
-/* Vue d'un tampon pour code désassemblé (classe) */
-struct _GBufferViewClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-    /* Signaux */
-
-    void (* need_redraw) (GBufferView *);
-
-};
-
-
-#define HEIGHT_CACHED(view) ((view)->line_height != -1)
-#define WIDTHS_CACHED(view) ((view)->max_widths[0] != -1)
-
-
-/* Procède à l'initialisation d'une classe de vue de tampon. */
-static void g_buffer_view_class_init(GBufferViewClass *);
-
-/* Procède à l'initialisation d'une vue d'un tampon pour code. */
-static void g_buffer_view_init(GBufferView *);
-
-/* Supprime toutes les références externes. */
-static void g_buffer_view_dispose(GBufferView *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_buffer_view_finalize(GBufferView *);
-
-/* Réagit à un changement de contenu d'une ligne donnée. */
-static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *);
-
-/* Réinitialise le cache de la hauteur des lignes. */
-static void g_buffer_view_reset_required_height(GBufferView *);
+/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */
 
-/* Réinitialise le cache des largeurs de colonne calculées. */
-static void g_buffer_view_reset_required_widths(GBufferView *);
 
-/* Calcule les largeurs requises par une visualisation. */
-static void g_buffer_view_compute_required_widths(GBufferView *, const bool *);
+/* Fait suivre une variation de la quantité de lignes du tampon. */
+static void g_code_buffer_notify_size_changed(const GCodeBuffer *, bool, size_t, size_t);
 
 
 
@@ -444,206 +393,77 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkStatusStack *status)
 
 
 /* ---------------------------------------------------------------------------------- */
-/*                           CONFORTS POUR LES COMMENTAIRES                           */
+/*                            TAMPON POUR CODE DESASSEMBLE                            */
 /* ---------------------------------------------------------------------------------- */
 
 
+/* Détermine le type du composant de tampon pour code désassemblé. */
+G_DEFINE_TYPE(GCodeBuffer, g_code_buffer, G_TYPE_OBJECT);
+
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
-*                line    = ligne à l'intérieur d'un commentaire.              *
-*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
-*                creator = créateur à l'origine de la construction.           *
+*  Paramètres  : class = classe de composant GTK à initialiser.               *
 *                                                                             *
-*  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
+*  Description : Procède à l'initialisation d'une classe de tampon de code.   *
 *                                                                             *
-*  Retour      : Bilan de l'opération : ajout ou non ?                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
+static void g_code_buffer_class_init(GCodeBufferClass *class)
 {
-    bool result;                            /* Bilan à retourner           */
-    const mrange_t *range;                  /* Emplace de ligne à utiliser */
-    char *wcopy;                            /* Copie de travail            */
-    GBufferLine **extra;                    /* Lignes supplémentaires      */
-    size_t extra_count;                     /* Quantité de ces lignes      */
-    char *saveptr;                          /* Sauvegarde pour la sécurité */
-    char *token;                            /* Fragment à insérer          */
-    size_t len;                             /* Taille dudit fragment       */
-    GBufferSegment *segment;                /* Segment à marquer au fer    */
-    GBufferLine *new;                       /* Nouvelle ligne créée        */
-    size_t i;                               /* Boucle de parcours          */
-
-    assert(!g_buffer_line_has_comment(line));
-
-    result = false;
-
-    range = g_buffer_line_get_range(line);
-
-    wcopy = strdup(comment);
-
-    extra = NULL;
-    extra_count = 0;
-
-    for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr);
-         token != NULL;
-         token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr))
-    {
-        len = strlen(token);
-
-        if (!result)
-        {
-            segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
-            g_buffer_segment_set_creator(segment, creator);
-        }
-
-        else
-        {
-            new = g_code_buffer_prepare_new_line(buffer, range);
-
-            segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
-            g_buffer_segment_set_creator(segment, creator);
-
-            extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
-
-            extra[extra_count - 1] = new;
-
-        }
-
-        result = true;
-
-    }
-
-    free(wcopy);
-
-    if (extra_count > 0)
-    {
-        result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false);
-
-        if (!result)
-            for (i = 0; i < extra_count; i++)
-                g_object_unref(G_OBJECT(extra[i]));
-
-        free(extra);
-
-    }
-
-    return result;
+    g_signal_new("line-changed",
+                 G_TYPE_CODE_BUFFER,
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET(GCodeBufferClass, line_changed),
+                 NULL, NULL,
+                 g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
+                 G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
-*                line    = ligne à l'intérieur d'un commentaire.              *
-*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
-*                creator = créateur à l'origine de la construction.           *
+*  Paramètres  : buffer = composant GTK à initialiser.                        *
 *                                                                             *
-*  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
+*  Description : Procède à l'initialisation d'un tampon pour code désassemblé.*
 *                                                                             *
-*  Retour      : Bilan de l'opération : ajout ou non ?                        *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
+static void g_code_buffer_init(GCodeBuffer *buffer)
 {
-    bool result;                            /* Bilan à retourner           */
-
-    if (g_buffer_line_has_comment(line))
-        result = _g_code_buffer_delete_lines_comment(buffer, line);
-    else
-        result = true;
-
-    if (result)
-        result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator);
-
-    /* TODO : emit() */
-
-    return result;
+    buffer->tracker = g_width_tracker_new(buffer);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
-*                line    = ligne à l'intérieur d'un commentaire.              *
-*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
-*                before  = précise la position du commentaire.                *
-*                creator = créateur à l'origine de la construction.           *
+*  Paramètres  : main = colonne à référencer comme étant la principale.       *
 *                                                                             *
-*  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
+*  Description : Crée un nouveau composant de tampon pour code désassemblé.   *
 *                                                                             *
-*  Retour      : Bilan de l'opération : ajout ou non ?                        *
+*  Retour      : Composant GTK créé.                                          *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
+GCodeBuffer *g_code_buffer_new(BufferLineColumn main)
 {
-    bool result;                            /* Bilan à retourner           */
-    const mrange_t *range;                  /* Emplace de ligne à utiliser */
-    char *wcopy;                            /* Copie de travail            */
-    GBufferLine **extra;                    /* Lignes supplémentaires      */
-    size_t extra_count;                     /* Quantité de ces lignes      */
-    char *saveptr;                          /* Sauvegarde pour la sécurité */
-    char *token;                            /* Fragment à insérer          */
-    size_t len;                             /* Taille dudit fragment       */
-    GBufferLine *new;                       /* Nouvelle ligne créée        */
-    GBufferSegment *segment;                /* Segment à marquer au fer    */
-    size_t i;                               /* Boucle de parcours          */
-
-    assert(!g_buffer_line_has_comment(line));
-
-    result = false;
-
-    range = g_buffer_line_get_range(line);
-
-    wcopy = strdup(comment);
-
-    extra = NULL;
-    extra_count = 0;
-
-    for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr);
-         token != NULL;
-         token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr))
-    {
-        len = strlen(token);
-
-        new = g_code_buffer_prepare_new_line(buffer, range);
-        g_buffer_line_start_merge_at(new, BLC_DISPLAY);
-
-        segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
-        g_buffer_segment_set_creator(segment, creator);
-
-        extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
-
-        extra[extra_count - 1] = new;
-
-        result = true;
-
-    }
-
-    free(wcopy);
-
-    if (extra_count > 0)
-    {
-        result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, before);
-
-        if (!result)
-            for (i = 0; i < extra_count; i++)
-                g_object_unref(G_OBJECT(extra[i]));
+    GCodeBuffer *result;                    /* Composant à retourner       */
 
-        free(extra);
+    result = g_object_new(G_TYPE_CODE_BUFFER, NULL);
 
-    }
+    result->main_column = main;
 
     return result;
 
@@ -652,649 +472,40 @@ static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
-*                line    = ligne à l'intérieur d'un commentaire.              *
-*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
-*                before  = précise la position du commentaire.                *
-*                creator = créateur à l'origine de la construction.           *
+*  Paramètres  : buffer = composant GLib à consulter.                         *
 *                                                                             *
-*  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
+*  Description : Compte le nombre de lignes rassemblées dans un tampon.       *
 *                                                                             *
-*  Retour      : Bilan de l'opération : ajout ou non ?                        *
+*  Retour      : Nombre de lignes constituant le tampon.                      *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
+size_t g_code_buffer_count_lines(const GCodeBuffer *buffer)
 {
-    bool result;                            /* Bilan à retourner           */
-
-    if (g_buffer_line_has_comment(line))
-        result = _g_code_buffer_delete_lines_comment(buffer, line);
-    else
-        result = true;
-
-    if (result)
-        result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator);
-
-    /* TODO : emit() */
-
-    return result;
+    return buffer->used;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                index  = indice de ligne à l'intérieur d'un commentaire.     *
+*  Paramètres  : buffer = composant GLib à consulter.                         *
 *                                                                             *
-*  Description : Retrouve la première ligne d'une zone de commentaire.        *
+*  Description : Fournit un lien vers la structure de suivi de largeurs.      *
 *                                                                             *
-*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
+*  Retour      : Gestionnaire de largeurs de lignes.                          *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index)
+const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *buffer)
 {
-    size_t result;                          /* Indice trouvé à retourner   */
-    GBufferLine *prev;                      /* Ligne précédente            */
+    return buffer->tracker;
 
-    assert(index < buffer->used);
-
-    bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv)
-    {
-        bool first;                         /* Statut à renvoyer           */
-        BufferLineColumn merge_col;         /* Colonne de fusion #1        */
-        BufferLineColumn prev_merge_col;    /* Colonne de fusion #2        */
-
-        merge_col = g_buffer_line_get_merge_start(ln);
-
-        /**
-         * La ligne consultée contient toujours un commentaire.
-         *
-         * Deux cas de figures sont possibles ici :
-         *
-         *  - soit du texte est présent dans la colonne "commentaires".
-         *    Si du texte est présent avant, alors il s'agit forcément de
-         *    la première (et unique ?) ligne de commentaire.
-         *
-         *  - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY.
-         *    Si la ligne qui précède fait de même, il s'agit alors d'une étiquette
-         *    ou de l'amont du commentaire.
-         *
-         */
-
-        if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT))
-        {
-            first = g_buffer_line_has_text(ln, BLC_DISPLAY, BLC_COMMENTS);
-
-            if (!first)
-            {
-                /* La ligne d'avant doit avoir un commentaire ! */
-                first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT);
-            }
-
-        }
-
-        else
-        {
-            /**
-             * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable,
-             * la seule fusion possible ici est la suivante.
-             */
-            assert(merge_col == BLC_DISPLAY);
-
-            /**
-             * La première ligne d'un tampon est toujours un prologue.
-             */
-            assert(pv != NULL);
-
-            prev_merge_col = g_buffer_line_get_merge_start(pv);
-
-            first = (prev_merge_col != BLC_DISPLAY);
-
-            if (!first)
-                first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL);
-
-        }
-
-        return first;
-
-    }
-
-    for (result = index; result > 0; result--)
-    {
-        prev = (result > 0 ? buffer->lines[result - 1] : NULL);
-
-        if (is_first_line_of_comment(buffer->lines[result], prev))
-            break;
-
-    }
-
-    if (result == 0)
-    {
-        if (!is_first_line_of_comment(buffer->lines[0], NULL))
-            result = buffer->used;
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                index  = indice de ligne à l'intérieur d'un commentaire.     *
-*                                                                             *
-*  Description : Retrouve la dernière ligne d'une zone de commentaire.        *
-*                                                                             *
-*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index)
-{
-    size_t result;                          /* Indice trouvé à retourner   */
-    GBufferLine *next;                      /* Ligne suivante              */
-
-    assert(index < buffer->used);
-
-    bool is_last_line_of_comment(const GBufferLine *ln, const GBufferLine *nx)
-    {
-        bool last;                          /* Statut à renvoyer           */
-        BufferLineColumn merge_col;         /* Colonne de fusion #1        */
-        BufferLineColumn next_merge_col;    /* Colonne de fusion #2        */
-
-        merge_col = g_buffer_line_get_merge_start(ln);
-
-        /**
-         * La ligne consultée contient toujours un commentaire.
-         *
-         * Deux cas de figures sont possibles ici :
-         *
-         *  - soit du texte est présent dans la colonne "commentaires".
-         *    Si la ligne suivante est similaire et si du texte est présent avant,
-         *    alors il s'agit forcément de d'un nouveau commentaire. S'il n'y a
-         *    aucun texte, il s'agit de la suite du commentaire.
-         *
-         *  - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY.
-         *    Si la ligne qui suit fait de même, il s'agit alors d'une étiquette
-         *    ou de l'aval du commentaire.
-         *
-         */
-
-        if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT))
-        {
-            last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT);
-
-            if (!last)
-                last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS);
-
-        }
-
-        else
-        {
-            /**
-             * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable,
-             * la seule fusion possible ici est la suivante.
-             */
-            assert(merge_col == BLC_DISPLAY);
-
-            if (nx == NULL)
-                last = true;
-
-            else
-            {
-                next_merge_col = g_buffer_line_get_merge_start(nx);
-
-                last = (next_merge_col != BLC_DISPLAY);
-
-                if (!last)
-                    last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL);
-
-            }
-
-        }
-
-        return last;
-
-    }
-
-    for (result = index; result < buffer->used; result++)
-    {
-        next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL);
-
-        if (is_last_line_of_comment(buffer->lines[result], next))
-            break;
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                line   = ligne à l'intérieur d'un commentaire.               *
-*                                                                             *
-*  Description : Retrouve le créateur d'un commentaire existant.              *
-*                                                                             *
-*  Retour      : Instance trouvée à déréférencer ensuite ou NULL si aucune.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line)
-{
-    GObject *result;                        /* Instance à retourner        */
-    BufferLineColumn merge_col;             /* Colonne de fusion           */
-
-    if (g_buffer_line_has_comment(line))
-    {
-        merge_col = g_buffer_line_get_merge_start(line);
-
-        if (merge_col == BLC_DISPLAY)
-            result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY);
-        else
-            result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS);
-
-    }
-
-    else
-        result = NULL;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                line   = ligne à l'intérieur d'un commentaire.               *
-*                                                                             *
-*  Description : Récupère le contenu d'un commentaire existant.               *
-*                                                                             *
-*  Retour      : Commentaire retrouver à libérer ou NULL en cas d'échec.      *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line)
-{
-    char *result;                           /* Contenu à retourner         */
-    size_t index;                           /* Indice de la ligne fournie  */
-    size_t start;                           /* Ligne de départ             */
-    size_t end;                             /* Ligne d'arrivée             */
-    BufferLineColumn merge_col;             /* Colonne de fusion           */
-    size_t i;                               /* Boucle de parcours          */
-    char *extra;                            /* Commentaire supplémentaire  */
-
-    /* Pas de prologue ici ! */
-    assert(g_buffer_line_has_comment(line));
-
-    result = NULL;
-
-    index = g_code_buffer_find_index_by_line(buffer, line);
-
-    if (index == buffer->used)
-        goto gcbglc_exit;
-
-    start = g_code_buffer_find_first_line_comment(buffer, index);
-
-    if (start == buffer->used)
-        goto gcbglc_exit;
-
-    end = g_code_buffer_find_last_line_comment(buffer, index);
-
-    if (end == buffer->used)
-        goto gcbglc_exit;
-
-    merge_col = g_buffer_line_get_merge_start(line);
-
-    for (i = start; i <= end; i++)
-    {
-        if (merge_col == BLC_DISPLAY)
-            extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false);
-
-        else
-            extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false);
-
-        assert(extra != NULL);
-
-        if (result == NULL)
-            result = extra;
-
-        else
-        {
-            result = stradd(result, extra);
-            free(extra);
-        }
-
-    }
-
- gcbglc_exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à modifier.                        *
-*                line   = ligne à l'intérieur d'un commentaire.               *
-*                                                                             *
-*  Description : Supprime un commentaire existant.                            *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line)
-{
-    bool result;                            /* Bilan à retourner           */
-    size_t index;                           /* Indice de la ligne fournie  */
-    size_t start;                           /* Ligne de départ             */
-    size_t end;                             /* Ligne d'arrivée             */
-    BufferLineColumn merge_col;             /* Colonne de fusion           */
-
-    /* Pas de prologue ici ! */
-    assert(g_buffer_line_has_comment(line));
-
-    result = false;
-
-    index = g_code_buffer_find_index_by_line(buffer, line);
-
-    if (index == buffer->used)
-        goto gcbdlc_exit;
-
-    start = g_code_buffer_find_first_line_comment(buffer, index);
-
-    if (start == buffer->used)
-        goto gcbdlc_exit;
-
-    end = g_code_buffer_find_last_line_comment(buffer, index);
-
-    if (end == buffer->used)
-        goto gcbdlc_exit;
-
-    result = true;
-
-    merge_col = g_buffer_line_get_merge_start(line);
-
-    if (merge_col == BLC_DISPLAY)
-        g_code_buffer_delete_lines(buffer, start, end);
-
-    else
-    {
-        g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT);
-
-        if (end > start)
-            g_code_buffer_delete_lines(buffer, start + 1, end);
-
-    }
-
- gcbdlc_exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à modifier.                        *
-*                line   = ligne à l'intérieur d'un commentaire.               *
-*                                                                             *
-*  Description : Supprime un commentaire existant.                            *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line)
-{
-    bool result;                            /* Bilan à retourner           */
-
-    result = _g_code_buffer_delete_lines_comment(buffer, line);
-
-    /* TODO : emit() */
-
-    return result;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                            TAMPON POUR CODE DESASSEMBLE                            */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Détermine le type du composant de tampon pour code désassemblé. */
-G_DEFINE_TYPE(GCodeBuffer, g_code_buffer, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : class = classe de composant GTK à initialiser.               *
-*                                                                             *
-*  Description : Procède à l'initialisation d'une classe de tampon de code.   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_code_buffer_class_init(GCodeBufferClass *class)
-{
-    g_signal_new("line-changed",
-                 G_TYPE_CODE_BUFFER,
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET(GCodeBufferClass, line_changed),
-                 NULL, NULL,
-                 g_cclosure_user_marshal_VOID__OBJECT_OBJECT,
-                 G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = composant GTK à initialiser.                        *
-*                                                                             *
-*  Description : Procède à l'initialisation d'un tampon pour code désassemblé.*
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_code_buffer_init(GCodeBuffer *buffer)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : main = colonne à référencer comme étant la principale.       *
-*                                                                             *
-*  Description : Crée un nouveau composant de tampon pour code désassemblé.   *
-*                                                                             *
-*  Retour      : Composant GTK créé.                                          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GCodeBuffer *g_code_buffer_new(BufferLineColumn main)
-{
-    GCodeBuffer *result;                    /* Composant à retourner       */
-
-    result = g_object_new(G_TYPE_CODE_BUFFER, NULL);
-
-    result->main_column = main;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
-*                addr   = adresse où va se situer la ligne.                   *
-*                first  = indique si on l'arrête à la première ou la dernière.*
-*                                                                             *
-*  Description : Convertit une adresse en indice de ligne.                    *
-*                                                                             *
-*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first)
-{
-    size_t result;                          /* Indice à retourner          */
-    GBufferLine **found;                    /* Renvoi vers une trouvaille  */
-    const mrange_t *range;                  /* Couverture d'une ligne      */
-
-    /**
-     * Si aucune adresse (ie. aucune limite ?) n'est précisée, on se base sur
-     * la direction pour trouver le bon indice.
-     */
-
-    if (addr == NULL)
-        result = (first ? 0 : buffer->used - 1);
-
-    /**
-     * Sinon on parcourt méthodiquement toutes les lignes !
-     */
-
-    else
-    {
-        /* Recherche dichotomique grossière */
-
-        int cmp_addr_and_line(const vmpa2t *addr, const GBufferLine **line)
-        {
-            int status;                     /* Bilan d'une comparaison     */
-            const mrange_t *lrange;         /* Couverture d'une ligne      */
-
-            lrange = g_buffer_line_get_range(*line);
-
-            status = cmp_mrange_with_vmpa(lrange, addr);
-
-            return status;
-
-        }
-
-        found = bsearch(addr, buffer->lines, buffer->used, sizeof(GBufferLine *),
-                        (__compar_fn_t)cmp_addr_and_line);
-
-        /* Dernier raffinage pour approcher la cible réelle */
-
-        if (found == NULL)
-            result = buffer->used;
-
-        else
-        {
-            result = found - buffer->lines;
-
-            if (first)
-                for (; result > 0; result--)
-                {
-                    range = g_buffer_line_get_range(buffer->lines[result - 1]);
-                    if (!mrange_contains_addr(range, addr)) break;
-                }
-
-            else
-                for (; (result + 1) < buffer->used; result++)
-                {
-                    range = g_buffer_line_get_range(buffer->lines[result + 1]);
-                    if (!mrange_contains_addr(range, addr)) break;
-                }
-
-        }
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon contentenant un ensemble de lignes.          *
-*                first  = première ligne modifiée à considérer.               *
-*                last   = dernière ligne modifiée à considérer.               *
-*                                                                             *
-*  Description : Actualise les largeurs maximales par groupes de lignes.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_code_buffer_update_line_max_widths(const GCodeBuffer *buffer, size_t first, size_t last)
-{
-    GBufferLine **lines;                    /* Liste des lignes à traiter  */
-    size_t start;                           /* Début de groupe de largeurs */
-    size_t end;                             /* Fin de groupe de largeurs   */
-    GBufferLine *manager;                   /* Ligne de gestion de largeurs*/
-    size_t i;                               /* Boucle de parcours          */
-
-    assert(buffer->used > 0);
-
-    lines = buffer->lines;
-
-    /* Recherche des bornes du groupe de largeurs courant */
-
-    for (start = first; start > 0; start--)
-        if (g_buffer_line_get_flags(lines[start]) & BLF_WIDTH_MANAGER)
-            break;
-
-    for (end = last; end < (buffer->used - 1); end++)
-        if (g_buffer_line_get_flags(lines[end + 1]) & BLF_WIDTH_MANAGER)
-            break;
-
-    /* Réinitialisation ciblée des largeurs */
-
-    assert(g_buffer_line_get_flags(lines[start]) & BLF_WIDTH_MANAGER);
-
-    manager = NULL;
-
-    for (i = start; i <= end; i++)
-    {
-        if (g_buffer_line_get_flags(lines[i]) & BLF_WIDTH_MANAGER)
-            manager = lines[i];
-
-        g_buffer_line_update_max_widths(lines[i], manager);
-
-    }
-
-}
+}
 
 
 /******************************************************************************
@@ -1424,11 +635,9 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lin
 
     /* Recueil initial des largeurs */
 
-    /**
-     * Comme des optimisations reposant sur des cas particuliers peuvent être
-     * réalisées ici, c'est à l'appelant de prendre cette charge de calculs à
-     * son compte !
-     */
+    g_width_tracker_update_added(buffer->tracker, index, count);
+
+    g_code_buffer_notify_size_changed(buffer, true, index, count);
 
 }
 
@@ -1448,23 +657,8 @@ static void g_code_buffer_insert_lines_at(GCodeBuffer *buffer, GBufferLine **lin
 
 void g_code_buffer_append_new_line(GCodeBuffer *buffer, GBufferLine *line)
 {
-    GBufferLine *manager;                   /* Ligne de gestion de largeurs*/
-
     g_code_buffer_insert_lines_at(buffer, (GBufferLine *[]) { line }, 1, buffer->used);
 
-    /* Recueil initial des largeurs */
-
-    if (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER)
-        manager = line;
-
-    else
-    {
-        assert(buffer->used > 1);
-        manager = g_buffer_line_get_width_manager(buffer->lines[buffer->used - 2]);
-    }
-
-    g_buffer_line_update_max_widths(line, manager);
-
 }
 
 
@@ -1502,7 +696,6 @@ bool g_code_buffer_insert_lines(GCodeBuffer *buffer, GBufferLine **lines, size_t
     g_code_buffer_insert_lines_at(buffer, lines, count, index);
 
 
-    g_code_buffer_update_line_max_widths(buffer, index, index + count);
 
 
     result = true;
@@ -1547,8 +740,15 @@ void g_code_buffer_delete_lines(GCodeBuffer *buffer, size_t start, size_t end)
 
     }
 
-    memmove(&buffer->lines[start], &buffer->lines[end + 1],
-            (buffer->used - end - 1) * sizeof(GBufferLine *));
+    if ((end + 1) < buffer->used)
+        memmove(&buffer->lines[start], &buffer->lines[end + 1],
+                (buffer->used - end - 1) * sizeof(GBufferLine *));
+
+    buffer->used -= (end - start + 1);
+
+    g_width_tracker_update_deleted(buffer->tracker, start, end);
+
+    g_code_buffer_notify_size_changed(buffer, false, start, end - start + 1);
 
 }
 
@@ -1586,442 +786,198 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *buffer, const vm
         result = buffer->lines[index];
 
         if (flags != BLF_NONE)
-            while ((g_buffer_line_get_flags(result) & flags) != flags)
-            {
-                if ((index + 1) == buffer->used) break;
-
-                /* FIXME : vérifier que l'adresse est toujours celle recherchée ! */
-
-                if (idx != NULL)
-                    (*idx)++;
-
-                result = buffer->lines[++index];
-
-            }
-
-        g_object_ref(G_OBJECT(result));
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                index  = indice de la ligne recherchée.                      *
-*                                                                             *
-*  Description : Retrouve une ligne au sein d'un tampon avec un indice.       *
-*                                                                             *
-*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t index)
-{
-    GBufferLine *result;                    /* Ligne trouvée à retourner   */
-
-    if (index < buffer->used)
-        result = buffer->lines[index];
-    else
-        result = NULL;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de lignes à consulter.                       *
-*                line   = ligne dont l'indice est à retrouver.                *
-*                                                                             *
-*  Description : Retrouve l'indice associé à une ligne au sein d'un tampon.   *
-*                                                                             *
-*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-size_t g_code_buffer_find_index_by_line(const GCodeBuffer *buffer, const GBufferLine *line)
-{
-    size_t result;                          /* Indice trouvé à retourner   */
-    const mrange_t *range;                  /* Emplacement de la ligne     */
-    const mrange_t *next;                   /* Emplacement suivant         */
-
-    range = g_buffer_line_get_range(line);
-
-    result = g_code_buffer_get_index_from_address(buffer, get_mrange_addr(range), true);
-
-    /**
-     * Comme plusieurs lignes consécutives peuvent avoir la même adresse,
-     * on parcourt les lignes suivantes pour retrouver la ligne recherchée.
-     */
-
-    if (result < buffer->used)
-    {
-        while (buffer->lines[result] != line)
-        {
-            if (++result == buffer->used)
-                break;
-
-            next = g_buffer_line_get_range(buffer->lines[result]);
-
-            if (cmp_vmpa(get_mrange_addr(range), get_mrange_addr(next)) != 0)
-            {
-                result = buffer->used;
-                break;
-            }
-
-        }
-
-    }
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
-*                                                                             *
-*  Description : Augmente l'indentation des prochaines lignes.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_code_buffer_inc_indentation(GCodeBuffer *buffer)
-{
-    buffer->indent++;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
-*                                                                             *
-*  Description : Diminue l'indentation des prochaines lignes.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_code_buffer_dec_indentation(GCodeBuffer *buffer)
-{
-    /* BUG_ON(buffer->indent == 0) */
-
-    buffer->indent--;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = tampon de données à utiliser.                       *
-*                start   = première adresse visée ou 0.                       *
-*                end     = dernière adresse visée ou VMPA_MAX.                *
-*                message = message à afficher lors de la progression.         *
-*                process = fonction assurant le traitement effectif.          *
-*                data    = données utilisateur à faire suivre.                *
-*                                                                             *
-*  Description : Lance un parcours des différentes lignes du tampon de code.  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GDelayedWork *g_buffer_code_scan(GCodeBuffer *buffer, const vmpa2t *start, const vmpa2t *end, const char *message, process_line_fc process, void *data)
-{
-    GBufferScan *result;                    /* Procédure à créer / renvoyer*/
-    GWorkQueue *queue;                      /* Gestionnaire de différés    */
-
-    result = g_buffer_scan_new(buffer, start, end, message, process, data);
-    g_object_ref(G_OBJECT(result));
-
-    queue = get_work_queue();
-    g_work_queue_schedule_work(queue, G_DELAYED_WORK(result), DEFAULT_WORK_GROUP);
-
-    return G_DELAYED_WORK(result);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                        VUE PARTICULIERE D'UN TAMPON DE CODE                        */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Détermine le type de la vue d'un tampon pour code désassemblé. */
-G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : class = classe de composant GTK à initialiser.               *
-*                                                                             *
-*  Description : Procède à l'initialisation d'une classe de vue de tampon.    *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_buffer_view_class_init(GBufferViewClass *class)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-
-    object = G_OBJECT_CLASS(class);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize;
-
-    g_signal_new("need-redraw",
-                 G_TYPE_BUFFER_VIEW,
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET(GBufferViewClass, need_redraw),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__OBJECT,
-                 G_TYPE_NONE, 0);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer = composant GTK à initialiser.                        *
-*                                                                             *
-*  Description : Procède à l'initialisation d'une vue d'un tampon pour code.  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+            while ((g_buffer_line_get_flags(result) & flags) != flags)
+            {
+                if ((index + 1) == buffer->used) break;
 
-static void g_buffer_view_init(GBufferView *buffer)
-{
-    buffer->first_index = 0;
+                /* FIXME : vérifier que l'adresse est toujours celle recherchée ! */
 
-    g_buffer_view_reset_required_height(buffer);
-    g_buffer_view_reset_required_widths(buffer);
+                if (idx != NULL)
+                    (*idx)++;
 
-}
+                result = buffer->lines[++index];
 
+            }
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view = instance d'objet GLib à traiter.                      *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        g_object_ref(G_OBJECT(result));
 
-static void g_buffer_view_dispose(GBufferView *view)
-{
-    g_object_unref(G_OBJECT(view->buffer));
+    }
 
-    G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view));
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = instance d'objet GLib à traiter.                      *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                index  = indice de la ligne recherchée.                      *
 *                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
+*  Description : Retrouve une ligne au sein d'un tampon avec un indice.       *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void g_buffer_view_finalize(GBufferView *view)
+GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t index)
 {
-    if (!view->external)
-        exit_segment_content_list(view->highlighted);
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
 
-    G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view));
+    /* TODO : ref */
+
+    if (index < buffer->used)
+        result = buffer->lines[index];
+    else
+        result = NULL;
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : buffer = tampon à représenter à l'écran.                     *
-*                widget = composant GTK de destination pour le rendu.         *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
+*                addr   = adresse où va se situer la ligne.                   *
+*                first  = indique si on l'arrête à la première ou la dernière.*
 *                                                                             *
-*  Description : Crée une nouvelle vue d'un tampon pour code désassemblé.     *
+*  Description : Convertit une adresse en indice de ligne.                    *
 *                                                                             *
-*  Retour      : Composant GTK créé.                                          *
+*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted)
+size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first)
 {
-    GBufferView *result;                    /* Composant à retourner       */
+    size_t result;                          /* Indice à retourner          */
+    GBufferLine **found;                    /* Renvoi vers une trouvaille  */
+    const mrange_t *range;                  /* Couverture d'une ligne      */
 
-    result = g_object_new(G_TYPE_BUFFER_VIEW, NULL);
+    /**
+     * Si aucune adresse (ie. aucune limite ?) n'est précisée, on se base sur
+     * la direction pour trouver le bon indice.
+     */
 
-    g_object_ref(G_OBJECT(buffer));
+    if (addr == NULL)
+        result = (first ? 0 : buffer->used - 1);
 
-    result->buffer = buffer;
+    /**
+     * Sinon on parcourt méthodiquement toutes les lignes !
+     */
 
-    g_buffer_view_restrict(result, NULL, NULL);
+    else
+    {
+        /* Recherche dichotomique grossière */
 
-    g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result);
+        int cmp_addr_and_line(const vmpa2t *addr, const GBufferLine **line)
+        {
+            int status;                     /* Bilan d'une comparaison     */
+            const mrange_t *lrange;         /* Couverture d'une ligne      */
 
-    if (highlighted != NULL)
-        result->highlighted = highlighted;
-    else
-        result->highlighted = init_segment_content_list();
+            lrange = g_buffer_line_get_range(*line);
 
-    result->external = (highlighted != NULL);
+            status = cmp_mrange_with_vmpa(lrange, addr);
 
-    return result;
+            return status;
 
-}
+        }
 
+        found = bsearch(addr, buffer->lines, buffer->used, sizeof(GBufferLine *),
+                        (__compar_fn_t)cmp_addr_and_line);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : buffer  = tampon de lignes cohérentes à manipuler.           *
-*                line    = ligne dont la définition vient d'évoluer.          *
-*                segment = éventuel segment qui vient d'évoluer ou NULL.      *
-*                view    = vue active du tampon de lignes concerné.           *
-*                                                                             *
-*  Description : Réagit à un changement de contenu d'une ligne donnée.        *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        /* Dernier raffinage pour approcher la cible réelle */
 
-static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view)
-{
-    /* TODO : regarder si la vue et concernée et cibler d'avantage l'actualisation */
+        if (found == NULL)
+            result = buffer->used;
 
-    g_signal_emit_by_name(view, "need-redraw");
+        else
+        {
+            result = found - buffer->lines;
 
-}
+            if (first)
+                for (; result > 0; result--)
+                {
+                    range = g_buffer_line_get_range(buffer->lines[result - 1]);
+                    if (!mrange_contains_addr(range, addr)) break;
+                }
 
+            else
+                for (; (result + 1) < buffer->used; result++)
+                {
+                    range = g_buffer_line_get_range(buffer->lines[result + 1]);
+                    if (!mrange_contains_addr(range, addr)) break;
+                }
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view  = visualisateur à mettre à jour.                       *
-*                first = première ligne à imprimer.                           *
-*                last  = première ligne hors cadre.                           *
-*                                                                             *
-*  Description : Restreint le champ d'application de l'affichage.             *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        }
 
-void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end)
-{
-    view->start = (start != NULL ? dup_vmpa(start) : NULL);
-    view->end = (end != NULL ? dup_vmpa(end) : NULL);
+    }
 
-    view->first_index = g_code_buffer_get_index_from_address(view->buffer, start, true);
-    view->last_index = g_code_buffer_get_index_from_address(view->buffer, end, false);
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view  = visualisateur à mettre à jour.                       *
-*                first = première ligne à imprimer ou NULL. [OUT]             *
-*                last  = première ligne hors cadre ou NULL. [OUT]             *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                line   = ligne dont l'indice est à retrouver.                *
 *                                                                             *
-*  Description : Indique le champ d'application de l'affichage.               *
+*  Description : Retrouve l'indice associé à une ligne au sein d'un tampon.   *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end)
+size_t g_code_buffer_find_index_by_line(const GCodeBuffer *buffer, const GBufferLine *line)
 {
-    /* FIXME view->xxx == NULL -> plantage */
+    size_t result;                          /* Indice trouvé à retourner   */
+    const mrange_t *range;                  /* Emplacement de la ligne     */
+    const mrange_t *next;                   /* Emplacement suivant         */
 
-    if (start != NULL) copy_vmpa(start, view->start);
-    if (end != NULL) copy_vmpa(end, view->end);
+    range = g_buffer_line_get_range(line);
 
-}
+    result = g_code_buffer_get_index_from_address(buffer, get_mrange_addr(range), true);
 
+    /**
+     * Comme plusieurs lignes consécutives peuvent avoir la même adresse,
+     * on parcourt les lignes suivantes pour retrouver la ligne recherchée.
+     */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view = visualisateur à consulter.                            *
-*                                                                             *
-*  Description : Fournit le tampon de code lié à un visualisateur donné.      *
-*                                                                             *
-*  Retour      : Tampon de code associé au gestionnaire d'affichage.          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    if (result < buffer->used)
+    {
+        while (buffer->lines[result] != line)
+        {
+            if (++result == buffer->used)
+                break;
 
-GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view)
-{
-    return view->buffer;
+            next = g_buffer_line_get_range(buffer->lines[result]);
 
-}
+            if (cmp_vmpa(get_mrange_addr(range), get_mrange_addr(next)) != 0)
+            {
+                result = buffer->used;
+                break;
+            }
 
+        }
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
-*                                                                             *
-*  Description : Réinitialise le cache de la hauteur des lignes.              *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    }
 
-static void g_buffer_view_reset_required_height(GBufferView *view)
-{
-    view->line_height = -1;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
 *                                                                             *
-*  Description : Réinitialise le cache des largeurs de colonne calculées.     *
+*  Description : Augmente l'indentation des prochaines lignes.                *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -2029,23 +985,18 @@ static void g_buffer_view_reset_required_height(GBufferView *view)
 *                                                                             *
 ******************************************************************************/
 
-static void g_buffer_view_reset_required_widths(GBufferView *view)
+void g_code_buffer_inc_indentation(GCodeBuffer *buffer)
 {
-    unsigned int i;                         /* Boucle de parcours          */
-
-    for (i = 0; i < BLC_COUNT; i++)
-        view->max_widths[i] = -1;
-
-    view->merged_width = 0;
+    buffer->indent++;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à mettre à jour.                        *
+*  Paramètres  : buffer = composant GTK à mettre à jour.                      *
 *                                                                             *
-*  Description : Calcule la hauteur requise par une visualisation.            *
+*  Description : Diminue l'indentation des prochaines lignes.                 *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -2053,19 +1004,25 @@ static void g_buffer_view_reset_required_widths(GBufferView *view)
 *                                                                             *
 ******************************************************************************/
 
-static void g_buffer_view_compute_required_height(GBufferView *view)
+void g_code_buffer_dec_indentation(GCodeBuffer *buffer)
 {
-    view->line_height = 17;
+    /* BUG_ON(buffer->indent == 0) */
+
+    buffer->indent--;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à mettre à jour.                        *
-*                display = règles d'affichage des colonnes modulables.        *
+*  Paramètres  : buffer = tampon de données à utiliser.                       *
+*                start   = première adresse visée ou 0.                       *
+*                end     = dernière adresse visée ou VMPA_MAX.                *
+*                message = message à afficher lors de la progression.         *
+*                process = fonction assurant le traitement effectif.          *
+*                data    = données utilisateur à faire suivre.                *
 *                                                                             *
-*  Description : Calcule les largeurs requises par une visualisation.         *
+*  Description : Lance un parcours des différentes lignes du tampon de code.  *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -2073,114 +1030,110 @@ static void g_buffer_view_compute_required_height(GBufferView *view)
 *                                                                             *
 ******************************************************************************/
 
-static void g_buffer_view_compute_required_widths(GBufferView *view, const bool *display)
+GDelayedWork *g_buffer_code_scan(GCodeBuffer *buffer, const vmpa2t *start, const vmpa2t *end, const char *message, process_line_fc process, void *data)
 {
-    GBufferLine **lines;                    /* Liste des lignes à traiter  */
-    size_t first;                           /* Première ligne intégrée     */
-    size_t last;                            /* Dernière ligne intégrée     */
-    size_t i;                               /* Boucle de parcours          */
-
-    if (!HEIGHT_CACHED(view))
-        g_buffer_view_compute_required_height(view);
+    GBufferScan *result;                    /* Procédure à créer / renvoyer*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
 
-    lines = view->buffer->lines;
+    result = g_buffer_scan_new(buffer, start, end, message, process, data);
+    g_object_ref(G_OBJECT(result));
 
-    first = g_code_buffer_get_index_from_address(view->buffer, view->start, true);
-    last = g_code_buffer_get_index_from_address(view->buffer, view->end, false);
+    queue = get_work_queue();
+    g_work_queue_schedule_work(queue, G_DELAYED_WORK(result), DEFAULT_WORK_GROUP);
 
-    view->left_margin = 2 * view->line_height;
-    view->left_text = 2.5 * view->line_height;
+    return G_DELAYED_WORK(result);
 
-    if (view->buffer->used > 0)
-    {
-        //g_code_buffer_update_line_max_widths(view->buffer, first, last);
+}
 
-        for (i = first; i <= last; i++)
-            g_buffer_line_apply_max_widths(lines[i], view->max_widths, &view->merged_width);
 
-    }
 
-}
+/* ---------------------------------------------------------------------------------- */
+/*                           CONFORTS POUR LES COMMENTAIRES                           */
+/* ---------------------------------------------------------------------------------- */
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
+*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
+*                line    = ligne à l'intérieur d'un commentaire.              *
+*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
-*  Description : Fournit la hauteur d'impression d'une ligne visualisée.      *
+*  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
 *                                                                             *
-*  Retour      : Hauteur de ligne en pixel.                                   *
+*  Retour      : Bilan de l'opération : ajout ou non ?                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-gint g_buffer_view_get_line_height(GBufferView *view)
+static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
 {
-    if (!HEIGHT_CACHED(view))
-        g_buffer_view_compute_required_height(view);
+    bool result;                            /* Bilan à retourner           */
+    const mrange_t *range;                  /* Emplace de ligne à utiliser */
+    char *wcopy;                            /* Copie de travail            */
+    GBufferLine **extra;                    /* Lignes supplémentaires      */
+    size_t extra_count;                     /* Quantité de ces lignes      */
+    char *saveptr;                          /* Sauvegarde pour la sécurité */
+    char *token;                            /* Fragment à insérer          */
+    size_t len;                             /* Taille dudit fragment       */
+    GBufferSegment *segment;                /* Segment à marquer au fer    */
+    GBufferLine *new;                       /* Nouvelle ligne créée        */
+    size_t i;                               /* Boucle de parcours          */
 
-    return view->line_height;
+    assert(!g_buffer_line_has_comment(line));
 
-}
+    result = false;
 
+    range = g_buffer_line_get_range(line);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view    = visualisation à consulter.                         *
-*                display = règles d'affichage des colonnes modulables.        *
-*                                                                             *
-*  Description : Fournit la largeur requise par une visualisation.            *
-*                                                                             *
-*  Retour      : Dimension calculée.                                          *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    wcopy = strdup(comment);
 
-gint g_buffer_view_get_width(GBufferView *view, const bool *display)
-{
-    gint result;                            /* Taille à retourner          */
-    gint col_width;                         /* Calcul selon les colonnes   */
-    gint full_width;                        /* Calcul selon les fusions    */
-    BufferLineColumn i;                     /* Boucle de parcours          */
+    extra = NULL;
+    extra_count = 0;
+
+    for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr);
+         token != NULL;
+         token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr))
+    {
+        len = strlen(token);
 
-    if (!WIDTHS_CACHED(view))
-        g_buffer_view_compute_required_widths(view, display);
+        if (!result)
+        {
+            segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT);
+            g_buffer_segment_set_creator(segment, creator);
+        }
 
-    result = view->left_text;
+        else
+        {
+            new = g_code_buffer_prepare_new_line(buffer, range);
 
-    col_width = 0;
-    full_width = 0;
+            segment = g_buffer_line_insert_text(new, BLC_COMMENTS, token, len, RTT_COMMENT);
+            g_buffer_segment_set_creator(segment, creator);
 
-    /* Première méthode */
+            extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
 
-    for (i = 0; i < BLC_COUNT; i++)
-    {
-        if (i < BLC_DISPLAY && !display[i]) continue;
+            extra[extra_count - 1] = new;
 
-        col_width += view->max_widths[i];
+        }
 
-        if ((i + 1) < BLC_COUNT)
-            col_width += COL_MARGIN;
+        result = true;
 
     }
 
-    /* Seconde méthode */
+    free(wcopy);
 
-    for (i = 0; i < BLC_DISPLAY; i++)
+    if (extra_count > 0)
     {
-        if (!display[i]) continue;
-
-        full_width += view->max_widths[i] + COL_MARGIN;
-
-    }
+        result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false);
 
-    full_width += view->merged_width;
+        if (!result)
+            for (i = 0; i < extra_count; i++)
+                g_object_unref(G_OBJECT(extra[i]));
 
-    /* Mise en concurrence et poursuite... */
+        free(extra);
 
-    result += + MAX(col_width, full_width);
+    }
 
     return result;
 
@@ -2189,34 +1142,32 @@ gint g_buffer_view_get_width(GBufferView *view, const bool *display)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view    = visualisation à consulter.                         *
-*                display = règles d'affichage des colonnes modulables.        *
+*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
+*                line    = ligne à l'intérieur d'un commentaire.              *
+*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
-*  Description : Fournit la largeur requise pour dépasser les marges gauches. *
+*  Description : Affiche un commentaire sur une ligne de tampon donnée.       *
 *                                                                             *
-*  Retour      : Dimension calculée.                                          *
+*  Retour      : Bilan de l'opération : ajout ou non ?                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-gint g_buffer_view_get_margin(GBufferView *view, const bool *display)
+bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator)
 {
-    gint result;                            /* Taille à retourner          */
-    BufferLineColumn i;                     /* Boucle de parcours          */
-
-    if (!WIDTHS_CACHED(view))
-        g_buffer_view_compute_required_widths(view, display);
-
-    result = view->left_text;
+    bool result;                            /* Bilan à retourner           */
 
-    for (i = 0; i < BLC_DISPLAY; i++)
-    {
-        if (!display[i]) continue;
+    if (g_buffer_line_has_comment(line))
+        result = _g_code_buffer_delete_lines_comment(buffer, line);
+    else
+        result = true;
 
-        result += view->max_widths[i] + COL_MARGIN;
+    if (result)
+        result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator);
 
-    }
+    /* TODO : emit() */
 
     return result;
 
@@ -2225,226 +1176,214 @@ gint g_buffer_view_get_margin(GBufferView *view, const bool *display)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
+*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
+*                line    = ligne à l'intérieur d'un commentaire.              *
+*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                before  = précise la position du commentaire.                *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
-*  Description : Fournit la hauteur requise par une visualisation.            *
+*  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
 *                                                                             *
-*  Retour      : Dimension calculée.                                          *
+*  Retour      : Bilan de l'opération : ajout ou non ?                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-gint g_buffer_view_get_height(const GBufferView *view)
+static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
 {
-    gint result;                            /* Taille à retourner          */
-    size_t first;                           /* Première ligne intégrée     */
-    size_t last;                            /* Dernière ligne intégrée     */
-
-    result = view->line_height;
-
-    first = g_code_buffer_get_index_from_address(view->buffer, view->start, true);
-    last = g_code_buffer_get_index_from_address(view->buffer, view->end, false);
-
-    result *= (last - first + 1);
-
-    return result;
-
-}
-
+    bool result;                            /* Bilan à retourner           */
+    const mrange_t *range;                  /* Emplace de ligne à utiliser */
+    char *wcopy;                            /* Copie de travail            */
+    GBufferLine **extra;                    /* Lignes supplémentaires      */
+    size_t extra_count;                     /* Quantité de ces lignes      */
+    char *saveptr;                          /* Sauvegarde pour la sécurité */
+    char *token;                            /* Fragment à insérer          */
+    size_t len;                             /* Taille dudit fragment       */
+    GBufferLine *new;                       /* Nouvelle ligne créée        */
+    GBufferSegment *segment;                /* Segment à marquer au fer    */
+    size_t i;                               /* Boucle de parcours          */
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
-*                x       = abscisse de la zone principale à traiter.          *
-*                y       = ordonnée de la zone principale à traiter.          *
-*                display = règles d'affichage des colonnes modulables.        *
-*                caret   = position du curseur à construire. [OUT]            *
-*                                                                             *
-*  Description : Calcule la position idéale de curseur pour un point donné.   *
-*                                                                             *
-*  Retour      : Adresse si une a pu être déterminée, NULL sinon.             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    assert(!g_buffer_line_has_comment(line));
 
-const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret)
-{
-    gint remaining;                         /* Copie de travail modifiable */
-    size_t index;                           /* Indice de ligne de tampon   */
-    GBufferLine *line;                      /* Ligne à la position courante*/
-    GBufferSegment *segment;                /* Segment présent sur la place*/
+    result = false;
 
-    remaining = x;
+    range = g_buffer_line_get_range(line);
 
-    line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment);
+    wcopy = strdup(comment);
 
-    if (line == NULL) return NULL;
-    if (segment == NULL) printf(" -- no segment\n");
-    if (segment == NULL) return NULL;
+    extra = NULL;
+    extra_count = 0;
 
+    for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr);
+         token != NULL;
+         token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr))
+    {
+        len = strlen(token);
 
+        new = g_code_buffer_prepare_new_line(buffer, range);
+        g_buffer_line_start_merge_at(new, BLC_DISPLAY);
 
+        segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT);
+        g_buffer_segment_set_creator(segment, creator);
 
+        extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *));
 
-    printf("\n[BASE]  orig = %d   tronc = %d   reste = %d   dernier = %d   largeur = %d\n",
-           x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining),
-           g_buffer_segment_get_width(segment));
+        extra[extra_count - 1] = new;
 
-    printf("        '%s'\n", g_buffer_segment_get_text(segment, false));
+        result = true;
 
+    }
 
+    free(wcopy);
 
+    if (extra_count > 0)
+    {
+        result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, before);
 
-    caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining);
+        if (!result)
+            for (i = 0; i < extra_count; i++)
+                g_object_unref(G_OBJECT(extra[i]));
 
-    caret->y = (index - view->first_index) * view->line_height;
+        free(extra);
 
-    caret->width = 2;
-    caret->height = view->line_height;
+    }
 
-    return get_mrange_addr(g_buffer_line_get_range(line));
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
-*                line    = ligne correspondant à la position.                 *
-*                index   = indice de cette même ligne dans le tampon.         *
-*                x       = abscisse de la zone principale à traiter.          *
-*                display = règles d'affichage des colonnes modulables.        *
-*                caret   = position du curseur à construire. [OUT]            *
+*  Paramètres  : buffer  = tampon de lignes à consulter.                      *
+*                line    = ligne à l'intérieur d'un commentaire.              *
+*                comment = nouveau commentaire à inscrire à la ligne donnée.  *
+*                before  = précise la position du commentaire.                *
+*                creator = créateur à l'origine de la construction.           *
 *                                                                             *
-*  Description : Calcule la position idéale de curseur pour un point donné.   *
+*  Description : Affiche un commentaire sur une ligne de tampon dédiée.       *
 *                                                                             *
-*  Retour      : Adresse si une a pu être déterminée, NULL sinon.             *
+*  Retour      : Bilan de l'opération : ajout ou non ?                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret)
+bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator)
 {
-    gint offset;                            /* Point de travail modifiable */
-    gint base;                              /* Position absolue de segment */
-    GBufferSegment *segment;                /* Segment visé par le pointeur*/
-
-    offset = x;
-
-    offset -= view->left_text;
-    if (offset < 0) return NULL;
-
-    segment = g_buffer_line_get_segment_at(line, view->max_widths, display, &base, &offset, GDK_SCROLL_LEFT, true);
-    if (segment == NULL) return NULL;
-
-    caret->x = view->left_text + base + offset;
+    bool result;                            /* Bilan à retourner           */
 
-    printf("caret Y : %zu -> %zu\n", view->first_index, index);
+    if (g_buffer_line_has_comment(line))
+        result = _g_code_buffer_delete_lines_comment(buffer, line);
+    else
+        result = true;
 
-    caret->y = (index - view->first_index) * view->line_height;
+    if (result)
+        result = _g_code_buffer_write_comment_area(buffer, line, comment, before, creator);
 
-    caret->width = 2;
-    caret->height = view->line_height;
+    /* TODO : emit() */
 
-    return get_mrange_addr(g_buffer_line_get_range(line));
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : line    = ligne à venir consulter.                           *
-*                caret   = position du curseur à faire évoluer.               *
-*                ctrl    = indique la demande d'un parcours rapide.           *
-*                dir     = direction du parcours.                             *
-*                display = règles d'affichage des colonnes modulables.        *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                index  = indice de ligne à l'intérieur d'un commentaire.     *
 *                                                                             *
-*  Description : Déplace le curseur au sein d'une vue de tampon.              *
+*  Description : Retrouve la première ligne d'une zone de commentaire.        *
 *                                                                             *
-*  Retour      : true si un déplacement a été effectué, false sinon.          *
+*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
+static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index)
 {
-    bool result;                            /* Bilan à retourner           */
-    gint offset;                            /* Point de travail modifiable */
-    gint base;                              /* Position absolue de segment */
-    GBufferSegment *segment;                /* Segment visé par le pointeur*/
-
-
-
-    offset = caret->x;
-
-    offset -= view->left_text;
-    if (offset < 0) return false;
-
-    segment = g_buffer_line_get_segment_at(line, view->max_widths, display, &base, &offset, dir, false);
-
-    if (segment == NULL) printf(" ===== NO SEG...\n");
-
-    if (segment == NULL) return false;
-
-
-    printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false));
-
-
-
-
-
+    size_t result;                          /* Indice trouvé à retourner   */
+    GBufferLine *prev;                      /* Ligne précédente            */
 
-    //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT)
-        result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
-    //else
-        //result = true;
+    assert(index < buffer->used);
 
-    printf(" ====== MOVE 1 ? %d\n", result);
+    bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv)
+    {
+        bool first;                         /* Statut à renvoyer           */
+        BufferLineColumn merge_col;         /* Colonne de fusion #1        */
+        BufferLineColumn prev_merge_col;    /* Colonne de fusion #2        */
 
-    ///////////////////
+        merge_col = g_buffer_line_get_merge_start(ln);
 
-    if (!result)
-    {
-        base = 0;
+        /**
+         * La ligne consultée contient toujours un commentaire.
+         *
+         * Deux cas de figures sont possibles ici :
+         *
+         *  - soit du texte est présent dans la colonne "commentaires".
+         *    Si du texte est présent avant, alors il s'agit forcément de
+         *    la première (et unique ?) ligne de commentaire.
+         *
+         *  - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY.
+         *    Si la ligne qui précède fait de même, il s'agit alors d'une étiquette
+         *    ou de l'amont du commentaire.
+         *
+         */
 
-        segment = g_buffer_line_find_near_segment(line, segment, view->max_widths, display, dir, &offset);
+        if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT))
+        {
+            first = g_buffer_line_has_text(ln, BLC_DISPLAY, BLC_COMMENTS);
 
+            if (!first)
+            {
+                /* La ligne d'avant doit avoir un commentaire ! */
+                first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT);
+            }
 
-        printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL);
+        }
 
-        if (segment != NULL)
+        else
         {
+            /**
+             * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable,
+             * la seule fusion possible ici est la suivante.
+             */
+            assert(merge_col == BLC_DISPLAY);
 
-            result = true;
-            //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
+            /**
+             * La première ligne d'un tampon est toujours un prologue.
+             */
+            assert(pv != NULL);
 
-            /*
-            if (result)
-                caret->x -= COL_MARGIN;
-            */
+            prev_merge_col = g_buffer_line_get_merge_start(pv);
 
-            printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset);
+            first = (prev_merge_col != BLC_DISPLAY);
 
+            if (!first)
+                first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL);
 
         }
 
+        return first;
 
     }
 
+    for (result = index; result > 0; result--)
+    {
+        prev = (result > 0 ? buffer->lines[result - 1] : NULL);
 
-    if (result)
-        printf(" ====== NEW CARET: %d -> %d\n", caret->x, view->left_text + base + offset);
-    else
-        printf(" ====== NO NEW CARET!\n");
-
+        if (is_first_line_of_comment(buffer->lines[result], prev))
+            break;
 
+    }
 
-    if (result)
-        caret->x = view->left_text + base + offset;
+    if (result == 0)
+    {
+        if (!is_first_line_of_comment(buffer->lines[0], NULL))
+            result = buffer->used;
+    }
 
     return result;
 
@@ -2453,169 +1392,93 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
-*                caret   = position du curseur à faire évoluer.               *
-*                ctrl    = indique la demande d'un parcours rapide.           *
-*                dir     = direction du parcours.                             *
-*                display = règles d'affichage des colonnes modulables.        *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                index  = indice de ligne à l'intérieur d'un commentaire.     *
 *                                                                             *
-*  Description : Déplace le curseur au sein d'une vue de tampon.              *
+*  Description : Retrouve la dernière ligne d'une zone de commentaire.        *
 *                                                                             *
-*  Retour      : Adresse si une a pu être déterminée, VMPA_INVALID sinon.     *
+*  Retour      : Indice de l'adresse trouvée, ou le nombre de lignes sinon.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
-{
-    const vmpa2t *result;                   /* Actualisation à renvoyer    */
-    size_t index;                           /* Indice de ligne de tampon   */
-    GBufferLine *line;                      /* Ligne sous le pointeur      */
-
-
-    bool computed;                          /* Récursivité pris en compte  */
-    gint lheight;                           /* Hauteur d'une ligne         */
-    gint left_pos;                          /* Retour à la ligne           */
-    gint right_pos;                         /* Position d'extrème droite   */
-    BufferLineColumn i;                     /* Boucle de parcours          */
-    size_t first;                           /* Première ligne intégrée     */
-    size_t last;                            /* Dernière ligne intégrée     */
-
-
-
-
-    bool moved;                             /* Mémorisation d'une évolut°  */
-
-
-
-
-
-
-
-
-
-    result = NULL;
-    computed = false;
-
-
-
-    line = g_buffer_view_find_line_at(view, caret->y, &index);
-    if (line == NULL) return NULL;
-
-
-    lheight = g_buffer_view_get_line_height(view);
-
-
-    switch (dir)
-    {
-        case GDK_SCROLL_UP:
-        case GDK_SCROLL_DOWN:
-            lheight = g_buffer_view_get_line_height(view);
-            break;
-        case GDK_SCROLL_LEFT:
-        case GDK_SCROLL_RIGHT:
-            left_pos = view->left_text;
-            if (display[BLC_PHYSICAL]) left_pos += view->max_widths[BLC_PHYSICAL] + COL_MARGIN;
-            if (display[BLC_VIRTUAL]) left_pos += view->max_widths[BLC_VIRTUAL] + COL_MARGIN;
-            if (display[BLC_BINARY]) left_pos += view->max_widths[BLC_BINARY] + COL_MARGIN;
-            right_pos = left_pos;
-            for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++)
-                right_pos += view->max_widths[i] + COL_MARGIN;
-
-            /*
-gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths)
-
-BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
-            */
-
-            left_pos = view->left_text;
-
-            break;
-        default:    /* GDK_SCROLL_SMOOTH */
-            break;
-    }
-
-    first = view->first_index;
-    last = view->last_index;
-
-    switch (dir)
-    {
-        case GDK_SCROLL_UP:
-
-            if (index > first)
-            {
-                line = view->buffer->lines[index - 1];
-                result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret);
-            }
-
-            break;
-
-        case GDK_SCROLL_DOWN:
+static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index)
+{
+    size_t result;                          /* Indice trouvé à retourner   */
+    GBufferLine *next;                      /* Ligne suivante              */
 
-            if (index < last)
-            {
-                line = view->buffer->lines[index + 1];
-                result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret);
-            }
+    assert(index < buffer->used);
 
-            break;
+    bool is_last_line_of_comment(const GBufferLine *ln, const GBufferLine *nx)
+    {
+        bool last;                          /* Statut à renvoyer           */
+        BufferLineColumn merge_col;         /* Colonne de fusion #1        */
+        BufferLineColumn next_merge_col;    /* Colonne de fusion #2        */
 
-        case GDK_SCROLL_LEFT:
+        merge_col = g_buffer_line_get_merge_start(ln);
 
-            /*
-            line = g_buffer_view_find_line_at(view, caret->y, &index);
-            if (line == NULL) break;
-            */
+        /**
+         * La ligne consultée contient toujours un commentaire.
+         *
+         * Deux cas de figures sont possibles ici :
+         *
+         *  - soit du texte est présent dans la colonne "commentaires".
+         *    Si la ligne suivante est similaire et si du texte est présent avant,
+         *    alors il s'agit forcément de d'un nouveau commentaire. S'il n'y a
+         *    aucun texte, il s'agit de la suite du commentaire.
+         *
+         *  - soit la ligne effectue une fusion des colonnes depuis BLC_DISPLAY.
+         *    Si la ligne qui suit fait de même, il s'agit alors d'une étiquette
+         *    ou de l'aval du commentaire.
+         *
+         */
 
-            moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_LEFT, display);
+        if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT))
+        {
+            last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT);
 
-            if (moved)
-                result = get_mrange_addr(g_buffer_line_get_range(line));
+            if (!last)
+                last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS);
 
-            else if (index > first)
-            {
-                line = view->buffer->lines[index - 1];
-                result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret);
-            }
+        }
 
-            break;
+        else
+        {
+            /**
+             * Le prologue "merge_col == BLC_FIRST" n'étant pas éditable,
+             * la seule fusion possible ici est la suivante.
+             */
+            assert(merge_col == BLC_DISPLAY);
 
-        case GDK_SCROLL_RIGHT:
+            if (nx == NULL)
+                last = true;
 
-            /*
-            line = g_buffer_view_find_line_at(view, caret->y, &index);
-            if (line == NULL) break;
-            */
+            else
+            {
+                next_merge_col = g_buffer_line_get_merge_start(nx);
 
-            moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_RIGHT, display);
+                last = (next_merge_col != BLC_DISPLAY);
 
-            if (moved)
-                result = get_mrange_addr(g_buffer_line_get_range(line));
+                if (!last)
+                    last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL);
 
-            else if (index < last)
-            {
-                line = view->buffer->lines[index + 1];
-                result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret);
             }
 
-            break;
+        }
 
-        default:    /* GDK_SCROLL_SMOOTH */
-            break;
+        return last;
 
     }
 
-    /*
-    printf(" --- CARET ---   moved = %d   index = %d   result = %p\n",
-           moved, index, result);
-    */
+    for (result = index; result < buffer->used; result++)
+    {
+        next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL);
 
+        if (is_last_line_of_comment(buffer->lines[result], next))
+            break;
 
-    /*
-    if (result && !computed)
-        result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL);
-    */
+    }
 
     return result;
 
@@ -2624,180 +1487,172 @@ BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = vue de tampon à mettre à jour.                        *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                line   = ligne à l'intérieur d'un commentaire.               *
 *                                                                             *
-*  Description : Supprime toute mise en évidence de segments.                 *
+*  Description : Retrouve le créateur d'un commentaire existant.              *
 *                                                                             *
-*  Retour      : true si un besoin d'actualisation d'affichage se fait sentir.*
+*  Retour      : Instance trouvée à déréférencer ensuite ou NULL si aucune.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_buffer_view_unhighlight_segments(GBufferView *view)
+GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line)
 {
-    bool result;                            /* Bilan d'action à renvoyer   */
-
-    result = reset_segment_content_list(view->highlighted);
-
-    return result;
-
-}
+    GObject *result;                        /* Instance à retourner        */
+    BufferLineColumn merge_col;             /* Colonne de fusion           */
 
+    if (g_buffer_line_has_comment(line))
+    {
+        merge_col = g_buffer_line_get_merge_start(line);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view    = vue de tampon à mettre à jour.                     *
-*                x       = abscisse de la zone principale à traiter.          *
-*                y       = ordonnée de la zone principale à traiter.          *
-*                display = règles d'affichage des colonnes modulables.        *
-*                                                                             *
-*  Description : Surligne tous les segments similaires à celui sous la souris.*
-*                                                                             *
-*  Retour      : true si un besoin d'actualisation d'affichage se fait sentir.*
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        if (merge_col == BLC_DISPLAY)
+            result = g_buffer_line_find_first_segment_creator(line, BLC_DISPLAY);
+        else
+            result = g_buffer_line_find_first_segment_creator(line, BLC_COMMENTS);
 
-bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const bool *display)
-{
-    bool need_redraw;                       /* Besoin d'actualisation ?    */
-    GBufferSegment *segment;                /* Segment sélectionnable      */
+    }
 
-    if (view->highlighted != NULL)
-        need_redraw = g_buffer_view_unhighlight_segments(view);
     else
-        need_redraw = false;
-
-    g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment);
-
-    if (segment)
-        need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment);
-
-    if (need_redraw)
-        g_signal_emit_by_name(view, "need-redraw");
+        result = NULL;
 
-    return true;
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view     = visualisation à représenter.                      *
-*                cr       = contexte graphique dédié à la procédure.          *
-*                fake_x   = abscisse réelle du point 0 à l'écran.             *
-*                fake_y   = ordonnée réelle du point 0 à l'écran.             *
-*                area     = position et surface à traiter.                    *
-*                display  = règles d'affichage des colonnes modulables.       *
-*                selected = ordonnée d'une ligne sélectionnée ou NULL.        *
+*  Paramètres  : buffer = tampon de lignes à consulter.                       *
+*                line   = ligne à l'intérieur d'un commentaire.               *
 *                                                                             *
-*  Description : Imprime la visualisation du tampon de code désassemblé.      *
+*  Description : Récupère le contenu d'un commentaire existant.               *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Commentaire retrouver à libérer ou NULL en cas d'échec.      *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected)
+char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line)
 {
-    gint real_x;                            /* Abscisse réelle pour tampon */
-    gint real_y;                            /* Ordonnée réelle pour tampon */
-    size_t first;                           /* Première ligne visée        */
-    size_t last;                            /* Dernière ligne visée + 1    */
-    gint y;                                 /* Point de départ + décallage */
-    GBufferLine **lines;                    /* Liste des lignes à traiter  */
-    bool wait_selection;                    /* Sélection déjà passée ?     */
-    gint rel_selected;                      /* Position relative de sélect°*/
+    char *result;                           /* Contenu à retourner         */
+    size_t index;                           /* Indice de la ligne fournie  */
+    size_t start;                           /* Ligne de départ             */
+    size_t end;                             /* Ligne d'arrivée             */
+    BufferLineColumn merge_col;             /* Colonne de fusion           */
     size_t i;                               /* Boucle de parcours          */
+    char *extra;                            /* Commentaire supplémentaire  */
 
-    real_x = fake_x + view->left_text;
-    real_y = fake_y + area->y;
-
-    first = view->first_index;
-    first += (real_y / view->line_height);
+    /* Pas de prologue ici ! */
+    assert(g_buffer_line_has_comment(line));
 
-    last = first + (area->height / view->line_height);
-    if (area->height % view->line_height > 0) last++;
+    result = NULL;
 
-    last = MIN(last, view->last_index);
+    index = g_code_buffer_find_index_by_line(buffer, line);
 
-    y = area->y - (real_y % view->line_height);
+    if (index == buffer->used)
+        goto gcbglc_exit;
 
-    lines = view->buffer->lines;
+    start = g_code_buffer_find_first_line_comment(buffer, index);
 
-    wait_selection = true;
+    if (start == buffer->used)
+        goto gcbglc_exit;
 
-    if (selected != NULL)
-        rel_selected = *selected - fake_y;
+    end = g_code_buffer_find_last_line_comment(buffer, index);
 
-    if (view->buffer->used > 0)
-        for (i = first; i <= last; i++)
-        {
-            /* Si sélection, on sousligne la ligne concernée */
-            if (wait_selection && selected != NULL && rel_selected == y)
-            {
-                cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05);
+    if (end == buffer->used)
+        goto gcbglc_exit;
 
-                cairo_rectangle(cr, area->x, y, area->width, view->line_height);
-                cairo_fill(cr);
+    merge_col = g_buffer_line_get_merge_start(line);
 
-                wait_selection = false;
+    for (i = start; i <= end; i++)
+    {
+        if (merge_col == BLC_DISPLAY)
+            extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false);
 
-            }
+        else
+            extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false);
 
-            g_buffer_line_draw(lines[i], cr, view->max_widths, real_x, y, display, view->highlighted);
+        assert(extra != NULL);
 
-            y += view->line_height;
+        if (result == NULL)
+            result = extra;
 
+        else
+        {
+            result = stradd(result, extra);
+            free(extra);
         }
 
+    }
+
+ gcbglc_exit:
+
+    return result;
+
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view  = visualisation à consulter.                           *
-*                addr  = adresse où retrouver la ligne recherchée.            *
-*                flags = propriétés à vérifier en tout ou partie.             *
-*                idx   = indice de la ligne trouvée ou NULL. [OUT]            *
+*  Paramètres  : buffer = tampon de lignes à modifier.                        *
+*                line   = ligne à l'intérieur d'un commentaire.               *
 *                                                                             *
-*  Description : Retrouve une ligne au sein d'un tampon avec une adresse.     *
+*  Description : Supprime un commentaire existant.                            *
 *                                                                             *
-*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx)
+static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line)
 {
-    GBufferLine *result;                    /* Ligne trouvée à retourner   */
-    phys_t length;                          /* Taille de la vue            */
-    mrange_t vrange;                        /* Couverture de la vue        */
-    bool allowed;                           /* Rechercher validée ?        */
+    bool result;                            /* Bilan à retourner           */
+    size_t index;                           /* Indice de la ligne fournie  */
+    size_t start;                           /* Ligne de départ             */
+    size_t end;                             /* Ligne d'arrivée             */
+    BufferLineColumn merge_col;             /* Colonne de fusion           */
 
-    /* Vérification des bornes */
+    /* Pas de prologue ici ! */
+    assert(g_buffer_line_has_comment(line));
 
-    if (view->start != NULL/* && view->end != NULL*/)
-    {
-        length = compute_vmpa_diff(view->start, view->end);
+    result = false;
 
-        init_mrange(&vrange, view->start, length);
+    index = g_code_buffer_find_index_by_line(buffer, line);
 
-        allowed = mrange_contains_addr_inclusive(&vrange, addr);
+    if (index == buffer->used)
+        goto gcbdlc_exit;
 
-    }
-    else allowed = true;
+    start = g_code_buffer_find_first_line_comment(buffer, index);
 
-    /* Lancement des recherches ? */
+    if (start == buffer->used)
+        goto gcbdlc_exit;
+
+    end = g_code_buffer_find_last_line_comment(buffer, index);
+
+    if (end == buffer->used)
+        goto gcbdlc_exit;
+
+    result = true;
+
+    merge_col = g_buffer_line_get_merge_start(line);
+
+    if (merge_col == BLC_DISPLAY)
+        g_code_buffer_delete_lines(buffer, start, end);
 
-    if (allowed)
-        result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx);
     else
-        result = NULL;
+    {
+        g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT);
+
+        if (end > start)
+            g_code_buffer_delete_lines(buffer, start + 1, end);
+
+    }
+
+ gcbdlc_exit:
 
     return result;
 
@@ -2806,187 +1661,125 @@ GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view  = visualisation à consulter.                           *
-*                index = indice de la ligne recherchée.                       *
+*  Paramètres  : buffer = tampon de lignes à modifier.                        *
+*                line   = ligne à l'intérieur d'un commentaire.               *
 *                                                                             *
-*  Description : Retrouve une ligne au sein d'un tampon avec un indice.       *
+*  Description : Supprime un commentaire existant.                            *
 *                                                                             *
-*  Retour      : Line retrouvée ou NULL en cas d'échec.                       *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index)
+bool g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, GBufferLine *line)
 {
-    GBufferLine *result;                    /* Ligne trouvée à retourner   */
-    bool allowed;                           /* Rechercher validée ?        */
-
-    /* Vérification des bornes */
-
-    allowed = (view->first_index <= index && index < view->last_index);
+    bool result;                            /* Bilan à retourner           */
 
-    /* Lancement des recherches ? */
+    result = _g_code_buffer_delete_lines_comment(buffer, line);
 
-    if (allowed)
-        result = view->buffer->lines[index];
-    else
-        result = NULL;
+    /* TODO : emit() */
 
     return result;
 
 }
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                           SIGNAUX IMMEDIATS POUR UNE VUE                           */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
-*                y    = ordonnée comprise dans la ligne recherchée.           *
-*                idx  = indice de la ligne trouvée ou NULL. [OUT]             *
+*  Paramètres  : buffer = tampon de lignes à modifier.                        *
+*                cb     = fonction à appeler au moment opportun.              *
+*                data   = object GLib à associer à l'appel.                   *
 *                                                                             *
-*  Description : Fournit la ligne présente à une ordonnée donnée.             *
+*  Description : Enregistre l'adresse d'une fonction de mise à jour de vue.   *
 *                                                                             *
-*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx)
+void g_code_buffer_register_view_callback(GCodeBuffer *buffer, buffer_size_changed_cb cb, GObject *data)
 {
-    gint lheight;                           /* Hauteur d'une ligne         */
-    size_t index;                           /* Indice attendu              */
+    view_callback *new;                     /* Informations sur l'appel    */
 
-    lheight = g_buffer_view_get_line_height(view);
-    index = y / lheight;
+    buffer->vcount++;
 
-    index += view->first_index;
+    buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks, buffer->vcount * sizeof(view_callback));
 
-    if (idx != NULL)
-        *idx = index;
+    new = &buffer->vcallbacks[buffer->vcount - 1];
 
-    return (index < view->buffer->used ? view->buffer->lines[index] : NULL);
+    new->size_changed = cb;
+    new->data = data;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view    = visualisation à consulter.                         *
-*                x       = abscisse comprise dans le segment recherché. [OUT] *
-*                y       = ordonnée comprise dans la ligne recherchée.        *
-*                idx     = indice de la ligne trouvée ou NULL. [OUT]          *
-*                display = règles d'affichage des colonnes modulables.        *
-*                segment = portion de texte recherchée ou NULL. [OUT]         *
+*  Paramètres  : buffer = tampon de lignes à modifier.                        *
+*                data   = object GLib à associer à l'appel.                   *
 *                                                                             *
-*  Description : Fournit la ligne et son segment présents à une position.     *
+*  Description : Supprime un élément des vues à contacter pour mises à jour.  *
 *                                                                             *
-*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment)
+void g_code_buffer_unregister_view_callback(GCodeBuffer *buffer, GObject *data)
 {
-    GBufferLine *result;                    /* Ligne trouvée à retourner   */
-
-    /* Recherche d'une ligne correspondante */
+    size_t i;                               /* Boucle de parcours          */
 
-    result = g_buffer_view_find_line_at(view, y, idx);
+    for (i = 0; i < buffer->vcount; i++)
+        if (buffer->vcallbacks[i].data == data)
+        {
+            if ((i + 1) < buffer->vcount)
+                memmove(&buffer->vcallbacks[i], &buffer->vcallbacks[i + 1],
+                        (buffer->vcount - i - 1) * sizeof(view_callback));
 
-    /* Recherche du segment visé éventuel */
+            buffer->vcount--;
 
-    if (result != NULL && segment != NULL)
-    {
-        if (*x < view->left_text)
-            *segment = NULL;
+            buffer->vcallbacks = (view_callback *)realloc(buffer->vcallbacks,
+                                                          buffer->vcount * sizeof(view_callback));
 
-        else
-        {
-            *x -= view->left_text;
-            *segment = g_buffer_line_get_segment_at(result, view->max_widths, display,
-                                                    (gint []) { 0 }, x, GDK_SCROLL_LEFT, true);
         }
 
-    }
-
-    return result;
-
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : view = composant GTK à consulter.                            *
-*                addr = adresse à présenter à l'écran.                        *
-*                x    = position horizontale au sein du composant. [OUT]      *
-*                y    = position verticale au sein du composant. [OUT]        *
-*                code = s'arrête si possible à une ligne avec code.           *
+*  Paramètres  : buffer = tampon de lignes à diffuser.                        *
+*                added  = indication sur la variation de la taille du tampon. *
+*                index  = indice de la première ligne à traiter.              *
+*                count  = nombre de lignes à traiter.                         *
 *                                                                             *
-*  Description : Indique la position d'affichage d'une adresse donnée.        *
+*  Description : Fait suivre une variation de la quantité de lignes du tampon.*
 *                                                                             *
-*  Retour      : true si l'adresse fait partie du composant, false sinon.     *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_buffer_view_get_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code)
+static void g_code_buffer_notify_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count)
 {
-    bool result;                            /* Bilan à retourner           */
-    gint lheight;                           /* Hauteur d'une ligne         */
-    size_t first;                           /* Première ligne intégrée     */
-    size_t last;                            /* Dernière ligne intégrée     */
     size_t i;                               /* Boucle de parcours          */
-    const mrange_t *range;                  /* Emplacement parcouru        */
-
-    result = false;
-
-    *x = 0;
-    *y = 0;
-
-    lheight = g_buffer_view_get_line_height(view);
+    view_callback *cb;                      /* Informations sur l'appel    */
 
-    first = g_code_buffer_get_index_from_address(view->buffer, view->start, true);
-    last = g_code_buffer_get_index_from_address(view->buffer, view->end, false);
-
-    for (i = first; i <= last; i++)
+    for (i = 0; i < buffer->vcount; i++)
     {
-        /**
-         * Si l'adresse recherchée est plus petite que l'adresse de départ,
-         * on va effectuer un parcours complet pour rien.
-         *
-         * On considère cependant que le seul cas où celà peut arriver
-         * est lorsque que des découpages en blocs sont impliqués.
-         *
-         * Les découpages conduisent alors à la formation de petites zones,
-         * rapides à parcourir.
-         */
-
-        range = g_buffer_line_get_range(view->buffer->lines[i]);
+        cb = &buffer->vcallbacks[i];
 
-        result = mrange_contains_addr(range, addr);
-        if (result) break;
-
-        *y += lheight;
+        cb->size_changed(buffer, added, index, count, cb->data);
 
     }
 
-    if (result && code)
-        for (; i <= last; i++)
-        {
-            if (g_buffer_line_get_flags(view->buffer->lines[i]) & BLF_HAS_CODE) break;
-
-            if (i == last) break;
-
-            range = g_buffer_line_get_range(view->buffer->lines[i + 1]);
-            if (!mrange_contains_addr(range, addr)) break;
-
-            *y += lheight;
-
-        }
-
-    return result;
-
 }
diff --git a/src/glibext/gcodebuffer.h b/src/glibext/gcodebuffer.h
index 8bcbc4a..f0a7f8d 100644
--- a/src/glibext/gcodebuffer.h
+++ b/src/glibext/gcodebuffer.h
@@ -30,6 +30,7 @@
 
 #include "delayed.h"
 #include "gbufferline.h"
+#include "gwidthtracker.h"
 
 
 
@@ -57,6 +58,12 @@ GType g_code_buffer_get_type(void);
 /* Crée un nouveau composant de tampon pour code désassemblé. */
 GCodeBuffer *g_code_buffer_new(BufferLineColumn);
 
+/* Compte le nombre de lignes rassemblées dans un tampon. */
+size_t g_code_buffer_count_lines(const GCodeBuffer *);
+
+/* Fournit un lien vers la structure de suivi de largeurs. */
+const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *);
+
 /* Initie une nouvelle ligne devant être insérée dans le tampon. */
 GBufferLine *g_code_buffer_prepare_new_line(GCodeBuffer *, const mrange_t *);
 
@@ -86,6 +93,9 @@ GBufferLine *g_code_buffer_find_line_by_addr(const GCodeBuffer *, const vmpa2t *
 /* Retrouve une ligne au sein d'un tampon avec un indice. */
 GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *, size_t);
 
+/* Convertit une adresse en indice de ligne. */
+size_t g_code_buffer_get_index_from_address(const GCodeBuffer *, const vmpa2t *, bool);
+
 /* Retrouve l'indice associé à une ligne au sein d'un tampon. */
 size_t g_code_buffer_find_index_by_line(const GCodeBuffer *, const GBufferLine *);
 
@@ -127,83 +137,18 @@ bool g_code_buffer_delete_lines_comment(GCodeBuffer *, GBufferLine *);
 
 
 
-/* ---------------------- VUE PARTICULIERE D'UN TAMPON DE CODE ---------------------- */
-
-
-#define G_TYPE_BUFFER_VIEW                  (g_buffer_view_get_type())
-#define G_BUFFER_VIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_VIEW, GBufferView))
-#define G_BUFFER_VIEW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_VIEW, GBufferViewClass))
-#define G_IS_BUFFER_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_VIEW))
-#define G_IS_BUFFER_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_VIEW))
-#define G_BUFFER_VIEW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_VIEW, GBufferViewClass))
-
-
-/* Vue d'un tampon pour code désassemblé (instance) */
-typedef struct _GBufferView GBufferView;
-
-/* Vue d'un tampon pour code désassemblé (classe) */
-typedef struct _GBufferViewClass GBufferViewClass;
-
-
-/* Détermine le type de la vue d'un tampon pour code désassemblé. */
-GType g_buffer_view_get_type(void);
-
-/* Crée une nouvelle vue d'un tampon pour code désassemblé. */
-GBufferView *g_buffer_view_new(GCodeBuffer *, segcnt_list *);
-
-/* Restreint le champ d'application de l'affichage. */
-void g_buffer_view_restrict(GBufferView *, const vmpa2t *, const vmpa2t *);
-
-/* Indique le champ d'application de l'affichage. */
-void g_buffer_view_get_restrictions(GBufferView *, vmpa2t *, vmpa2t *);
+/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */
 
-/* Fournit le tampon de code lié à un visualisateur donné. */
-GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *);
 
-/* Fournit la hauteur d'impression d'une ligne visualisée. */
-gint g_buffer_view_get_line_height(GBufferView *);
-
-/* Fournit la largeur requise par une visualisation. */
-gint g_buffer_view_get_width(GBufferView *, const bool *);
-
-/* Fournit la largeur requise pour dépasser les marges gauches. */
-gint g_buffer_view_get_margin(GBufferView *, const bool *);
-
-/* Fournit la hauteur requise par une visualisation. */
-gint g_buffer_view_get_height(const GBufferView *);
-
-/* Calcule la position idéale de curseur pour un point donné. */
-const vmpa2t *g_buffer_view_compute_caret(GBufferView *, gint, gint, const bool *, GdkRectangle *);
-
-/* Calcule la position idéale de curseur pour un point donné. */
-const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *, GBufferLine *, size_t, gint, const bool *, GdkRectangle *);
-
-/* Déplace le curseur au sein d'une vue de tampon. */
-const vmpa2t *g_buffer_view_move_caret(GBufferView *, GdkRectangle *, bool, GdkScrollDirection, const bool *);
-
-/* Supprime toute mise en évidence de segments. */
-bool g_buffer_view_unhighlight_segments(GBufferView *);
-
-/* Surligne tous les segments similaires à celui sous la souris. */
-bool g_buffer_view_highlight_segments(GBufferView *, gint, gint, const bool *);
-
-/* Imprime la visualisation du tampon de code désassemblé. */
-void g_buffer_view_draw(const GBufferView *, cairo_t *, gint, gint, const cairo_rectangle_int_t *, const bool *, const gint *);
-
-/* Retrouve une ligne au sein d'un tampon avec une adresse. */
-GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *, const vmpa2t *, BufferLineFlags, size_t *);
-
-/* Retrouve une ligne au sein d'un tampon avec un indice. */
-GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *, size_t );
+/* Accompagne une variation de la quantité de lignes du tampon. */
+typedef void (* buffer_size_changed_cb) (const GCodeBuffer *, bool, size_t, size_t, GObject *);
 
-/* Fournit la ligne présente à une ordonnée donnée. */
-GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *);
 
-/* Fournit la ligne et son segment présents à une position. */
-GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *, gint *, gint, size_t *, const bool *, GBufferSegment **);
+/* Enregistre l'adresse d'une fonction de mise à jour de vue. */
+void g_code_buffer_register_view_callback(GCodeBuffer *, buffer_size_changed_cb, GObject *);
 
-/* Indique la position d'affichage d'une adresse donnée. */
-bool g_buffer_view_get_address_coordinates(GBufferView *, const vmpa2t *, gint *, gint *, bool);
+/* Supprime un élément des vues à contacter pour mises à jour. */
+void g_code_buffer_unregister_view_callback(GCodeBuffer *, GObject *);
 
 
 
diff --git a/src/glibext/gwidthtracker.c b/src/glibext/gwidthtracker.c
new file mode 100644
index 0000000..11ea0b1
--- /dev/null
+++ b/src/glibext/gwidthtracker.c
@@ -0,0 +1,830 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gwidthtracker.c - suivi des largeurs associées à un ensemble de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gwidthtracker.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "gcodebuffer.h"
+
+
+
+/* Portions de largeurs communes */
+typedef struct _common_metrics
+{
+    size_t first;                           /* Premier indice de portion   */
+    size_t last;                            /* Dernier indice de portion   */
+
+    line_width_summary summary;             /* Compilation de largeurs     */
+
+} common_metrics;
+
+
+/* Gestionnaire de largeurs associées aux lignes (instance) */
+struct _GWidthTracker
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    GCodeBuffer *buffer;                    /* Ensemble complet de lignes  */
+
+    common_metrics *portions;               /* Portions représentées       */
+    size_t count;                           /* Quantité de ces portions    */
+
+    line_width_summary summary;             /* Largeurs requises suivies   */
+    bool cached;                            /* Mise en cache des calculs   */
+
+};
+
+/* Gestionnaire de largeurs associées aux lignes (classe) */
+struct _GWidthTrackerClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+/* Procède à l'initialisation d'une classe de suivi de largeurs. */
+static void g_width_tracker_class_init(GWidthTrackerClass *);
+
+/* Procède à l'initialisation d'un suivi de largeurs de lignes. */
+static void g_width_tracker_init(GWidthTracker *);
+
+/* Supprime toutes les références externes. */
+static void g_width_tracker_dispose(GWidthTracker *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_width_tracker_finalize(GWidthTracker *);
+
+/* Recherche la portion contenant un indice de ligne donné. */
+static size_t g_width_tracker_find_metrics(const GWidthTracker *, size_t);
+
+/* Prend en compte une évolution du volume de lignes. */
+static void g_width_tracker_update_ranges(GWidthTracker *, size_t, size_t);
+
+/* Recalcule les largeurs requises par une portion de lignes. */
+static void g_width_tracker_update_widths(GWidthTracker *, size_t);
+
+/* Calcule les largeurs requises par un ensemble de lignes. */
+static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                            TAMPON POUR CODE DESASSEMBLE                            */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Détermine le type du gestionnaire de largeurs associées aux lignes. */
+G_DEFINE_TYPE(GWidthTracker, g_width_tracker, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe de composant GTK à initialiser.               *
+*                                                                             *
+*  Description : Procède à l'initialisation d'une classe de suivi de largeurs.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_class_init(GWidthTrackerClass *class)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(class);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_width_tracker_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_width_tracker_finalize;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = composant GLib à initialiser.                      *
+*                                                                             *
+*  Description : Procède à l'initialisation d'un suivi de largeurs de lignes. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_init(GWidthTracker *tracker)
+{
+    tracker->portions = NULL;
+    tracker->count = 0;
+
+    memset(&tracker->summary, 0, sizeof(line_width_summary));
+    tracker->cached = false;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_dispose(GWidthTracker *tracker)
+{
+    g_object_unref(G_OBJECT(tracker->buffer));
+
+    G_OBJECT_CLASS(g_width_tracker_parent_class)->dispose(G_OBJECT(tracker));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_finalize(GWidthTracker *tracker)
+{
+    G_OBJECT_CLASS(g_width_tracker_parent_class)->finalize(G_OBJECT(tracker));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = tampon contenant les lignes à surveiller.           *
+*                first  = adresse contenant l'indice de la première ligne.    *
+*                last   = adresse contenant l'indice de la dernière ligne.    *
+*                                                                             *
+*  Description : Crée un nouveau suivi de largeurs au sein de lignes.         *
+*                                                                             *
+*  Retour      : Composant GLib créé.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GWidthTracker *g_width_tracker_new(GCodeBuffer *buffer)
+{
+    GWidthTracker *result;                  /* Composant à retourner       */
+
+    result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL);
+
+    g_object_ref(G_OBJECT(buffer));
+    result->buffer = buffer;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : buffer = tampon contenant les lignes à surveiller.           *
+*                first  = indice de la première ligne d'une zone réduite.     *
+*                last   = indice de la dernière ligne d'une zone réduite.     *
+*                                                                             *
+*  Description : Crée un nouveau suivi de largeurs au sein de lignes.         *
+*                                                                             *
+*  Retour      : Composant GLib créé.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *template, size_t first, size_t last)
+{
+    GWidthTracker *result;                  /* Composant à retourner       */
+    size_t start;                           /* Début de la zone à copier   */
+    size_t end;                             /* Fin de cette même zone      */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = g_object_new(G_TYPE_WIDTH_TRACKER, NULL);
+
+    g_object_ref(G_OBJECT(template->buffer));
+    result->buffer = template->buffer;
+
+    start = g_width_tracker_find_metrics(template, first);
+    assert(start < template->count);
+
+    end = g_width_tracker_find_metrics(template, last);
+    assert(end < template->count);
+
+    result->count = end - start + 1;
+    result->portions = (common_metrics *)calloc(result->count, sizeof(common_metrics));
+
+    for (i = 0; i < result->count; i++)
+        memcpy(&result->portions[i], &template->portions[start + i], sizeof(common_metrics));
+
+    if (result->portions[0].first != first)
+    {
+        result->portions[0].first = first;
+        g_width_tracker_update_widths(result, 0);
+    }
+
+    if (result->portions[result->count - 1].last != last)
+    {
+        result->portions[result->count - 1].last = last;
+        g_width_tracker_update_widths(result, result->count - 1);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = gestionnaire de suivi à consulter.                 *
+*                index   = indice d'une ligne dont la portion est inconnue.   *
+*                                                                             *
+*  Description : Recherche la portion contenant un indice de ligne donné.     *
+*                                                                             *
+*  Retour      : Indice de portion trouvée ou le nombre de portions sinon.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t g_width_tracker_find_metrics(const GWidthTracker *tracker, size_t index)
+{
+    size_t result;                          /* Indice trouvé à retourner   */
+    common_metrics *found;                  /* Portion trouvée ou NULL     */
+
+    int look_for_metrics(const size_t *idx, const common_metrics *m)
+    {
+        int status;
+
+        if (*idx < m->first)
+            status = -1;
+
+        else if (*idx > m->last)
+            status = 1;
+
+        else
+            status = 0;
+
+        return status;
+
+    }
+
+    found = bsearch(&index, tracker->portions, tracker->count,
+                    sizeof(common_metrics), (__compar_fn_t)look_for_metrics);
+
+    if (found == NULL)
+        result = tracker->count;
+    else
+        result = found - tracker->portions;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = gestionnaire de largeurs de lignes à mettre jour.  *
+*                start   = première ligne à traiter.                          *
+*                diff    = nombre de lignes ajoutées ou supprimées.           *
+*                                                                             *
+*  Description : Prend en compte une évolution du volume de lignes.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_update_ranges(GWidthTracker *tracker, size_t start, size_t diff)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = start; i < tracker->count; i++)
+    {
+        tracker->portions[i].first += diff;
+        tracker->portions[i].last += diff;
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = gestionnaire de largeurs de lignes à mettre jour.  *
+*                index   = indice de la portion à rafraîchir.                 *
+*                                                                             *
+*  Description : Recalcule les largeurs requises par une portion de lignes.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_update_widths(GWidthTracker *tracker, size_t index)
+{
+    common_metrics *portion;                /* Portion à actualiser        */
+    BufferLineColumn k;                     /* Boucle de parcours #1       */
+    size_t i;                               /* Boucle de parcours #2       */
+    GBufferLine *line;                      /* Ligne à manipuler           */
+
+    assert(index < tracker->count);
+
+    portion = &tracker->portions[index];
+
+    /* Réinitialisation globale ? */
+
+    for (k = 0; k < BLC_COUNT && tracker->cached; k++)
+        tracker->cached &= (tracker->summary.max_widths[k] != portion->summary.max_widths[k]);
+
+    tracker->cached &= (tracker->summary.merged_width != portion->summary.merged_width);
+
+    /* Réinitialisation locale */
+
+    memset(&portion->summary, 0, sizeof(line_width_summary));
+
+    /* Collecte */
+
+    for (i = portion->first; i <= portion->last; i++)
+    {
+        line = g_code_buffer_find_line_by_index(tracker->buffer, i);
+
+        g_buffer_line_collect_widths(line, &portion->summary);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = gestionnaire de largeurs de lignes à mettre jour.  *
+*                index   = position de la première des lignes à ajouter.      *
+*                count   = quantité de lignes devant être ajoutées.           *
+*                                                                             *
+*  Description : Prend acte de l'ajout de lignes pour les largeurs.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_width_tracker_update_added(GWidthTracker *tracker, size_t index, size_t count)
+{
+    size_t current;                         /* Indice de portion visée     */
+    common_metrics *portion;                /* Portion sélectionnée        */
+    size_t next;                            /* Prochaine portion à décaller*/
+    size_t i;                               /* Boucle de parcours          */
+    GBufferLine *line;                      /* Ligne à manipuler           */
+    size_t dest;                            /* Destination d'une recopie   */
+    size_t src;                             /* Source d'une recopie        */
+
+    /* Cas particulier du premier ajout */
+    if (tracker->count == 0)
+    {
+        assert(index == 0);
+
+        tracker->portions = (common_metrics *)calloc(1, sizeof(common_metrics));
+        tracker->count = 1;
+
+        tracker->portions[0].first = 0;
+        tracker->portions[0].last = count - 1;
+
+        g_width_tracker_update_widths(tracker, 0);
+
+        return;
+
+    }
+
+    current = g_width_tracker_find_metrics(tracker, index);
+
+    /* Si la ligne est rajoutée en fin d'ensemble */
+    if (current == tracker->count)
+    {
+        current = tracker->count - 1;
+        portion = &tracker->portions[current];
+
+        assert(index == (portion->last + 1));
+
+    }
+    else
+        portion = &tracker->portions[current];
+
+    portion->last += count;
+
+    g_width_tracker_update_widths(tracker, current);
+
+    next = current + 1;
+
+    /* Un découpage s'impose-t-il quelque part ? */
+
+    for (i = index + count - 1; i >= index; i--)
+    {
+        line = g_code_buffer_find_line_by_index(tracker->buffer, i);
+
+        if (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER)
+        {
+            /* Insertion d'une nouvelle place */
+
+            tracker->count++;
+
+            tracker->portions = (common_metrics *)realloc(tracker->portions,
+                                                          tracker->count * sizeof(common_metrics));
+
+            dest = current + 2;
+            src = current + 1;
+
+            if ((tracker->count - src) > 0)
+                memmove(&tracker->portions[dest], &tracker->portions[src],
+                        (tracker->count - src - 1) * sizeof(common_metrics));
+
+            next++;
+
+            /* Insertion au début */
+            if (i == portion->first)
+            {
+                assert(i == index);
+
+                tracker->portions[current + 1].first = portion->first + 1;
+                tracker->portions[current + 1].last = portion->last;
+
+                portion->first = i;
+                portion->last = i;
+
+            }
+
+            /* Insertion au sein de la portion ou à la fin */
+            else
+            {
+                tracker->portions[current + 1].first = i;
+                tracker->portions[current + 1].last = portion->last;
+
+                portion->last = i - 1;
+
+            }
+
+            /* Mise à jour des largeurs */
+
+            g_width_tracker_update_widths(tracker, current);
+
+            g_width_tracker_update_widths(tracker, current + 1);
+
+        }
+
+    }
+
+    /* Suite impérative : accroître les indices ! */
+
+    g_width_tracker_update_ranges(tracker, next, 1);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = gestionnaire de largeurs de lignes à mettre jour.  *
+*                start   = première ligne devant être supprimée.              *
+*                end     = dernière ligne devant être supprimée.              *
+*                                                                             *
+*  Description : Prend acte de la suppression de lignes pour les largeurs.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t end)
+{
+    size_t first;                           /* Première portion concernée  */
+    size_t last;                            /* Dernière portion concernée  */
+    size_t diff;                            /* Nombre de lignes supprimées */
+    bool keep_first;                        /* Conservation de portion #1  */
+    size_t dest;                            /* Destination du transfert    */
+    bool keep_last;                         /* Conservation de portion #2  */
+    size_t src;                             /* Source du transfert         */
+
+    first = g_width_tracker_find_metrics(tracker, start);
+    assert(first < tracker->count);
+
+    last = g_width_tracker_find_metrics(tracker, end);
+    assert(last < tracker->count);
+
+    diff = end - start + 1;
+
+    /* Suppression de portions inutiles ? */
+
+    keep_first = (tracker->portions[first].first > start || end < tracker->portions[first].last);
+
+    dest = (keep_first ? first + 1 : first);
+
+    keep_last = (tracker->portions[last].first > start || end < tracker->portions[last].last);
+
+    src = (keep_last ? last : last + 1);
+
+    if (src > dest)
+    {
+        memmove(&tracker->portions[dest], &tracker->portions[src],
+                (tracker->count - src) * sizeof(common_metrics));
+
+        tracker->count -= (src - dest);
+
+        tracker->portions = (common_metrics *)realloc(tracker->portions,
+                                                      tracker->count * sizeof(common_metrics));
+
+    }
+
+    /* Si une fusion s'impose */
+
+    if (keep_first && keep_last && last != first)
+    {
+        tracker->portions[first].last = tracker->portions[dest].last;
+
+        memmove(&tracker->portions[first + 1], &tracker->portions[first + 2],
+                (tracker->count - first - 2) * sizeof(common_metrics));
+
+        tracker->count--;
+
+        tracker->portions = (common_metrics *)realloc(tracker->portions,
+                                                      tracker->count * sizeof(common_metrics));
+
+        keep_last = false;
+
+    }
+
+    /* Avant toute chose : faire décroître les indices ! */
+
+    if (keep_first)
+    {
+        if (end < tracker->portions[first].last)
+            tracker->portions[first].last -= diff;
+        else
+            tracker->portions[first].last = start;
+    }
+
+    if (keep_last && last != first)
+    {
+        tracker->portions[dest].first = end + 1;
+        tracker->portions[dest].last -= diff;
+    }
+
+    g_width_tracker_update_ranges(tracker, keep_last ? dest + 1 : dest, -diff);
+
+    /* Mise à jour des largeurs aux extrémités */
+
+    if (keep_first)
+        g_width_tracker_update_widths(tracker, first);
+
+    if (keep_last && last != first)
+        g_width_tracker_update_widths(tracker, dest);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = suivi de largeurs à mettre à jour si besoin est.   *
+*                                                                             *
+*  Description : Calcule les largeurs requises par un ensemble de lignes.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *tracker)
+{
+    line_width_summary *global;             /* Valeurs collectées          */
+    size_t i;                               /* Boucle de parcours #1       */
+    const line_width_summary *summary;      /* Valeurs à intégrer          */
+    BufferLineColumn k;                     /* Boucle de parcours #2       */
+
+    if (!tracker->cached)
+    {
+        /* Réinitialisation */
+
+        memset(&tracker->summary, 0, sizeof(line_width_summary));
+
+        /* Collecte */
+
+        global = &tracker->summary;
+
+        for (i = 0; i < tracker->count; i++)
+        {
+            summary = &tracker->portions[i].summary;
+
+            for (k = 0; k < BLC_COUNT; k++)
+                global->max_widths[k] = MAX(global->max_widths[k], summary->max_widths[k]);
+
+            global->merged_width = MAX(global->merged_width, summary->merged_width);
+
+        }
+
+        tracker->cached = true;
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = suivi de largeurs à consulter.                     *
+*                                                                             *
+*  Description : Fournit un bon résumé des largeurs en vigueur.               *
+*                                                                             *
+*  Retour      : Ensemble des largeurs collectées.                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *tracker)
+{
+    g_width_tracker_ensure_valid_required_widths(tracker);
+
+    return &tracker->summary;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = suivi de largeurs à consulter.                     *
+*                index   = indice de la ligne dont la portion est recherchée. *
+*                summary = ensemble ciblé de largeurs collectées. [OUT]       *
+*                                                                             *
+*  Description : Fournit un résumé local des largeurs en vigueur.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_width_tracker_get_local_width_summary(GWidthTracker *tracker, size_t index, line_width_summary *summary)
+{
+    size_t current;                         /* Indice de portion visée     */
+    common_metrics *portion;                /* Portion locale à consulter  */
+    BufferLineColumn i;                     /* Boucle de parcours          */
+
+    g_width_tracker_ensure_valid_required_widths(tracker);
+
+    current = g_width_tracker_find_metrics(tracker, index);
+    assert(current < tracker->count);
+
+    portion = &tracker->portions[current];
+
+    for (i = BLC_FIRST; i < BLC_DISPLAY; i++)
+        summary->max_widths[i] = tracker->summary.max_widths[i];
+
+    for (i = BLC_DISPLAY; i < BLC_COUNT; i++)
+        summary->max_widths[i] = portion->summary.max_widths[i];
+
+    summary->merged_width = portion->summary.merged_width;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = suivi de largeurs à consulter.                     *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Fournit la largeur requise par une visualisation.            *
+*                                                                             *
+*  Retour      : Dimension calculée.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_width_tracker_get_width(GWidthTracker *tracker, const bool *display)
+{
+    gint result;                            /* Taille à retourner          */
+    const line_width_summary *summary;      /* Accès rapide aux mesures    */
+    gint col_width;                         /* Calcul selon les colonnes   */
+    gint full_width;                        /* Calcul selon les fusions    */
+    BufferLineColumn i;                     /* Boucle de parcours          */
+
+    g_width_tracker_ensure_valid_required_widths(tracker);
+
+    result = 0;
+
+    summary = &tracker->summary;
+
+    col_width = 0;
+    full_width = 0;
+
+    /* Première méthode */
+
+    for (i = 0; i < BLC_COUNT; i++)
+    {
+        if (i < BLC_DISPLAY && !display[i]) continue;
+
+        col_width += summary->max_widths[i];
+
+        if ((i + 1) < BLC_COUNT)
+            col_width += COL_MARGIN;
+
+    }
+
+    /* Seconde méthode */
+
+    for (i = 0; i < BLC_DISPLAY; i++)
+    {
+        if (!display[i]) continue;
+
+        full_width += summary->max_widths[i] + COL_MARGIN;
+
+    }
+
+    full_width += summary->merged_width;
+
+    /* Mise en concurrence et poursuite... */
+
+    result += + MAX(col_width, full_width);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : tracker = suivi de largeurs à consulter.                     *
+*                display = règles d'affichage des colonnes modulables.        *
+*                                                                             *
+*  Description : Fournit la largeur requise pour dépasser les marges gauches. *
+*                                                                             *
+*  Retour      : Dimension calculée.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gint g_width_tracker_get_margin(GWidthTracker *tracker, const bool *display)
+{
+    gint result;                            /* Taille à retourner          */
+    const line_width_summary *summary;      /* Accès rapide aux mesures    */
+    BufferLineColumn i;                     /* Boucle de parcours          */
+
+    g_width_tracker_ensure_valid_required_widths(tracker);
+
+    result = 0;
+
+    summary = &tracker->summary;
+
+    for (i = 0; i < BLC_DISPLAY; i++)
+    {
+        if (!display[i]) continue;
+
+        result += summary->max_widths[i] + COL_MARGIN;
+
+    }
+
+    return result;
+
+}
diff --git a/src/glibext/gwidthtracker.h b/src/glibext/gwidthtracker.h
new file mode 100644
index 0000000..31168be
--- /dev/null
+++ b/src/glibext/gwidthtracker.h
@@ -0,0 +1,85 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gwidthtracker.h - prototypes pour le suivi des largeurs associées à un ensemble de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  OpenIDA is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  OpenIDA is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_GWIDTHTRACKER_H
+#define _GLIBEXT_GWIDTHTRACKER_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "gbufferline.h"
+
+
+
+/* gcodebuffer.h : Tampon pour code désassemblé (instance) */
+typedef struct _GCodeBuffer GCodeBuffer;
+
+
+
+#define G_TYPE_WIDTH_TRACKER            (g_width_tracker_get_type())
+#define G_WIDTH_TRACKER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_TRACKER, GWidthTracker))
+#define G_WIDTH_TRACKER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass))
+#define G_IS_WIDTH_TRACKER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_TRACKER))
+#define G_IS_WIDTH_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_TRACKER))
+#define G_WIDTH_TRACKER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_TRACKER, GWidthTrackerClass))
+
+
+/* Gestionnaire de largeurs associées aux lignes (instance) */
+typedef struct _GWidthTracker GWidthTracker;
+
+/* Gestionnaire de largeurs associées aux lignes (classe) */
+typedef struct _GWidthTrackerClass GWidthTrackerClass;
+
+
+/* Détermine le type du gestionnaire de largeurs associées aux lignes. */
+GType g_width_tracker_get_type(void);
+
+/* Crée un nouveau suivi de largeurs au sein de lignes. */
+GWidthTracker *g_width_tracker_new(GCodeBuffer *);
+
+/* Crée un nouveau suivi de largeurs au sein de lignes. */
+GWidthTracker *g_width_tracker_new_restricted(const GWidthTracker *, size_t, size_t);
+
+/* Prend acte de l'ajout de lignes pour les largeurs. */
+void g_width_tracker_update_added(GWidthTracker *, size_t, size_t);
+
+/* Prend acte de la suppression de lignes pour les largeurs. */
+void g_width_tracker_update_deleted(GWidthTracker *, size_t, size_t);
+
+/* Fournit un bon résumé des largeurs en vigueur. */
+const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *);
+
+/* Fournit un résumé local des largeurs en vigueur. */
+void g_width_tracker_get_local_width_summary(GWidthTracker *, size_t, line_width_summary *);
+
+/* Fournit la largeur requise par une visualisation. */
+gint g_width_tracker_get_width(GWidthTracker *, const bool *);
+
+/* Fournit la largeur requise pour dépasser les marges gauches. */
+gint g_width_tracker_get_margin(GWidthTracker *, const bool *);
+
+
+
+#endif  /* _GLIBEXT_GWIDTHTRACKER_H */
diff --git a/src/gtkext/gtkbufferview-int.h b/src/gtkext/gtkbufferview-int.h
index ea181f9..2da069d 100644
--- a/src/gtkext/gtkbufferview-int.h
+++ b/src/gtkext/gtkbufferview-int.h
@@ -41,7 +41,7 @@ struct _GtkBufferView
 {
     GtkViewPanel parent;                    /* A laisser en premier        */
 
-    GCodeBuffer *buffer;                    /* Code sous forme de texte    */
+    //GCodeBuffer *buffer;                    /* Code sous forme de texte    */
     GBufferView *buffer_view;               /* Affichage de cette forme    */
 
     gint line_height;                       /* Hauteur maximale des lignes */
diff --git a/src/gtkext/gtkbufferview.c b/src/gtkext/gtkbufferview.c
index b56a170..f0efce0 100644
--- a/src/gtkext/gtkbufferview.c
+++ b/src/gtkext/gtkbufferview.c
@@ -892,14 +892,14 @@ void gtk_buffer_view_attach_buffer(GtkBufferView *view, GBufferView *buffer)
     gint width;                             /* Largeur de l'objet actuelle */
     gint height;                            /* Hauteur de l'objet actuelle */
 
-    if (view->buffer != NULL)
+    if (view->buffer_view != NULL)
     {
-        g_object_unref(G_OBJECT(view->buffer));
+        //g_object_unref(G_OBJECT(view->buffer));
         g_object_unref(G_OBJECT(view->buffer_view));
     }
 
-    view->buffer = g_buffer_view_get_buffer(buffer);
-    g_object_ref(G_OBJECT(view->buffer));
+    //view->buffer = g_buffer_view_get_buffer(buffer);
+    //g_object_ref(G_OBJECT(view->buffer));
 
     view->buffer_view = buffer;
 
diff --git a/src/gtkext/gtkbufferview.h b/src/gtkext/gtkbufferview.h
index 06249cf..a46a9dd 100644
--- a/src/gtkext/gtkbufferview.h
+++ b/src/gtkext/gtkbufferview.h
@@ -29,7 +29,7 @@
 #include <gtk/gtk.h>
 
 
-#include "../glibext/gcodebuffer.h"
+#include "../glibext/gbufferview.h"
 
 
 
-- 
cgit v0.11.2-87-g4458