@@ -589,6 +589,103 @@ static void table_capture_append(RenderCtx *ctx, const gchar *text) {
589589 g_free (escaped );
590590}
591591
592+ static gchar * table_cell_markup_to_plain (const gchar * markup ) {
593+ gchar * plain = NULL ;
594+ GError * error = NULL ;
595+
596+ if (!markup || markup [0 ] == '\0' ) {
597+ return g_strdup ("" );
598+ }
599+
600+ if (pango_parse_markup (markup , -1 , 0 , NULL , & plain , NULL , & error )) {
601+ return plain ;
602+ }
603+
604+ if (error ) {
605+ g_error_free (error );
606+ }
607+ return g_strdup (markup );
608+ }
609+
610+ static void table_search_index_free (gpointer data ) {
611+ ViewmdTableSearchIndex * index = (ViewmdTableSearchIndex * )data ;
612+ if (!index ) {
613+ return ;
614+ }
615+ if (index -> cells ) {
616+ g_array_free (index -> cells , TRUE);
617+ }
618+ g_free (index );
619+ }
620+
621+ static void table_emit_hidden_search_text (RenderCtx * ctx , ViewmdTable * table ,
622+ GtkTextChildAnchor * anchor ) {
623+ ViewmdTableSearchIndex * index ;
624+
625+ if (!ctx || !ctx -> buffer || !table || !anchor || !table -> rows ||
626+ table -> rows -> len == 0 || table -> col_count == 0 ) {
627+ return ;
628+ }
629+
630+ index = g_new0 (ViewmdTableSearchIndex , 1 );
631+ index -> cells = g_array_new (FALSE, FALSE, sizeof (ViewmdTableSearchCellRange ));
632+ index -> start_offset = gtk_text_iter_get_offset (& ctx -> iter );
633+
634+ for (guint r = 0 ; r < table -> rows -> len ; r ++ ) {
635+ ViewmdTableRow * row = g_ptr_array_index (table -> rows , r );
636+ if (!row ) {
637+ continue ;
638+ }
639+
640+ for (guint c = 0 ; c < table -> col_count ; c ++ ) {
641+ const gchar * cell_markup = "" ;
642+ gchar * plain ;
643+ gint cell_start ;
644+ gint cell_end ;
645+
646+ if (c < row -> cells -> len ) {
647+ cell_markup = g_ptr_array_index (row -> cells , c );
648+ if (!cell_markup ) {
649+ cell_markup = "" ;
650+ }
651+ }
652+
653+ plain = table_cell_markup_to_plain (cell_markup );
654+ cell_start = gtk_text_iter_get_offset (& ctx -> iter );
655+ if (plain && plain [0 ] != '\0' ) {
656+ gtk_text_buffer_insert (ctx -> buffer , & ctx -> iter , plain , -1 );
657+ }
658+ cell_end = gtk_text_iter_get_offset (& ctx -> iter );
659+
660+ if (cell_end > cell_start ) {
661+ ViewmdTableSearchCellRange cell_range = {(gint )r , (gint )c , cell_start ,
662+ cell_end };
663+ g_array_append_val (index -> cells , cell_range );
664+ }
665+
666+ g_free (plain );
667+
668+ if (c + 1 < table -> col_count ) {
669+ gtk_text_buffer_insert (ctx -> buffer , & ctx -> iter , "\t" , 1 );
670+ }
671+ }
672+
673+ if (r + 1 < table -> rows -> len ) {
674+ gtk_text_buffer_insert (ctx -> buffer , & ctx -> iter , "\n" , 1 );
675+ }
676+ }
677+
678+ index -> end_offset = gtk_text_iter_get_offset (& ctx -> iter );
679+ if (index -> end_offset > index -> start_offset ) {
680+ apply_tag_by_name_offsets (ctx -> buffer , TAG_INVISIBLE , index -> start_offset ,
681+ index -> end_offset );
682+ g_object_set_data_full (G_OBJECT (anchor ), VIEWMD_TABLE_SEARCH_INDEX_DATA , index ,
683+ table_search_index_free );
684+ } else {
685+ table_search_index_free (index );
686+ }
687+ }
688+
592689static void table_capture_span_enter (RenderCtx * ctx , MD_SPANTYPE type ) {
593690 if (!ctx || !ctx -> table_cell_text ) {
594691 return ;
@@ -711,6 +808,9 @@ static void table_emit_anchor(RenderCtx *ctx) {
711808 g_object_set_data_full (G_OBJECT (anchor ), TABLE_MODEL_DATA_KEY , ctx -> table_model ,
712809 viewmd_table_free );
713810
811+ /* Keep table text searchable via Ctrl+F without showing duplicate content. */
812+ table_emit_hidden_search_text (ctx , ctx -> table_model , anchor );
813+
714814 /* Force at least one hard line break after the embedded table widget so
715815 * following markdown never shares the same visual line. */
716816 insert_cstr (ctx , "\n" );
@@ -1241,6 +1341,10 @@ GtkWidget *markdown_create_table_widget(GtkTextChildAnchor *anchor) {
12411341 gtk_style_context_add_class (gtk_widget_get_style_context (cell ),
12421342 "viewmd-table-header-cell" );
12431343 }
1344+ g_object_set_data (G_OBJECT (cell ), VIEWMD_TABLE_CELL_ROW_DATA ,
1345+ GINT_TO_POINTER ((gint )r ));
1346+ g_object_set_data (G_OBJECT (cell ), VIEWMD_TABLE_CELL_COL_DATA ,
1347+ GINT_TO_POINTER ((gint )c ));
12441348 gtk_style_context_add_class (gtk_widget_get_style_context (label ),
12451349 "viewmd-table-label" );
12461350 gtk_widget_set_hexpand (cell , FALSE);
0 commit comments