/** * ev_document_synctex_forward_search: * @document: a #EvDocument * @source_link: a #EvSourceLink * * Peforms a Synctex forward search to obtain the area in the document * corresponding to the position @line and @column number in the source Tex file * * Returns: An EvMapping with the page number and area corresponfing to * the given line in the source file. It must be free with g_free when done */ EvMapping * ev_document_synctex_forward_search (EvDocument *document, EvSourceLink *link) { EvMapping *result = NULL; synctex_scanner_t scanner; g_return_val_if_fail (EV_IS_DOCUMENT (document), NULL); scanner = document->priv->synctex_scanner; if (!scanner) return NULL; if (synctex_display_query (scanner, link->filename, link->line, link->col) > 0) { synctex_node_t node; gint page; if ((node = synctex_next_result (scanner))) { result = g_new (EvMapping, 1); page = synctex_node_page (node) - 1; result->data = GINT_TO_POINTER (page); result->area.x1 = synctex_node_box_visible_h (node); result->area.y1 = synctex_node_box_visible_v (node) - synctex_node_box_visible_height (node); result->area.x2 = synctex_node_box_visible_width (node) + result->area.x1; result->area.y2 = synctex_node_box_visible_depth (node) + synctex_node_box_visible_height (node) + result->area.y1; } } return result; }
QList<SynctexTextBox> SynctexHandler::syncFromSource(const QString &sourceFile, int lineNumber) { QList<SynctexTextBox> textBoxList; if (!m_synctexScanner) return textBoxList; // find the name synctex is using for this file const QFileInfo sourceFileInfo(sourceFile); const QDir currentDir(QFileInfo(m_fileName).canonicalPath()); synctex_node_t synctexNode = synctex_scanner_input(m_synctexScanner); QString texFileName; bool found = false; while (synctexNode) { texFileName = QString::fromUtf8(synctex_scanner_get_name(m_synctexScanner, synctex_node_tag(synctexNode))); if (QFileInfo(currentDir, texFileName) == sourceFileInfo) { found = true; break; } synctexNode = synctex_node_sibling(synctexNode); } if (!found) return textBoxList; if (synctex_display_query(m_synctexScanner, texFileName.toUtf8().data(), lineNumber, 0) > 0) { int pageNumber = -1; while ((synctexNode = synctex_next_result(m_synctexScanner)) != 0) { if (pageNumber < 0) pageNumber = synctex_node_page(synctexNode); if (synctex_node_page(synctexNode) != pageNumber) continue; const QRectF textBox(synctex_node_box_visible_h(synctexNode), synctex_node_box_visible_v(synctexNode) - synctex_node_box_visible_height(synctexNode), synctex_node_box_visible_width(synctexNode), synctex_node_box_visible_height(synctexNode)); SynctexTextBox synctexTextBox; synctexTextBox.pageNumber = pageNumber; synctexTextBox.textBox = textBox; textBoxList << synctexTextBox; } } return textBoxList; }
int SyncTex::SourceToDoc(const WCHAR* srcfilename, UINT line, UINT col, UINT *page, Vec<RectI> &rects) { if (IsIndexDiscarded()) if (RebuildIndex() != PDFSYNCERR_SUCCESS) return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED; assert(this->scanner); ScopedMem<WCHAR> srcfilepath; // convert the source file to an absolute path if (PathIsRelative(srcfilename)) srcfilepath.Set(PrependDir(srcfilename)); else srcfilepath.Set(str::Dup(srcfilename)); if (!srcfilepath) return PDFSYNCERR_OUTOFMEMORY; bool isUtf8 = true; char *mb_srcfilepath = str::conv::ToUtf8(srcfilepath); TryAgainAnsi: if (!mb_srcfilepath) return PDFSYNCERR_OUTOFMEMORY; int ret = synctex_display_query(this->scanner, mb_srcfilepath, line, col); free(mb_srcfilepath); // recent SyncTeX versions encode in UTF-8 instead of ANSI if (isUtf8 && -1 == ret) { isUtf8 = false; mb_srcfilepath = str::conv::ToAnsi(srcfilepath); goto TryAgainAnsi; } if (-1 == ret) return PDFSYNCERR_UNKNOWN_SOURCEFILE; if (0 == ret) return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD; synctex_node_t node; int firstpage = -1; rects.Reset(); while ((node = synctex_next_result(this->scanner)) != NULL) { if (firstpage == -1) { firstpage = synctex_node_page(node); if (firstpage <= 0 || firstpage > engine->PageCount()) continue; *page = (UINT)firstpage; } if (synctex_node_page(node) != firstpage) continue; RectD rc; rc.x = synctex_node_box_visible_h(node); rc.y = synctex_node_box_visible_v(node) - synctex_node_box_visible_height(node); rc.dx = synctex_node_box_visible_width(node), rc.dy = synctex_node_box_visible_height(node) + synctex_node_box_visible_depth(node); rects.Push(rc.Round()); } if (firstpage <= 0) return PDFSYNCERR_NOSYNCPOINT_FOR_LINERECORD; return PDFSYNCERR_SUCCESS; }
int synctex_view_proceed(synctex_view_params_t * Ps) { synctex_scanner_t scanner = NULL; size_t size = 0; #if SYNCTEX_DEBUG printf("line:%i\n",Ps->line); printf("column:%i\n",Ps->column); printf("input:%s\n",Ps->input); printf("viewer:%s\n",Ps->viewer); printf("before:%s\n",Ps->before); printf("offset:%i\n",Ps->offset); printf("middle:%s\n",Ps->middle); printf("after:%s\n",Ps->after); printf("output:%s\n",Ps->output); printf("cwd:%s\n",getcwd(NULL,0)); #endif /* We assume that viewer is not so big: */ # define SYNCTEX_STR_SIZE 65536 if(Ps->viewer && strlen(Ps->viewer)>=SYNCTEX_STR_SIZE) { synctex_help_view("Viewer command is too long"); return -1; } scanner = synctex_scanner_new_with_output_file(Ps->output,Ps->directory,1); if(scanner && synctex_display_query(scanner,Ps->input,Ps->line,Ps->column)) { synctex_node_t node = NULL; if((node = synctex_next_result(scanner)) != NULL) { /* filtering the command */ if(Ps->viewer && strlen(Ps->viewer)) { char * viewer = Ps->viewer; char * where = NULL; char * buffer = NULL; char * buffer_cur = NULL; int printed = 0; int status = 0; /* Preparing the buffer where everything will be printed */ size = strlen(viewer)+3*sizeof(int)+6*sizeof(float)+4*(SYNCTEX_STR_SIZE); buffer = malloc(size+1); if(NULL == buffer) { synctex_help_view("No memory available"); return -1; } /* Properly terminate the buffer, no bad access for string related functions. */ buffer[size] = '\0'; /* Replace %{ by &{, then remove all unescaped '%'*/ while((where = strstr(viewer,"%{")) != NULL) { *where = '&'; } /* find all the unescaped '%', change to a safe character */ where = viewer; while(where && (where = strstr(where,"%"))) { /* Find the next occurrence of a "%", * if it is not followed by another "%", * replace it by a "&" */ if(strlen(++where)) { if(*where == '%') { ++where; } else { *(where-1)='&'; } } } buffer_cur = buffer; /* find the next occurrence of a format key */ where = viewer; while(viewer && (where = strstr(viewer,"&{"))) { #define TEST(KEY,FORMAT,WHAT)\ if(!strncmp(where,KEY,strlen(KEY))) {\ printed = where-viewer;\ if(buffer_cur != memcpy(buffer_cur,viewer,(size_t)printed)) {\ synctex_help_view("Memory copy problem");\ free(buffer);\ return -1;\ }\ buffer_cur += printed;size-=printed;\ printed = snprintf(buffer_cur,size,FORMAT,WHAT);\ if((unsigned)printed >= (unsigned)size) {\ synctex_help_view("Snprintf problem");\ free(buffer);\ return -1;\ }\ buffer_cur += printed;size-=printed;\ *buffer_cur='\0';\ viewer = where+strlen(KEY);\ continue;\ } TEST("&{output}","%s",synctex_scanner_get_output(scanner)); TEST("&{page}", "%i",synctex_node_page(node)-1); TEST("&{page+1}","%i",synctex_node_page(node)); TEST("&{x}", "%f",synctex_node_visible_h(node)); TEST("&{y}", "%f",synctex_node_visible_v(node)); TEST("&{h}", "%f",synctex_node_box_visible_h(node)); TEST("&{v}", "%f",synctex_node_box_visible_v(node)+synctex_node_box_visible_depth(node)); TEST("&{width}", "%f",fabs(synctex_node_box_visible_width(node))); TEST("&{height}","%f",fmax(synctex_node_box_visible_height(node)+synctex_node_box_visible_depth(node),1)); TEST("&{before}","%s",(Ps->before && strlen(Ps->before)<SYNCTEX_STR_SIZE?Ps->before:"")); TEST("&{offset}","%i",Ps->offset); TEST("&{middle}","%s",(Ps->middle && strlen(Ps->middle)<SYNCTEX_STR_SIZE?Ps->middle:"")); TEST("&{after}", "%s",(Ps->after && strlen(Ps->after)<SYNCTEX_STR_SIZE?Ps->after:"")); #undef TEST break; } /* copy the rest of viewer into the buffer */ if(buffer_cur != strncpy(buffer_cur,viewer,size + 1)) { synctex_help_view("Memory copy problem"); free(buffer); return -1; } buffer_cur[size] = '\0'; printf("SyncTeX: Executing\n%s\n",buffer); status = system(buffer); free(buffer); buffer = NULL; return status; } else { /* just print out the results */ puts("SyncTeX result begin"); do { printf( "Output:%s\n" "Page:%i\n" "x:%f\n" "y:%f\n" "h:%f\n" "v:%f\n" "W:%f\n" "H:%f\n" "before:%s\n" "offset:%i\n" "middle:%s\n" "after:%s\n", Ps->output, synctex_node_page(node), synctex_node_visible_h(node), synctex_node_visible_v(node), synctex_node_box_visible_h(node), synctex_node_box_visible_v(node)+synctex_node_box_visible_depth(node), synctex_node_box_visible_width(node), synctex_node_box_visible_height(node)+synctex_node_box_visible_depth(node), (Ps->before?Ps->before:""), Ps->offset, (Ps->middle?Ps->middle:""), (Ps->after?Ps->after:"")); } while((node = synctex_next_result(scanner)) != NULL); puts("SyncTeX result end"); } } } return 0; }
girara_list_t* synctex_rectangles_from_position(const char* filename, const char* input_file, int line, int column, unsigned int* page, girara_list_t** secondary_rects) { if (filename == NULL || input_file == NULL || page == NULL) { return NULL; } synctex_scanner_t scanner = synctex_scanner_new_with_output_file(filename, NULL, 1); if (scanner == NULL) { girara_debug("Failed to create synctex scanner."); return NULL; } synctex_scanner_t temp = synctex_scanner_parse(scanner); if (temp == NULL) { girara_debug("Failed to parse synctex file."); synctex_scanner_free(scanner); return NULL; } girara_list_t* hitlist = girara_list_new2(g_free); girara_list_t* other_rects = girara_list_new2(g_free); if (synctex_display_query(scanner, input_file, line, column) > 0) { synctex_node_t node = NULL; bool got_page = false; while ((node = synctex_next_result (scanner)) != NULL) { const unsigned int current_page = synctex_node_page(node) - 1; if (got_page == false) { got_page = true; *page = current_page; } zathura_rectangle_t rect = { 0, 0, 0, 0 }; rect.x1 = synctex_node_box_visible_h(node); rect.y1 = synctex_node_box_visible_v(node) - synctex_node_box_visible_height(node); rect.x2 = rect.x1 + synctex_node_box_visible_width(node); rect.y2 = synctex_node_box_visible_depth(node) + synctex_node_box_visible_height (node) + rect.y1; if (*page == current_page) { zathura_rectangle_t* real_rect = g_try_malloc(sizeof(zathura_rectangle_t)); if (real_rect == NULL) { continue; } *real_rect = rect; girara_list_append(hitlist, real_rect); } else { synctex_page_rect_t* page_rect = g_try_malloc(sizeof(synctex_page_rect_t)); if (page_rect == NULL) { continue; } page_rect->page = current_page; page_rect->rect = rect; girara_list_append(other_rects, page_rect); } } } synctex_scanner_free(scanner); if (secondary_rects != NULL) { *secondary_rects = other_rects; } else { girara_list_free(other_rects); } return hitlist; }