Example #1
0
/**
 * 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;
}
Example #2
0
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));
		}
	}
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
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);
}