/* * Merge widget module * * At first, the base file is appended into @dtmap (draw_text()). * On each operation(insert, remove), inserted lines are inserted into @dtmap, * and also they are appended to an array of AddDispL. * * Copyright INOUE Seiichiro , licensed under the GPL. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "diff.h" #include "gui.h" #include "dtextmap.h" #include "merge-widget.h" #include "misc.h" #include "gtktext-support.h" #include "linenum.h" #include "style.h" /* Managed by merge->adl_array Added DispLines to basefile. */ typedef struct { int whichfile; DispLines *displn; /* Not own, just refer */ } AddDispL; /* Ideally, any file can be the basefile. But now there is a code which depends on basefile==FIRST_FILE. */ static WhichFile basefile = FIRST_FILE; static WhichFile otherfile = SECOND_FILE; static WhichFile otherfile2 = THIRD_FILE;/* ugly? */ static const char marktext[] = "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n";/* character doesn't matter */ static const int marktext_lenb = sizeof(marktext)-1; /* Private function declarations */ static void gdiff_merge_class_init(GdiffMergeClass *klass); static void gdiff_merge_init(GdiffMerge *merge); static void gdiff_merge_destroy(GtkObject *object); static void gdiff_merge_display(GdiffBasePane *basepane); static void gdiff_merge_show_linenum(GdiffBasePane *basepane, gboolean to_show); static void gdiff_merge_select_dlines(GdiffBasePane *basepane, WhichFile whichfile, int ln); static void guts_merge_display(GdiffMerge *merge); static void draw_text(GdiffMerge *merge); static void show_hide_numbers(GdiffMerge *merge, gboolean b_show); static gint text_click_cb(GtkWidget *text, GdkEventButton *event, gpointer data); static void guts_output_file(GdiffMerge *merge, const char *filename); static void adl_add(GdiffMerge *merge, int i_adl, WhichFile whichfile, const DiffLines *dlines); static void adl_remove(GdiffMerge *merge, int i_adl, WhichFile whichfile, const DiffLines *dlines); static DispAttr map_dtype_to_attr(DiffType dtype, WhichFile whichfile); static AddDispL* add_displn(GdiffMerge *merge, WhichFile whichfile, const DiffLines *dlines, int pos); static int remove_displn(DTextMap *dtmap, GtkWidget *text, DispLines *displn); static int adl_add_mark(GdiffMerge *merge, int i_adl, int cur_pos); static int adl_remove_mark(GdiffMerge *merge, int i_adl); static GdiffOnePaneClass *parent_class = NULL; GtkType gdiff_merge_get_type(void) { static GtkType merge_type = 0; if (!merge_type) { static const GtkTypeInfo merge_info = { "GdiffMerge", sizeof(GdiffMerge), sizeof(GdiffMergeClass), (GtkClassInitFunc)gdiff_merge_class_init, (GtkObjectInitFunc)gdiff_merge_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc)NULL, }; merge_type = gtk_type_unique(GDIFF_TYPE_ONEPANE, &merge_info); } return merge_type; } static void gdiff_merge_class_init(GdiffMergeClass *klass) { GtkObjectClass *object_class; GdiffBasePaneClass *basepane_class; object_class = (GtkObjectClass*)klass; basepane_class = (GdiffBasePaneClass*)klass; parent_class = gtk_type_class(GDIFF_TYPE_ONEPANE); object_class->destroy = gdiff_merge_destroy; basepane_class->display = gdiff_merge_display; basepane_class->show_linenum = gdiff_merge_show_linenum; basepane_class->select_dlines = gdiff_merge_select_dlines; } static void gdiff_merge_init(GdiffMerge *merge) { GdiffOnePane *onepane; onepane = GDIFF_ONEPANE(merge); PANE_PREF(merge).view_type = NO_VIEW; } GtkWidget* gdiff_merge_new(DiffDir *diffdir, DiffFiles *dfiles) { GdiffMerge *merge; const FileInfo *fi1 = dfiles_get_fileinfo(dfiles, FIRST_FILE, TRUE); int dlines_len; int i; merge = gtk_type_new(GDIFF_TYPE_MERGE); _gdiff_basepane_set_backend(GDIFF_BASEPANE(merge), diffdir, dfiles);/*XXX*/ /* Merge-pane specific internal data */ dlines_len = g_list_length(dfiles->dlines_list); merge->adl_array = g_new(GSList*, dlines_len); for (i = 0; i < dlines_len; i++) merge->adl_array[i] = NULL; /* Merge-pane internal data derived from onepane */ GDIFF_ONEPANE(merge)->dtmap = dtmap_new(fi1->nlines); if (dfiles->is_diff3) PANE_PREF(merge).view_type = MERGE3_VIEW; else PANE_PREF(merge).view_type = MERGE2_VIEW; gtk_signal_connect_after(GTK_OBJECT(GDIFF_ONEPANE(merge)->text), "button_press_event", GTK_SIGNAL_FUNC(text_click_cb), merge); /* workaround */ gtk_widget_ensure_style(GDIFF_ONEPANE(merge)->text); /* Not implemented yet */ PANE_PREF(merge).show_line_num = FALSE; guts_merge_display(merge); return GTK_WIDGET(merge); } static void gdiff_merge_destroy(GtkObject *object) { GdiffMerge *merge; int dlines_len; int i; g_return_if_fail(object != NULL); g_return_if_fail(GDIFF_IS_MERGE(object)); merge = GDIFF_MERGE(object); /* free internal data */ dlines_len = g_list_length(PANE_DFILES(GDIFF_BASEPANE(merge))->dlines_list); for (i = 0; i < dlines_len; i++) { GSList *list; for (list = merge->adl_array[i]; list; list = list->next) { g_free(list->data); } g_slist_free(merge->adl_array[i]); } g_free(merge->adl_array); if (GTK_OBJECT_CLASS(parent_class)->destroy) GTK_OBJECT_CLASS(parent_class)->destroy(object); } /** Interfaces **/ static void gdiff_merge_display(GdiffBasePane *basepane) { GdiffMerge *merge; g_return_if_fail(basepane != NULL); g_return_if_fail(GDIFF_IS_MERGE(basepane)); merge = GDIFF_MERGE(basepane); guts_merge_display(merge); } /* Not implemented yet */ static void gdiff_merge_show_linenum(GdiffBasePane *basepane, gboolean to_show) { GdiffMerge *merge; g_return_if_fail(basepane != NULL); g_return_if_fail(GDIFF_IS_MERGE(basepane)); merge = GDIFF_MERGE(basepane); /* if (to_show != PANE_PREF(merge).show_line_num) { show_hide_numbers(merge, to_show); PANE_PREF(merge).show_line_num = to_show; } */ } static void gdiff_merge_select_dlines(GdiffBasePane *basepane, WhichFile whichfile, int ln) { GdiffMerge *merge; DiffFiles *dfiles; const GList *dlines_node; g_return_if_fail(basepane != NULL); g_return_if_fail(GDIFF_IS_MERGE(basepane)); merge = GDIFF_MERGE(basepane); dfiles = PANE_DFILES(merge); dlines_node = dfiles_find_includel(dfiles, whichfile, ln); if (dlines_node == NULL && ln == 1) dlines_node = dfiles_find_rel_curl(dfiles, whichfile, 0);/* exception */ if (dlines_node) { /* todo coloring */ GDIFF_BASEPANE(merge)->cur_dlines_node = dlines_node; gtk_signal_emit_by_name(GTK_OBJECT(merge), "move_diff", MOVED_CUR_NOSCROLL); } } void gdiff_merge_insert_all(GdiffMerge *merge, WhichFile whichfile) { DiffFiles *dfiles; GList *node;/* node of DiffLines list */ GtkWidget *text; int i_adl; g_return_if_fail(merge != NULL); g_return_if_fail(GDIFF_IS_MERGE(merge)); dfiles = PANE_DFILES(merge); text = GDIFF_ONEPANE(merge)->text; gtext_freeze(text); for (i_adl = 0, node = dfiles->dlines_list; node; node = node->next, i_adl++) { adl_add(merge, i_adl, whichfile, node->data); } gtext_thaw(text); } void gdiff_merge_remove_all(GdiffMerge *merge, WhichFile whichfile) { DiffFiles *dfiles; GList *node;/* node of DiffLines list */ GtkWidget *text; int i_adl; g_return_if_fail(merge != NULL); g_return_if_fail(GDIFF_IS_MERGE(merge)); dfiles = PANE_DFILES(merge); text = GDIFF_ONEPANE(merge)->text; gtext_freeze(text); for (i_adl = 0, node = dfiles->dlines_list; node; node = node->next, i_adl++) { adl_remove(merge, i_adl, whichfile, node->data); } gtext_thaw(text); } void gdiff_merge_insert(GdiffMerge *merge, WhichFile whichfile) { const GList *dlines_node; int i_adl; g_return_if_fail(merge != NULL); g_return_if_fail(GDIFF_IS_MERGE(merge)); dlines_node = GDIFF_BASEPANE(merge)->cur_dlines_node; if (dlines_node == NULL) return; i_adl = g_list_position(PANE_DFILES(merge)->dlines_list, (GList*)dlines_node); adl_add(merge, i_adl, whichfile, dlines_node->data); } void gdiff_merge_remove(GdiffMerge *merge, WhichFile whichfile) { const GList *dlines_node; int i_adl; g_return_if_fail(merge != NULL); g_return_if_fail(GDIFF_IS_MERGE(merge)); dlines_node = GDIFF_BASEPANE(merge)->cur_dlines_node; if (dlines_node == NULL) return; i_adl = g_list_position(PANE_DFILES(merge)->dlines_list, (GList*)dlines_node); adl_remove(merge, i_adl, whichfile, dlines_node->data); } void gdiff_merge_output_file(GdiffMerge *merge, const char *filename) { g_return_if_fail(merge != NULL); g_return_if_fail(GDIFF_IS_MERGE(merge)); g_return_if_fail(filename != NULL && filename[0] != '\0'); guts_output_file(merge, filename); } /** Internal functions **/ /** * guts_merge_display: * Show the diff result in merge. **/ static void guts_merge_display(GdiffMerge *merge) { draw_text(merge); if (PANE_PREF(merge).show_line_num == TRUE) { show_hide_numbers(merge, TRUE); } } /* difftype condition macros */ /* The basefile has the only portion */ #define IS_BASE_ONLY(dtype) \ ((dtype & ONLY_ADD) && (dtype & F1ONLY)) /* The other file has the only portion, which means the basefile doesn't */ #define IS_OTHER_ONLY(dtype) \ (((dtype & ONLY_ADD) && (dtype & (F2ONLY|F3ONLY))) \ || (dtype & F23ADD)) /* This file doesn't have a corresponding portion. It implies no need to take care of insert or remove. */ #define IS_NOT_THIS_O(dtype, whichfile) \ (((whichfile == SECOND_FILE) \ && (((dtype & ONLY_ADD) && (dtype & (F1ONLY|F3ONLY))) || (dtype & F31ADD))) \ || ((whichfile == THIRD_FILE) \ && (((dtype & ONLY_ADD) && (dtype & (F1ONLY|F2ONLY))) || (dtype & F12ADD)))) /** * draw_text: * Draw the base file mainly. * The other files are managed internally. **/ static void draw_text(GdiffMerge *merge) { DiffFiles *dfiles = PANE_DFILES(merge); const FileInfo *fi = dfiles_get_fileinfo(dfiles, basefile, TRUE); const FileInfo *fi_o = dfiles_get_fileinfo(dfiles, otherfile, TRUE); const FileInfo *fi_o2 = dfiles_get_fileinfo(dfiles, otherfile2, TRUE); MBuffer *mbuf = PANE_MBUF(merge, basefile); const char *buf_pt; int buf_ln; int buf_lenb; DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GtkWidget *text = GDIFF_ONEPANE(merge)->text; GdkFont *font = text->style->font; GList *node;/* node of DiffLines list */ FontProp fprop; int oldpos = 0; int pos; int i_adl = 0; if (fi->buf == NULL && fi_o->buf == NULL && fi_o2->buf == NULL) /* Maybe, the file has been deleted. */ return; fprop.font = font; mbuf_goto_top(mbuf); gtext_freeze(text); for (node = dfiles->dlines_list; node; node = node->next, i_adl++) { const DiffLines *dlines = node->data; /* Use local variables for readability */ int begin = dlines->between[basefile].begin; int end = dlines->between[basefile].end; DispAttr attr; int num_chars; fprop.fg = fprop.bg = NULL; buf_ln = mbuf->cur_ln; buf_pt = mbuf->cur_pt; buf_lenb = mbuf_goto_line(mbuf, begin) - buf_pt; pos = gtext_insert_buf(text, &fprop, buf_pt, mbuf->cur_pt - buf_pt); dtmap_append_displn(dtmap, DA_COMMON, oldpos, pos - oldpos, buf_pt, buf_lenb, begin - buf_ln); oldpos = pos; buf_pt = mbuf->cur_pt; if (end == 0) {/* special */ g_assert(IS_OTHER_ONLY(dlines->difftype)); dtmap_append_displn(dtmap, DA_O_ONLY|DA_O_ONLY_TOP, 0, 0, 0, 0, 0); /* mark here (after) */ oldpos = adl_add_mark(merge, i_adl, oldpos); continue; } else { buf_lenb = mbuf_goto_line(mbuf, end + 1) - buf_pt; } if (IS_OTHER_ONLY(dlines->difftype)) { DispLines *displn; pos = gtext_insert_buf(text, &fprop, buf_pt, buf_lenb); attr = map_dtype_to_attr(dlines->difftype, basefile); displn = dtmap_append_displn(dtmap, attr, oldpos, pos - oldpos, buf_pt, buf_lenb, end+1 - begin); /* mark here (after) */ oldpos = adl_add_mark(merge, i_adl, pos); } else { AddDispL *adl; DispLines *displn; /* mark here (before) */ oldpos = adl_add_mark(merge, i_adl, oldpos); attr = map_dtype_to_attr(dlines->difftype, basefile); num_chars = get_num_chars(buf_pt, buf_lenb, !GTK_TEXT(text)->use_wchar); displn = dtmap_append_displn(dtmap, attr|DA_HIDE, oldpos, num_chars, buf_pt, buf_lenb, end+1 - begin); dtmap->total_nl -= (end+1 - begin);/* Hidden lines */ adl = g_new(AddDispL, 1); adl->whichfile = basefile; adl->displn = displn; merge->adl_array[i_adl] = g_slist_append(merge->adl_array[i_adl], adl); } } /* Draw the remained part */ fprop.fg = fprop.bg = NULL; buf_ln = mbuf->cur_ln; buf_pt = mbuf->cur_pt; buf_lenb = mbuf_goto_line(mbuf, fi->nlines + 1) - buf_pt; pos = gtext_insert_buf(text, &fprop, buf_pt, buf_lenb); dtmap_append_displn(dtmap, DA_COMMON, oldpos, pos - oldpos, buf_pt, buf_lenb, fi->nlines+1 - buf_ln); gtext_thaw(text); } /** * show_hide_numbers: * Show(or hide) line numbers on the head of each lines. **/ static void show_hide_numbers(GdiffMerge *merge, gboolean b_show) { /*XXX TODO*/ } /** * text_click_cb: * Signal handler for button_click on text widget. * This is connected after default handler, * so I can get the clicked position (point in text widget term). * Calculate line number from the point, * and map it to line number on the buffer. **/ static gint text_click_cb(GtkWidget *text, GdkEventButton *event, gpointer data) { GdiffMerge *merge = data; DiffFiles *dfiles = PANE_DFILES(merge); DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; if (event->button == 1) { const GList *dlines_node; int index, tln, bln; index = gtext_get_cursor_pos(text); tln = gtext_line_from_index(text, index); bln = dtmap_map_t2b(dtmap, tln); #ifdef DEBUG g_print("tln=%d, bln=%d\n", tln, bln); #endif dlines_node = dfiles_find_includel(dfiles, basefile, bln); if (dlines_node == NULL && bln == 1) dlines_node = dfiles_find_rel_curl(dfiles, basefile, 0);/* exception */ if (dlines_node) { gtk_signal_emit_by_name(GTK_OBJECT(merge), "select_dlines", basefile, bln); } } return FALSE; } static void guts_output_file(GdiffMerge *merge, const char *filename) { DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; DispLines *displn; FILE *fp = NULL; fp = fopen(filename, "w"); if (fp == NULL) { g_message("can't write to %s\n", filename); return; } for (displn = dtmap_first_displn(dtmap, DA_ANY); displn; displn = dtmap_next_displn(dtmap, DA_ANY)) { const char *buf_pt; if (displn->attr & DA_HIDE) continue; if (displn->attr & DA_MARK) continue; buf_pt = mbuf_goto_top(MBUFFER(displn)); fwrite(buf_pt, mbuf_goto_bottom(MBUFFER(displn)) - buf_pt, 1, fp); } if (fp) fclose(fp); } /** * adl_add: * Add the portion of @whichfile into text widget. * The inserted portion is managed by GSList *merge->adl_array[i_adl]. **/ static void adl_add(GdiffMerge *merge, int i_adl, WhichFile whichfile, const DiffLines *dlines) { MBuffer *mbuf = PANE_MBUF(merge, whichfile); DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GtkWidget *text = GDIFF_ONEPANE(merge)->text; GSList *list; AddDispL *adl; DispLines *displn; FontProp fprop; const char *buf_pt; int buf_lenb; int begin = dlines->between[whichfile].begin; int end = dlines->between[whichfile].end; int pos; if (whichfile == basefile && IS_OTHER_ONLY(dlines->difftype)) return; if (whichfile != basefile && IS_BASE_ONLY(dlines->difftype)) return; if (whichfile != basefile && IS_NOT_THIS_O(dlines->difftype, whichfile)) return; fprop.font = text->style->font; fprop.fg = &PANE_PREF(merge).diff_fg[whichfile]; fprop.bg = &PANE_PREF(merge).diff_bg[whichfile]; gtext_freeze(text); pos = adl_remove_mark(merge, i_adl); if (IS_OTHER_ONLY(dlines->difftype)) { for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; if (adl->whichfile == whichfile) {/* already exist */ goto done; } } if (merge->adl_array[i_adl]) {/* append the list */ GSList *last; last = g_slist_last(merge->adl_array[i_adl]); displn = ((AddDispL*)last->data)->displn; pos = displn->pos + displn->len; } else {/* no list in here, which means no inserted portions */ /* pos is taken from the mark abobe */ g_assert(pos != -1); } adl = add_displn(merge, whichfile, dlines, pos); merge->adl_array[i_adl] = g_slist_append(merge->adl_array[i_adl], adl); } else { if (whichfile == basefile) { /* look for a hidden one */ for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; displn = adl->displn; if (displn->attr & DA_HIDE) { g_assert(adl->whichfile == basefile); gtext_set_point(text, displn->pos); buf_pt = mbuf_goto_line(mbuf, begin); buf_lenb = mbuf_goto_line(mbuf, end + 1) - buf_pt; gtext_insert_buf(text, &fprop, buf_pt, buf_lenb); /* hack to show */ dtmap_show_displn(dtmap, displn); break; } } } else { GSList *last = NULL;/* the node related to the last shown portion */ int last_pos = 0; for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; if (adl->whichfile == whichfile) {/* already exist */ goto done; } } /* look for the last shown portion */ for (list = merge->adl_array[i_adl]; list; list = list->next, last_pos++) { adl = list->data; displn = adl->displn; if (displn->attr & DA_HIDE) { continue; } last = list; } if (last) { displn = ((AddDispL*)last->data)->displn; pos = displn->pos + displn->len; adl = add_displn(merge, whichfile, dlines, pos); merge->adl_array[i_adl] = g_slist_append(merge->adl_array[i_adl], adl); } else {/* implies a hidden one exists */ list = merge->adl_array[i_adl]; g_assert(list); displn = ((AddDispL*)list->data)->displn; g_assert(displn->attr & DA_HIDE); pos = displn->pos; adl = add_displn(merge, whichfile, dlines, pos); merge->adl_array[i_adl] = g_slist_prepend(merge->adl_array[i_adl], adl); } } } done: gtext_thaw(text); } /** * adl_remove: * Remove the inserted portion of @whichfile from text widget. * The inserted portion is managed by GSList *merge->adl_array[i_adl]. **/ static void adl_remove(GdiffMerge *merge, int i_adl, WhichFile whichfile, const DiffLines *dlines) { DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GtkWidget *text = GDIFF_ONEPANE(merge)->text; GSList *list; AddDispL *adl; DispLines *displn; int pos = -1; int num_shown; if (whichfile == basefile && IS_OTHER_ONLY(dlines->difftype)) return; if (whichfile != basefile && IS_BASE_ONLY(dlines->difftype)) return; if (whichfile != basefile && IS_NOT_THIS_O(dlines->difftype, whichfile)) return; gtext_freeze(text); /* look for the current one */ for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; if (adl->whichfile == whichfile) {/* already there */ displn = adl->displn; if (displn->attr & DA_HIDE) { goto done; } else { if (whichfile == basefile) { pos = displn->pos; gtext_set_point(text, pos); gtext_forward_delete(text, displn->len); /* hack to hide */ dtmap_hide_displn(dtmap, displn); } else { pos = remove_displn(dtmap, text, displn); g_free(adl); merge->adl_array[i_adl] = g_slist_remove(merge->adl_array[i_adl], adl); } break; } } } /* If no portion is added, add a mark */ num_shown = 0; if (IS_OTHER_ONLY(dlines->difftype)) { if (merge->adl_array[i_adl] == NULL) { if (dlines->between[basefile].end == 0) dtmap_append_displn(dtmap, DA_O_ONLY|DA_O_ONLY_TOP, 0, 0, 0, 0, 0); adl_add_mark(merge, i_adl, pos); } else { pos = -1;/* for a strict check */ for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; displn = adl->displn; if (displn->attr & DA_O_ONLY) { pos = displn->pos + displn->len; continue; } num_shown++; } if (num_shown == 0) { g_assert(pos != -1); adl_add_mark(merge, i_adl, pos); } } } else { if (merge->adl_array[i_adl] == NULL) { adl_add_mark(merge, i_adl, pos); } else { for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; displn = adl->displn; if (displn->attr & DA_HIDE) { pos = displn->pos; continue; } num_shown++; } if (num_shown == 0) { adl_add_mark(merge, i_adl, pos); } } } done: gtext_thaw(text); } static DispAttr map_dtype_to_attr(DiffType dtype, WhichFile whichfile) { if (dtype == CHANGE) return whichfile == basefile ? DA_CHANGE : DA_CHANGE_O; else if (dtype & F1ONLY) return DA_ONLY; else if (dtype & F2ONLY) return whichfile == basefile ? DA_O_ONLY : DA_ONLY_O; else if (dtype & F3ONLY) return whichfile == basefile ? DA_O2_ONLY : DA_ONLY_O2;/* XXX: Need? */ else if (dtype == F12ADD || dtype == F31ADD) return whichfile == basefile ? DA_CHANGE : DA_CHANGE_O; else if (dtype == F23ADD) return whichfile == basefile ? DA_O_ONLY : DA_ONLY_O; g_assert_not_reached(); return 0; } /* Add the diff portion to text widget. * Allocate AddDislL and return it. * The returned AddDislL will be inserted to GSList *merge->adl_array[i_adl]. */ static AddDispL* add_displn(GdiffMerge *merge, WhichFile whichfile, const DiffLines *dlines, int pos) { MBuffer *mbuf = PANE_MBUF(merge, whichfile); DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GtkWidget *text = GDIFF_ONEPANE(merge)->text; DispLines *displn; FontProp fprop; int begin = dlines->between[whichfile].begin; int end = dlines->between[whichfile].end; AddDispL* adl; const char *buf_pt; int buf_lenb; int newpos; DispAttr attr; fprop.font = text->style->font; fprop.fg = &PANE_PREF(merge).diff_fg[whichfile]; fprop.bg = &PANE_PREF(merge).diff_bg[whichfile]; adl = g_new(AddDispL, 1); adl->whichfile = whichfile; buf_pt = mbuf_goto_line(mbuf, begin); buf_lenb = mbuf_goto_line(mbuf, end + 1) - buf_pt; gtext_set_point(text, pos); newpos = gtext_insert_buf(text, &fprop, buf_pt, buf_lenb); attr = map_dtype_to_attr(dlines->difftype, whichfile); displn = dtmap_insert_displn(dtmap, attr, pos, newpos - pos, buf_pt, buf_lenb, end+1 - begin); adl->displn = displn; return adl; } /* Remove the lines related to @displn from text widget. Also remove its data from the internal data, dtmap. */ static int remove_displn(DTextMap *dtmap, GtkWidget *text, DispLines *displn) { int pos; pos = displn->pos; gtext_set_point(text, pos); gtext_forward_delete(text, displn->len); dtmap_remove_displn(dtmap, displn); return pos; } /* Add a mark to text widget. * The added mark is also inserted to GSList *merge->adl_array[i_adl]. */ static int adl_add_mark(GdiffMerge *merge, int i_adl, int cur_pos) { DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GSList *list; AddDispL *adl; GtkWidget *text = GDIFF_ONEPANE(merge)->text; FontProp fprop; int pos; for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; if (adl->whichfile == -1) {/* mark is found */ return -1; } } fprop.font = text->style->font; fprop.fg = fprop.bg = >K_WIDGET(text)->style->bg[GTK_STATE_INSENSITIVE]; adl = g_new(AddDispL, 1); adl->whichfile = -1; gtext_set_point(text, cur_pos); pos = gtext_insert_buf(text, &fprop, marktext, marktext_lenb); adl->displn = dtmap_insert_displn(dtmap, DA_MARK, cur_pos, pos - cur_pos, marktext, marktext_lenb, 1); merge->adl_array[i_adl] = g_slist_append(merge->adl_array[i_adl], adl); return pos; } /* Remove the mark from text widget * The inserted mark is managed by GSList of AddDispL. */ static int adl_remove_mark(GdiffMerge *merge, int i_adl) { DTextMap *dtmap = GDIFF_ONEPANE(merge)->dtmap; GtkWidget *text = GDIFF_ONEPANE(merge)->text; GSList *list; AddDispL *adl; int pos; for (list = merge->adl_array[i_adl]; list; list = list->next) { adl = list->data; if (adl->whichfile == -1) {/* found the mark */ pos = remove_displn(dtmap, text, adl->displn); g_free(adl); merge->adl_array[i_adl] = g_slist_remove(merge->adl_array[i_adl], adl); return pos; } } return -1; }