/** * ev_document_synctex_backward_search: * @document: a #EvDocument * @page_index: the target page * @x: X coordinate * @y: Y coordinate * * Peforms a Synctex backward search to obtain the TeX input file, line and * (possibly) column corresponding to the position (@x,@y) (in 72dpi * coordinates) in the @page of @document. * * Returns: A pointer to the EvSourceLink structure that holds the result. @NULL if synctex * is not enabled for the document or no result is found. * The EvSourceLink pointer should be freed with g_free after it is used. */ EvSourceLink * ev_document_synctex_backward_search (EvDocument *document, gint page_index, gfloat x, gfloat y) { EvSourceLink *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_edit_query (scanner, page_index + 1, x, y) > 0) { synctex_node_t node; /* We assume that a backward search returns either zero or one result_node */ node = synctex_next_result (scanner); if (node != NULL) { const gchar *filename; filename = synctex_scanner_get_name (scanner, synctex_node_tag (node)); if (filename) { result = ev_source_link_new (filename, synctex_node_line (node), synctex_node_column (node)); } } } return result; }
void SynctexHandler::synctexClick(const QPointF &pagePos, int pageNumber) { if (!m_synctexScanner) return; if (synctex_edit_query(m_synctexScanner, pageNumber + 1, pagePos.x(), pagePos.y()) > 0) { synctex_node_t synctexNode; while ((synctexNode = synctex_next_result(m_synctexScanner)) != 0) { const QString texFileName = QString::fromUtf8(synctex_scanner_get_name(m_synctexScanner, synctex_node_tag(synctexNode))); const QDir currentDir(QFileInfo(m_fileName).canonicalPath()); Q_EMIT openTexDocument(QFileInfo(currentDir, texFileName).canonicalFilePath(), synctex_node_line(synctexNode)); } } }
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; }
bool synctex_get_input_line_column(const char* filename, unsigned int page, int x, int y, char** input_file, unsigned int* line, unsigned int* column) { if (filename == NULL) { return false; } synctex_scanner_t scanner = synctex_scanner_new_with_output_file(filename, NULL, 1); if (scanner == NULL) { girara_debug("Failed to create synctex scanner."); return false; } synctex_scanner_t temp = synctex_scanner_parse(scanner); if (temp == NULL) { girara_debug("Failed to parse synctex file."); synctex_scanner_free(scanner); return false; } bool ret = false; if (synctex_edit_query(scanner, page + 1u, x, y) > 0) { /* Assume that a backward search returns at most one result. */ synctex_node_t node = synctex_next_result(scanner); if (node != NULL) { if (input_file != NULL) { *input_file = g_strdup(synctex_scanner_get_name(scanner, synctex_node_tag(node))); } if (line != NULL) { *line = synctex_node_line(node); } if (column != NULL) { *column = synctex_node_column(node); } ret = true; } } synctex_scanner_free(scanner); return ret; }
int SyncTex::DocToSource(UINT pageNo, PointI pt, ScopedMem<WCHAR>& filename, UINT *line, UINT *col) { if (IsIndexDiscarded()) { if (RebuildIndex() != PDFSYNCERR_SUCCESS) return PDFSYNCERR_SYNCFILE_CANNOT_BE_OPENED; } CrashIf(!this->scanner); // Coverity: at this point, this->scanner->flags.has_parsed == 1 and thus // synctex_scanner_parse never gets the chance to freeing the scanner if (synctex_edit_query(this->scanner, pageNo, (float)pt.x, (float)pt.y) <= 0) return PDFSYNCERR_NO_SYNC_AT_LOCATION; synctex_node_t node = synctex_next_result(this->scanner); if (!node) return PDFSYNCERR_NO_SYNC_AT_LOCATION; const char *name = synctex_scanner_get_name(this->scanner, synctex_node_tag(node)); if (!name) return PDFSYNCERR_UNKNOWN_SOURCEFILE; bool isUtf8 = true; filename.Set(str::conv::FromUtf8(name)); TryAgainAnsi: if (!filename) return PDFSYNCERR_OUTOFMEMORY; // undecorate the filepath: replace * by space and / by \ str::TransChars(filename, L"*/", L" \\"); // Convert the source filepath to an absolute path if (PathIsRelative(filename)) filename.Set(PrependDir(filename)); // recent SyncTeX versions encode in UTF-8 instead of ANSI if (isUtf8 && !file::Exists(filename)) { isUtf8 = false; filename.Set(str::conv::FromAnsi(name)); goto TryAgainAnsi; } *line = synctex_node_line(node); *col = synctex_node_column(node); return PDFSYNCERR_SUCCESS; }
int synctex_edit_proceed(synctex_edit_params_t * Ps) { synctex_scanner_t scanner = NULL; #if SYNCTEX_DEBUG printf("page:%i\n",Ps->page); printf("x:%f\n",Ps->x); printf("y:%f\n",Ps->y); printf("almost output:%s\n",Ps->output); printf("editor:%s\n",Ps->editor); printf("offset:%i\n",Ps->offset); printf("context:%s\n",Ps->context); printf("cwd:%s\n",getcwd(NULL,0)); #endif scanner = synctex_scanner_new_with_output_file(Ps->output,Ps->directory,1); if(NULL == scanner) { synctex_help_edit("No SyncTeX available for %s",Ps->output); return -1; } if(synctex_edit_query(scanner,Ps->page,Ps->x,Ps->y)) { synctex_node_t node = NULL; const char * input = NULL; if(NULL != (node = synctex_next_result(scanner)) && NULL != (input = synctex_scanner_get_name(scanner,synctex_node_tag(node)))) { /* filtering the command */ if(Ps->editor && strlen(Ps->editor)) { size_t size = 0; char * where = NULL; char * buffer = NULL; char * buffer_cur = NULL; int printed; int status; size = strlen(Ps->editor)+3*sizeof(int)+3*SYNCTEX_STR_SIZE; buffer = malloc(size+1); if(NULL == buffer) { printf("SyncTeX ERROR: No memory available\n"); return -1; } buffer[size]='\0'; /* Replace %{ by &{, then remove all unescaped '%'*/ while((where = strstr(Ps->editor,"%{")) != NULL) { *where = '&'; } where = Ps->editor; while(where &&(where = strstr(where,"%"))) { if(strlen(++where)) { if(*where == '%') { ++where; } else { *(where-1)='&'; } } } buffer_cur = buffer; /* find the next occurrence of a format key */ where = Ps->editor; while(Ps->editor && (where = strstr(Ps->editor,"&{"))) { #define TEST(KEY,FORMAT,WHAT)\ if(!strncmp(where,KEY,strlen(KEY))) {\ printed = where-Ps->editor;\ if(buffer_cur != memcpy(buffer_cur,Ps->editor,(size_t)printed)) {\ synctex_help_edit("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_edit("Snprintf problem");\ free(buffer);\ return -1;\ }\ buffer_cur += printed;size-=printed;\ *buffer_cur='\0';\ Ps->editor = where+strlen(KEY);\ continue;\ } TEST("&{output}", "%s",Ps->output); TEST("&{input}", "%s",input); TEST("&{line}", "%i",synctex_node_line(node)); TEST("&{column}", "%i",-1); TEST("&{offset}", "%i",Ps->offset); TEST("&{context}","%s",Ps->context); #undef TEST break; } /* copy the rest of editor into the buffer */ if(buffer_cur != memcpy(buffer_cur,Ps->editor,strlen(Ps->editor))) { fputs("! synctex_edit: Memory copy problem",stderr); free(buffer); return -1; }\ 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" "Input:%s\n" "Line:%i\n" "Column:%i\n" "Offset:%i\n" "Context:%s\n", Ps->output, input, synctex_node_line(node), synctex_node_column(node), Ps->offset, (Ps->context?Ps->context:"")); } while((node = synctex_next_result(scanner)) != NULL); puts("SyncTeX result end"); } } } return 0; }
void synctex_edit(zathura_t* zathura, zathura_page_t* page, int x, int y) { if (zathura == NULL || page == NULL || zathura->synctex.editor == NULL) { return; } zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { return; } const char *filename = zathura_document_get_path(document); if (filename == NULL) { return; } synctex_scanner_t scanner = synctex_scanner_new_with_output_file(filename, NULL, 1); if (scanner == NULL) { girara_debug("Failed to create synctex scanner."); return; } synctex_scanner_t temp = synctex_scanner_parse(scanner); if (temp == NULL) { girara_debug("Failed to parse synctex file."); synctex_scanner_free(scanner); return; } if (synctex_edit_query(scanner, zathura_page_get_index(page) + 1, x, y) > 0) { /* Assume that a backward search returns either at most one result. */ synctex_node_t node = synctex_next_result(scanner); if (node != NULL) { const char* input_file = synctex_scanner_get_name(scanner, synctex_node_tag(node)); const int line = synctex_node_line(node); const int column = synctex_node_column (node); char* linestr = g_strdup_printf("%d", line); char* columnstr = g_strdup_printf("%d", column); gchar** argv = NULL; gint argc = 0; if (g_shell_parse_argv(zathura->synctex.editor, &argc, &argv, NULL) == TRUE) { for (gint i = 0; i != argc; ++i) { char* temp = girara_replace_substring(argv[i], "%{line}", linestr); g_free(argv[i]); argv[i] = temp; temp = girara_replace_substring(argv[i], "%{column}", columnstr); g_free(argv[i]); argv[i] = temp; temp = girara_replace_substring(argv[i], "%{input}", input_file); g_free(argv[i]); argv[i] = temp; } g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); g_strfreev(argv); } g_free(linestr); g_free(columnstr); } } synctex_scanner_free(scanner); }