/* SPDX-FileCopyrightText: 2008-2017 jerome DOT laurens AT u-bourgogne DOT fr SPDX-License-Identifier: X11 This file is part of the __SyncTeX__ package. [//]: # (Latest Revision: Fri Jul 14 16:20:41 UTC 2017) [//]: # (Version: 1.19) See `synctex_parser_readme.md` for more details ## Acknowledgments: The author received useful remarks from the __pdfTeX__ developers, especially Hahn The Thanh, and significant help from __XeTeX__ developer Jonathan Kew. ## Nota Bene: If you include or use a significant part of the __SyncTeX__ package into a software, I would appreciate to be listed as contributor and see "__SyncTeX__" highlighted. */ #ifndef __SYNCTEX_PARSER__ #define __SYNCTEX_PARSER__ #ifdef __cplusplus extern "C" { #endif #define SYNCTEX_VERSION_STRING "1.19" /* The main synctex object is a scanner. * Its implementation is considered private. * The basic workflow is * - create a "synctex scanner" with the contents of a file * - perform actions on that scanner like synctex_display_query or synctex_edit_query below. * - perform actions on nodes returned by the scanner * - free the scanner when the work is done */ typedef struct synctex_scanner_t synctex_scanner_s; typedef synctex_scanner_s *synctex_scanner_p; /** * This is the designated method to create * a new synctex scanner object. * - argument output: the pdf/dvi/xdv file associated * to the synctex file. * If necessary, it can be the tex file that * originated the synctex file but this might cause * problems if the \\jobname has a custom value. * Despite this method can accept a relative path * in practice, you should only pass full paths. * The path should be encoded by the underlying * file system, assuming that it is based on * 8 bits characters, including UTF8, * not 16 bits nor 32 bits. * The last file extension is removed and * replaced by the proper extension, * either synctex or synctex.gz. * - argument build_directory: It is the directory where * all the auxiliary stuff is created. * If no synctex file is found in the same directory * as the output file, then we try to find one in * this build directory. * It is the directory where all the auxiliary * stuff is created. Sometimes, the synctex output * file and the pdf, dvi or xdv files are not * created in the same location. See MikTeX. * This directory path can be NULL, * it will be ignored then. * It can be either absolute or relative to the * directory of the output pdf (dvi or xdv) file. * Please note that this new argument is provided * as a convenience but should not be used. * Available since version 1.5. * - argument parse: In general, use 1. * Use 0 only if you do not want to parse the * content but just check for existence. * Available since version 1.5 * - resturn: a scanner. NULL is returned in case * of an error or non existent file. */ synctex_scanner_p synctex_scanner_new_with_output_file(const char *output, const char *build_directory, int parse); /** * Designated method to delete a synctex scanner object, * including all its internal resources. * Frees all the memory, you must call it when you are finished with the scanner. * - argument scanner: a scanner. * - returns: an integer used for testing purposes. */ int synctex_scanner_free(synctex_scanner_p scanner); /** * Send this message to force the scanner to * parse the contents of the synctex output file. * Nothing is performed if the file was already parsed. * In each query below, this message is sent, * but if you need to access information more directly, * you must ensure that the parsing did occur. * Usage: * if((my_scanner = synctex_scanner_parse(my_scanner))) { * continue with my_scanner... * } else { * there was a problem * } * - returns: the argument on success. * On failure, frees scanner and returns NULL. */ synctex_scanner_p synctex_scanner_parse(synctex_scanner_p scanner); /* synctex_node_p is the type for all synctex nodes. * Its implementation is considered private. * The synctex file is parsed into a tree of nodes, either sheet, form, boxes, math nodes... */ typedef struct synctex_node_t synctex_node_s; typedef synctex_node_s *synctex_node_p; /* The main entry points. * Given the file name, a line and a column number, synctex_display_query returns the number of nodes * satisfying the contrain. Use code like * * if(synctex_display_query(scanner,name,line,column,page_hint)>0) { * synctex_node_p node; * while((node = synctex_scanner_next_result(scanner))) { * // do something with node * ... * } * } * * Please notice that since version 1.19, * there is a new argument page_hint. * The results in pages closer to page_hint are given first. * For example, one can * - highlight each resulting node in the output, using synctex_node_visible_h and synctex_node_visible_v * - highlight all the rectangles enclosing those nodes, using synctex_node_box_visible_... functions * - highlight just the character using that information * * Given the page and the position in the page, synctex_edit_query returns the number of nodes * satisfying the contrain. Use code like * * if(synctex_edit_query(scanner,page,h,v)>0) { * synctex_node_p node; * while(node = synctex_scanner_next_result(scanner)) { * // do something with node * ... * } * } * * For example, one can * - highlight each resulting line in the input, * - highlight just the character using that information * * page is 1 based * h and v are coordinates in 72 dpi unit, relative to the top left corner of the page. * If you make a new query, the result of the previous one is discarded. If you need to make more than one query * in parallel, use the iterator API exposed in * the synctex_parser_private.h header. * If one of this function returns a negative integer, * it means that an error occurred. * * Both methods are conservative, in the sense that matching is weak. * If the exact column number is not found, there will be an answer with the whole line. * * Sumatra-PDF, Skim, iTeXMac2, TeXShop and Texworks are examples of open source software that use this library. * You can browse their code for a concrete implementation. */ typedef long synctex_status_t; /* The page_hint argument is used to resolve ambiguities. * Whenever, different matches occur, the ones closest * to the page will be given first. Pass a negative number * when in doubt. Using pdf forms may lead to ambiguities. */ synctex_status_t synctex_display_query(synctex_scanner_p scanner, const char *name, int line, int column, int page_hint); synctex_status_t synctex_edit_query(synctex_scanner_p scanner, int page, float h, float v); synctex_node_p synctex_scanner_next_result(synctex_scanner_p scanner); synctex_status_t synctex_scanner_reset_result(synctex_scanner_p scanner); /** * The horizontal and vertical location, * the width, height and depth of a box enclosing node. * All dimensions are given in page coordinates * as opposite to TeX coordinates. * The origin is at the top left corner of the page. * Code example for Qt5: * (from TeXworks source TWSynchronize.cpp) * QRectF nodeRect(synctex_node_box_visible_h(node), * synctex_node_box_visible_v(node) - * synctex_node_box_visible_height(node), * synctex_node_box_visible_width(node), * synctex_node_box_visible_height(node) + * synctex_node_box_visible_depth(node)); * Code example for Cocoa: * NSRect bounds = [pdfPage * boundsForBox:kPDFDisplayBoxMediaBox]; * NSRect nodeRect = NSMakeRect( * synctex_node_box_visible_h(node), * NSMaxY(bounds)-synctex_node_box_visible_v(node) + * synctex_node_box_visible_height(node), * synctex_node_box_visible_width(node), * synctex_node_box_visible_height(node) + * synctex_node_box_visible_depth(node) * ); * The visible dimensions are bigger than real ones * to compensate 0 width boxes or nodes intentionally * put outside the box (using \\kern for example). * - parameter node: a node. * - returns: a float. * - author: JL */ float synctex_node_box_visible_h(synctex_node_p node); float synctex_node_box_visible_v(synctex_node_p node); float synctex_node_box_visible_width(synctex_node_p node); float synctex_node_box_visible_height(synctex_node_p node); float synctex_node_box_visible_depth(synctex_node_p node); /** * For quite all nodes, horizontal and vertical coordinates, and width. * All dimensions are given in page coordinates * as opposite to TeX coordinates. * The origin is at the top left corner of the page. * The visible dimensions are bigger than real ones * to compensate 0 width boxes or nodes intentionally * put outside the box (using \\kern for example). * All nodes have coordinates, but all nodes don't * have non null size. For example, math nodes * have no width according to TeX, and in that case * synctex_node_visible_width simply returns 0. * The same holds for kern nodes that do not have * height nor depth, etc... */ float synctex_node_visible_h(synctex_node_p node); float synctex_node_visible_v(synctex_node_p node); float synctex_node_visible_width(synctex_node_p node); float synctex_node_visible_height(synctex_node_p node); float synctex_node_visible_depth(synctex_node_p node); /** * Given a node, access to its tag, line and column. * The line and column numbers are 1 based. * The latter is not yet fully supported in TeX, * the default implementation returns 0 * which means the whole line. * synctex_node_get_name returns the path of the * TeX source file that was used to create the node. * When the tag is known, the scanner of the node * will also give that same file name, see * synctex_scanner_get_name below. */ int synctex_node_tag(synctex_node_p node); int synctex_node_line(synctex_node_p node); int synctex_node_column(synctex_node_p node); const char *synctex_node_get_name(synctex_node_p node); /** This is the page where the node appears. * This is a 1 based index as given by TeX. */ int synctex_node_page(synctex_node_p node); /** * Display all the information contained in the scanner. * If the records are too numerous, only the first ones are displayed. * This is mainly for informational purpose to help developers. */ void synctex_scanner_display(synctex_scanner_p scanner); /* Managing the input file names. * Given a tag, synctex_scanner_get_name will return the corresponding file name. * Conversely, given a file name, synctex_scanner_get_tag will return, the corresponding tag. * The file name must be the very same as understood by TeX. * For example, if you \input myDir/foo.tex, the file name is myDir/foo.tex. * No automatic path expansion is performed. * Finally, synctex_scanner_input is the first input node of the scanner. * To browse all the input node, use a loop like * ... * synctex_node_p = input_node; * ... * if((input_node = synctex_scanner_input(scanner))) { * do { * blah * } while((input_node=synctex_node_sibling(input_node))); * } * * The output is the name that was used to create the scanner. * The synctex is the real name of the synctex file, * it was obtained from output by setting the proper file extension. */ const char *synctex_scanner_get_name(synctex_scanner_p scanner, int tag); int synctex_scanner_get_tag(synctex_scanner_p scanner, const char *name); synctex_node_p synctex_scanner_input(synctex_scanner_p scanner); synctex_node_p synctex_scanner_input_with_tag(synctex_scanner_p scanner, int tag); const char *synctex_scanner_get_output(synctex_scanner_p scanner); const char *synctex_scanner_get_synctex(synctex_scanner_p scanner); /* The x and y offset of the origin in TeX coordinates. The magnification These are used by pdf viewers that want to display the real box size. For example, getting the horizontal coordinates of a node would require synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner) Getting its TeX width would simply require synctex_node_box_width(node)*synctex_scanner_magnification(scanner) but direct methods are available for that below. */ int synctex_scanner_x_offset(synctex_scanner_p scanner); int synctex_scanner_y_offset(synctex_scanner_p scanner); float synctex_scanner_magnification(synctex_scanner_p scanner); /** * ## Browsing the nodes * parent, child and sibling are standard names for tree nodes. * The parent is one level higher, * the child is one level deeper, * and the sibling is at the same level. * A node and its sibling have the same parent. * A node is the parent of its children. * A node is either the child of its parent, * or belongs to the sibling chain of its parent's child. * The sheet or form of a node is the topmost ancestor, * it is of type sheet or form. * The next node is either the child, the sibling or the parent's sibling, * unless the parent is a sheet, a form or NULL. * This allows to navigate through all the nodes of a given sheet node: * * synctex_node_p node = sheet; * while((node = synctex_node_next(node))) { * // do something with node * } * * With synctex_sheet_content and synctex_form_content, * you can retrieve the sheet node given the page * or form tag. * The page is 1 based, according to TeX standards. * Conversely synctex_node_parent_sheet or * synctex_node_parent_form allows to retrieve * the sheet or the form containing a given node. * Notice that a node is not contained in a sheet * and a form at the same time. * Some nodes are not contained in either (handles). */ synctex_node_p synctex_node_parent(synctex_node_p node); synctex_node_p synctex_node_parent_sheet(synctex_node_p node); synctex_node_p synctex_node_parent_form(synctex_node_p node); synctex_node_p synctex_node_child(synctex_node_p node); synctex_node_p synctex_node_last_child(synctex_node_p node); synctex_node_p synctex_node_sibling(synctex_node_p node); synctex_node_p synctex_node_last_sibling(synctex_node_p node); synctex_node_p synctex_node_arg_sibling(synctex_node_p node); synctex_node_p synctex_node_next(synctex_node_p node); /** * Top level entry points. * The scanner owns a list of sheet siblings and * a list of form siblings. * Sheets or forms have one child which is a box: * theie contents. * - argument page: 1 based sheet page number. * - argument tag: 1 based form tag number. */ synctex_node_p synctex_sheet(synctex_scanner_p scanner, int page); synctex_node_p synctex_sheet_content(synctex_scanner_p scanner, int page); synctex_node_p synctex_form(synctex_scanner_p scanner, int tag); synctex_node_p synctex_form_content(synctex_scanner_p scanner, int tag); /* This is primarily used for debugging purpose. * The second one logs information for the node and recursively displays information for its next node */ void synctex_node_log(synctex_node_p node); void synctex_node_display(synctex_node_p node); /* For quite all nodes, horizontal, vertical coordinates, and width. * These are expressed in TeX small points coordinates, with origin at the top left corner. */ int synctex_node_h(synctex_node_p node); int synctex_node_v(synctex_node_p node); int synctex_node_width(synctex_node_p node); int synctex_node_height(synctex_node_p node); int synctex_node_depth(synctex_node_p node); /* For all nodes, dimensions of the enclosing box. * These are expressed in TeX small points coordinates, with origin at the top left corner. * A box is enclosing itself. */ int synctex_node_box_h(synctex_node_p node); int synctex_node_box_v(synctex_node_p node); int synctex_node_box_width(synctex_node_p node); int synctex_node_box_height(synctex_node_p node); int synctex_node_box_depth(synctex_node_p node); #ifdef __cplusplus } #endif #endif