diff options
Diffstat (limited to 'src/glibext/gcodebuffer.c')
-rw-r--r-- | src/glibext/gcodebuffer.c | 2245 |
1 files changed, 519 insertions, 1726 deletions
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) - +/* ------------------------- SIGNAUX IMMEDIATS POUR UNE VUE ------------------------- */ -/* 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 *); - -/* 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,645 +393,6 @@ static void g_buffer_scan_process(GBufferScan *scan, GtkStatusStack *status) /* ---------------------------------------------------------------------------------- */ -/* CONFORTS POUR LES COMMENTAIRES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* 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 : Affiche un commentaire sur une ligne de tampon donnée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) -{ - 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; - -} - - -/****************************************************************************** -* * -* 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 : Affiche un commentaire sur une ligne de tampon donnée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) -{ - 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; - -} - - -/****************************************************************************** -* * -* 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 : Affiche un commentaire sur une ligne de tampon dédiée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) -{ - 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])); - - free(extra); - - } - - return result; - -} - - -/****************************************************************************** -* * -* 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 : Affiche un commentaire sur une ligne de tampon dédiée. * -* * -* Retour : Bilan de l'opération : ajout ou non ? * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) -{ - 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; - -} - - -/****************************************************************************** -* * -* Paramètres : buffer = tampon de lignes à consulter. * -* index = indice de ligne à l'intérieur d'un commentaire. * -* * -* Description : Retrouve la premiè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_first_line_comment(const GCodeBuffer *buffer, size_t index) -{ - size_t result; /* Indice trouvé à retourner */ - GBufferLine *prev; /* Ligne précédente */ - - 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 */ /* ---------------------------------------------------------------------------------- */ @@ -1130,6 +440,7 @@ static void g_code_buffer_class_init(GCodeBufferClass *class) static void g_code_buffer_init(GCodeBuffer *buffer) { + buffer->tracker = g_width_tracker_new(buffer); } @@ -1161,138 +472,38 @@ GCodeBuffer *g_code_buffer_new(BufferLineColumn main) /****************************************************************************** * * -* 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.* +* Paramètres : buffer = composant GLib à consulter. * * * -* Description : Convertit une adresse en indice de ligne. * +* Description : Compte le nombre de lignes rassemblées dans un tampon. * * * -* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * +* Retour : Nombre de lignes constituant le tampon. * * * * Remarques : - * * * ******************************************************************************/ -static size_t g_code_buffer_get_index_from_address(const GCodeBuffer *buffer, const vmpa2t *addr, bool first) +size_t g_code_buffer_count_lines(const GCodeBuffer *buffer) { - 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; + return buffer->used; } /****************************************************************************** * * -* 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. * +* Paramètres : buffer = composant GLib à consulter. * * * -* Description : Actualise les largeurs maximales par groupes de lignes. * +* Description : Fournit un lien vers la structure de suivi de largeurs. * * * -* Retour : - * +* Retour : Gestionnaire de largeurs de lignes. * * * * Remarques : - * * * ******************************************************************************/ -static void g_code_buffer_update_line_max_widths(const GCodeBuffer *buffer, size_t first, size_t last) +const GWidthTracker *g_code_buffer_get_width_tracker(const GCodeBuffer *buffer) { - 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); - - } + return buffer->tracker; } @@ -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); } @@ -1625,6 +825,8 @@ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t { GBufferLine *result; /* Ligne trouvée à retourner */ + /* TODO : ref */ + if (index < buffer->used) result = buffer->lines[index]; else @@ -1637,6 +839,90 @@ GBufferLine *g_code_buffer_find_line_by_index(const GCodeBuffer *buffer, size_t /****************************************************************************** * * +* 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 : - * +* * +******************************************************************************/ + +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 de lignes à consulter. * * line = ligne dont l'indice est à retrouver. * * * @@ -1762,144 +1048,126 @@ GDelayedWork *g_buffer_code_scan(GCodeBuffer *buffer, const vmpa2t *start, const /* ---------------------------------------------------------------------------------- */ -/* VUE PARTICULIERE D'UN TAMPON DE CODE */ +/* CONFORTS POUR LES COMMENTAIRES */ /* ---------------------------------------------------------------------------------- */ -/* 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. * +* 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 : Procède à l'initialisation d'une classe de vue de tampon. * +* Description : Affiche un commentaire sur une ligne de tampon donnée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_class_init(GBufferViewClass *class) +static bool _g_code_buffer_write_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) { - GObjectClass *object; /* Autre version de la classe */ + 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 */ - object = G_OBJECT_CLASS(class); + assert(!g_buffer_line_has_comment(line)); - object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose; - object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize; + result = false; - 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); + range = g_buffer_line_get_range(line); -} + wcopy = strdup(comment); + extra = NULL; + extra_count = 0; -/****************************************************************************** -* * -* Paramètres : buffer = composant GTK à initialiser. * -* * -* Description : Procède à l'initialisation d'une vue d'un tampon pour code. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + for (token = strtok_r(wcopy, COMMENT_LINE_SEP, &saveptr); + token != NULL; + token = strtok_r(NULL, COMMENT_LINE_SEP, &saveptr)) + { + len = strlen(token); -static void g_buffer_view_init(GBufferView *buffer) -{ - buffer->first_index = 0; + if (!result) + { + segment = g_buffer_line_insert_text(line, BLC_COMMENTS, token, len, RTT_COMMENT); + g_buffer_segment_set_creator(segment, creator); + } - g_buffer_view_reset_required_height(buffer); - g_buffer_view_reset_required_widths(buffer); + 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 *)); -/****************************************************************************** -* * -* Paramètres : view = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + extra[extra_count - 1] = new; -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)); + result = true; -} + } + free(wcopy); -/****************************************************************************** -* * -* Paramètres : view = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (extra_count > 0) + { + result &= g_code_buffer_insert_lines(buffer, extra, extra_count, line, false); -static void g_buffer_view_finalize(GBufferView *view) -{ - if (!view->external) - exit_segment_content_list(view->highlighted); + if (!result) + for (i = 0; i < extra_count; i++) + g_object_unref(G_OBJECT(extra[i])); - G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view)); + free(extra); + + } + + return result; } /****************************************************************************** * * -* Paramètres : buffer = tampon à représenter à l'écran. * -* widget = composant GTK de destination pour le rendu. * +* 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 : Crée une nouvelle vue d'un tampon pour code désassemblé. * +* Description : Affiche un commentaire sur une ligne de tampon donnée. * * * -* Retour : Composant GTK créé. * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) +bool g_code_buffer_update_inlined_comment(GCodeBuffer *buffer, GBufferLine *line, const char *comment, GObject *creator) { - 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_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result); + bool result; /* Bilan à retourner */ - if (highlighted != NULL) - result->highlighted = highlighted; + if (g_buffer_line_has_comment(line)) + result = _g_code_buffer_delete_lines_comment(buffer, line); else - result->highlighted = init_segment_content_list(); + result = true; + + if (result) + result = _g_code_buffer_write_inlined_comment(buffer, line, comment, creator); - result->external = (highlighted != NULL); + /* TODO : emit() */ return result; @@ -1908,314 +1176,213 @@ GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted) /****************************************************************************** * * -* 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é. * +* 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 : Réagit à un changement de contenu d'une ligne donnée. * +* Description : Affiche un commentaire sur une ligne de tampon dédiée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view) +static bool _g_code_buffer_write_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) { - /* TODO : regarder si la vue et concernée et cibler d'avantage l'actualisation */ - - g_signal_emit_by_name(view, "need-redraw"); + 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; -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + range = g_buffer_line_get_range(line); -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); + wcopy = strdup(comment); - 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); + 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); -/****************************************************************************** -* * -* 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 : - * -* * -* Remarques : - * -* * -******************************************************************************/ + segment = g_buffer_line_insert_text(new, BLC_DISPLAY, token, len, RTT_COMMENT); + g_buffer_segment_set_creator(segment, creator); -void g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end) -{ - /* FIXME view->xxx == NULL -> plantage */ + extra = (GBufferLine **)realloc(extra, ++extra_count * sizeof(GBufferLine *)); - if (start != NULL) copy_vmpa(start, view->start); - if (end != NULL) copy_vmpa(end, view->end); + extra[extra_count - 1] = new; -} + result = true; + } -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + free(wcopy); -GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view) -{ - return view->buffer; + 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])); + free(extra); -/****************************************************************************** -* * -* 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 = 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 : Réinitialise le cache des largeurs de colonne calculées. * +* Description : Affiche un commentaire sur une ligne de tampon dédiée. * * * -* Retour : - * +* Retour : Bilan de l'opération : ajout ou non ? * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_reset_required_widths(GBufferView *view) +bool g_code_buffer_update_comment_area(GCodeBuffer *buffer, GBufferLine *line, const char *comment, bool before, GObject *creator) { - unsigned int i; /* Boucle de parcours */ - - for (i = 0; i < BLC_COUNT; i++) - view->max_widths[i] = -1; - - view->merged_width = 0; + 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); -/****************************************************************************** -* * -* Paramètres : view = visualisation à mettre à jour. * -* * -* Description : Calcule la hauteur requise par une visualisation. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + /* TODO : emit() */ -static void g_buffer_view_compute_required_height(GBufferView *view) -{ - view->line_height = 17; + return result; } /****************************************************************************** * * -* Paramètres : view = visualisation à mettre à jour. * -* 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 : Calcule les largeurs requises par une visualisation. * +* Description : Retrouve la première ligne d'une zone de commentaire. * * * -* Retour : - * +* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * * * * Remarques : - * * * ******************************************************************************/ -static void g_buffer_view_compute_required_widths(GBufferView *view, const bool *display) +static size_t g_code_buffer_find_first_line_comment(const GCodeBuffer *buffer, size_t index) { - 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); - - lines = view->buffer->lines; - - 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); + size_t result; /* Indice trouvé à retourner */ + GBufferLine *prev; /* Ligne précédente */ - view->left_margin = 2 * view->line_height; - view->left_text = 2.5 * view->line_height; + assert(index < buffer->used); - if (view->buffer->used > 0) + bool is_first_line_of_comment(const GBufferLine *ln, const GBufferLine *pv) { - //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); - - } - -} - - -/****************************************************************************** -* * -* 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) -{ - if (!HEIGHT_CACHED(view)) - g_buffer_view_compute_required_height(view); + bool first; /* Statut à renvoyer */ + BufferLineColumn merge_col; /* Colonne de fusion #1 */ + BufferLineColumn prev_merge_col; /* Colonne de fusion #2 */ - return view->line_height; + 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); -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + if (!first) + { + /* La ligne d'avant doit avoir un commentaire ! */ + first = !g_buffer_line_has_text(pv, BLC_COMMENTS, BLC_COUNT); + } -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 */ + } - if (!WIDTHS_CACHED(view)) - g_buffer_view_compute_required_widths(view, display); + 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 = view->left_text; + /** + * La première ligne d'un tampon est toujours un prologue. + */ + assert(pv != NULL); - col_width = 0; - full_width = 0; + prev_merge_col = g_buffer_line_get_merge_start(pv); - /* Première méthode */ + first = (prev_merge_col != BLC_DISPLAY); - for (i = 0; i < BLC_COUNT; i++) - { - if (i < BLC_DISPLAY && !display[i]) continue; + if (!first) + first = (g_buffer_line_get_flags(pv) & BLF_IS_LABEL); - col_width += view->max_widths[i]; + } - if ((i + 1) < BLC_COUNT) - col_width += COL_MARGIN; + return first; } - /* Seconde méthode */ - - for (i = 0; i < BLC_DISPLAY; i++) + for (result = index; result > 0; result--) { - if (!display[i]) continue; + prev = (result > 0 ? buffer->lines[result - 1] : NULL); - full_width += view->max_widths[i] + COL_MARGIN; + if (is_first_line_of_comment(buffer->lines[result], prev)) + break; } - full_width += view->merged_width; - - /* Mise en concurrence et poursuite... */ - - result += + MAX(col_width, full_width); - - 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 */ - BufferLineColumn i; /* Boucle de parcours */ - - if (!WIDTHS_CACHED(view)) - g_buffer_view_compute_required_widths(view, display); - - result = view->left_text; - - for (i = 0; i < BLC_DISPLAY; i++) + if (result == 0) { - if (!display[i]) continue; - - result += view->max_widths[i] + COL_MARGIN; - + if (!is_first_line_of_comment(buffer->lines[0], NULL)) + result = buffer->used; } return result; @@ -2225,226 +1392,130 @@ gint g_buffer_view_get_margin(GBufferView *view, const bool *display) /****************************************************************************** * * -* 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 */ - 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; - -} - - -/****************************************************************************** -* * -* 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] * +* Paramètres : buffer = tampon de lignes à consulter. * +* index = indice de ligne à l'intérieur d'un commentaire. * * * -* Description : Calcule la position idéale de curseur pour un point donné. * +* Description : Retrouve la dernière ligne d'une zone de commentaire. * * * -* Retour : Adresse si une a pu être déterminée, NULL sinon. * +* Retour : Indice de l'adresse trouvée, ou le nombre de lignes sinon. * * * * Remarques : - * * * ******************************************************************************/ -const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret) +static size_t g_code_buffer_find_last_line_comment(const GCodeBuffer *buffer, size_t index) { - 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*/ - - 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)); + size_t result; /* Indice trouvé à retourner */ + GBufferLine *next; /* Ligne suivante */ - printf(" '%s'\n", g_buffer_segment_get_text(segment, false)); + 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. + * + */ - caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining); + if (g_buffer_line_has_text(ln, BLC_COMMENTS, BLC_COUNT)) + { + last = !g_buffer_line_has_text(nx, BLC_COMMENTS, BLC_COUNT); - caret->y = (index - view->first_index) * view->line_height; + if (!last) + last = g_buffer_line_has_text(nx, BLC_DISPLAY, BLC_COMMENTS); - caret->width = 2; - caret->height = view->line_height; + } - return get_mrange_addr(g_buffer_line_get_range(line)); + 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); -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + last = (next_merge_col != BLC_DISPLAY); -const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret) -{ - gint offset; /* Point de travail modifiable */ - gint base; /* Position absolue de segment */ - GBufferSegment *segment; /* Segment visé par le pointeur*/ + if (!last) + last = (g_buffer_line_get_flags(nx) & BLF_IS_LABEL); - 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; + return last; - caret->x = view->left_text + base + offset; + } - printf("caret Y : %zu -> %zu\n", view->first_index, index); + for (result = index; result < buffer->used; result++) + { + next = ((result + 1) < buffer->used ? buffer->lines[result + 1] : NULL); - caret->y = (index - view->first_index) * view->line_height; + if (is_last_line_of_comment(buffer->lines[result], next)) + break; - caret->width = 2; - caret->height = view->line_height; + } - 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. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Déplace le curseur au sein d'une vue de tampon. * +* Description : Retrouve le créateur d'un commentaire existant. * * * -* Retour : true si un déplacement a été effectué, false sinon. * +* Retour : Instance trouvée à déréférencer ensuite ou NULL si aucune. * * * * Remarques : - * * * ******************************************************************************/ -static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +GObject *g_code_buffer_get_comment_creator(const GCodeBuffer *buffer, const GBufferLine *line) { - 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)); - - - - - - - //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); - - /////////////////// + GObject *result; /* Instance à retourner */ + BufferLineColumn merge_col; /* Colonne de fusion */ - if (!result) + if (g_buffer_line_has_comment(line)) { - base = 0; - - segment = g_buffer_line_find_near_segment(line, segment, view->max_widths, 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); - - - } + 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); } - - if (result) - printf(" ====== NEW CARET: %d -> %d\n", caret->x, view->left_text + base + offset); else - printf(" ====== NO NEW CARET!\n"); - - - - if (result) - caret->x = view->left_text + base + offset; + result = NULL; return result; @@ -2453,192 +1524,71 @@ 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. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Déplace le curseur au sein d'une vue de tampon. * +* Description : Récupère le contenu d'un commentaire existant. * * * -* Retour : Adresse si une a pu être déterminée, VMPA_INVALID sinon. * +* Retour : Commentaire retrouver à libérer ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display) +char *g_code_buffer_get_lines_comment(const GCodeBuffer *buffer, const GBufferLine *line) { - 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° */ - - - - - - - + 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; - 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); + index = g_code_buffer_find_index_by_line(buffer, line); - 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; + if (index == buffer->used) + goto gcbglc_exit; - /* -gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths) + start = g_code_buffer_find_first_line_comment(buffer, index); -BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line) - */ + if (start == buffer->used) + goto gcbglc_exit; - left_pos = view->left_text; + end = g_code_buffer_find_last_line_comment(buffer, index); - break; - default: /* GDK_SCROLL_SMOOTH */ - break; - } + if (end == buffer->used) + goto gcbglc_exit; - first = view->first_index; - last = view->last_index; + merge_col = g_buffer_line_get_merge_start(line); - switch (dir) + for (i = start; i <= end; i++) { - 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: - - if (index < last) - { - 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_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 = view->buffer->lines[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 (merge_col == BLC_DISPLAY) + extra = g_buffer_line_get_text(buffer->lines[i], BLC_DISPLAY, BLC_COUNT, false); - if (moved) - result = get_mrange_addr(g_buffer_line_get_range(line)); + else + extra = g_buffer_line_get_text(buffer->lines[i], BLC_COMMENTS, BLC_COUNT, false); - 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); - } + assert(extra != NULL); - break; + if (result == NULL) + result = extra; - default: /* GDK_SCROLL_SMOOTH */ - break; + else + { + result = stradd(result, extra); + free(extra); + } } - /* - 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); + gcbglc_exit: return result; @@ -2647,157 +1597,62 @@ bool g_buffer_view_unhighlight_segments(GBufferView *view) /****************************************************************************** * * -* 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. * +* Paramètres : buffer = tampon de lignes à modifier. * +* line = ligne à l'intérieur d'un commentaire. * * * -* Description : Imprime la visualisation du tampon de code désassemblé. * +* Description : Supprime un commentaire existant. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * 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) +static bool _g_code_buffer_delete_lines_comment(GCodeBuffer *buffer, 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°*/ - size_t i; /* Boucle de parcours */ - - real_x = fake_x + view->left_text; - real_y = fake_y + area->y; - - first = view->first_index; - first += (real_y / view->line_height); - - last = first + (area->height / view->line_height); - if (area->height % view->line_height > 0) last++; - - last = MIN(last, view->last_index); - - y = area->y - (real_y % view->line_height); - - lines = view->buffer->lines; - - wait_selection = true; - - if (selected != NULL) - rel_selected = *selected - fake_y; - - 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); + 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 */ - cairo_rectangle(cr, area->x, y, area->width, view->line_height); - cairo_fill(cr); + /* Pas de prologue ici ! */ + assert(g_buffer_line_has_comment(line)); - wait_selection = false; + result = false; - } + index = g_code_buffer_find_index_by_line(buffer, line); - g_buffer_line_draw(lines[i], cr, view->max_widths, real_x, y, display, view->highlighted); + if (index == buffer->used) + goto gcbdlc_exit; - y += view->line_height; + 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; -/****************************************************************************** -* * -* 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 : - * -* * -******************************************************************************/ + result = true; -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 ? */ + merge_col = g_buffer_line_get_merge_start(line); - /* Vérification des bornes */ + if (merge_col == BLC_DISPLAY) + g_code_buffer_delete_lines(buffer, start, end); - if (view->start != NULL/* && view->end != NULL*/) + else { - length = compute_vmpa_diff(view->start, view->end); - - init_mrange(&vrange, view->start, length); + g_buffer_line_delete_text(buffer->lines[start], BLC_COMMENTS, BLC_COUNT); - allowed = mrange_contains_addr_inclusive(&vrange, addr); + if (end > start) + g_code_buffer_delete_lines(buffer, start + 1, end); } - else allowed = true; - /* Lancement des recherches ? */ - - if (allowed) - result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx); - else - result = NULL; + 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; + view_callback *cb; /* Informations sur l'appel */ - *x = 0; - *y = 0; - - lheight = g_buffer_view_get_line_height(view); - - 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]); - - result = mrange_contains_addr(range, addr); - if (result) break; + cb = &buffer->vcallbacks[i]; - *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; - } |