TeX 或 Synctex 在单词定位的设计上存在明显的缺陷。
给定 .tex 文件中的文本:
Blah blah blah. This is a sentence blah! Blah Blah!
整个段落被视为一个单位,而不是单个的单词。
事实证明,如果在每个单词或行中添加新行,那么同步效果就会很好:
Blah
blah
blah.
This
is
a
sentence
blah!
Blah
Blah!
我们得到的是单词的准确度。
问题在于,它使得读取 tex 文件变得毫无意义,因此它不是一个合适的解决方案。
一个真正的解决方案是让编译器自动将单词(或行)翻译成单独的行。
这将为单词或行解析提供适当的语法,但反向传播不会与原始未改变的 .tex 文件匹配。
需要跟踪线路信息,然后进行反向映射。
有什么方法可以轻松做到这一点?
例如,
Line1:
Blah blah blah. This is a sentence blah! Blah Blah!
Line2:
变成
Line1:
Blah
Line 2:
blah
Line 3:
blah.
Line 4:
This
Line 5:
is
Line 6:
a
Line 7:
sentence
Line 8:
blah!
Line 9:
Blah
Line 10:
Blah!
然后跟踪这些插入的新行的位置,并将其逆映射回插入它们的列。
这都是基本的映射,除了一些问题外,只需几行代码就很容易完成。
1:不得在无效位置插入新行,否则会破坏 .tex 文件或更改其输出。2:响应 synctex 的编辑器必须能够执行从行到行/列的逆映射。
本质上,只要不破坏 .tex 代码并能获得单词级精度,就可以在每个空格中插入一个新行。如果可以确定正确的单词边界,则可以在编译前完成此操作。我认为,如果可以在以下环境中完成,效果会更好:
\begin{synctexing}
…
\end{synctexing}
这实质上是将新行添加到中间的所有文本并忽略里面的任何环境,因此可以插入诸如 tikz 图片之类的内容,而不必创建一堆环境。
它只会输出映射文件(行/列到行),并且编辑器必须能够反转映射(很容易,但它需要支持它,除非它们已经支持列(但 synctex 总是给它们 0)。
问题不在于这很难,而在于我对具体细节一无所知。
事实上,即使我们必须做一些事情,比如\snl
在 synctex 中添加一个新行,也比什么都不做要好。
答案1
SyncTeX 架构目前将 PDF 页面上的位置映射到输入文件中的行和“标签”(我真的不知道“标签”是什么)。
这是来自的 SyncTeX 数据结构syntex.c
:
/* Here are all the local variables gathered in one "synchronization context" */
static struct {
void *file; /* the foo.synctex or foo.synctex.gz I/O identifier */
synctex_fprintf_t fprintf; /* either fprintf or gzprintf */
char *busy_name; /* the real "foo.synctex(busy)" or "foo.synctex.gz(busy)" name, with output_directory */
char *root_name; /* in general jobname.tex */
integer count; /* The number of interesting records in "foo.synctex" */
/* next concern the last sync record encountered */
halfword node; /* the last synchronized node, must be set
* before the recorder */
synctex_recorder_t recorder;/* the recorder of the node above, the
* routine that knows how to record the
* node to the .synctex file */
integer tag, line; /* current tag and line */
integer curh, curv; /* current point */
integer magnification; /* The magnification as given by \mag */
integer unit; /* The unit, defaults to 1, use 8192 to produce shorter but less accurate info */
integer total_length; /* The total length of the bytes written since the last check point */
integer options; /* unsigned options */
integer lastv; /* compression trick if
|synctex_options&4|>0. */
integer form_depth; /* pdf forms are an example of nested sheets */
struct _flags {
unsigned int option_read:1; /* Command line option read (in case of problem or at the end) */
unsigned int content_ready:1; /* Command line option read (in case of problem or at the end) */
unsigned int off:1; /* Definitely turn off synctex, corresponds to cli option -synctex=0 */
unsigned int no_gz:1; /* Whether zlib is used or not */
unsigned int not_void:1; /* Whether it really contains synchronization material */
unsigned int warn:1; /* One shot warning flag */
unsigned int quoted:1; /* Whether the input file name was quoted by tex or not, for example "\"my input file.tex\"", unused by XeTeX */
unsigned int output_p:1; /* Whether the output_directory is used */
unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-8; /* Align */
} flags;
} synctex_ctxt = {
要在输入文件中记录该列,您必须向数据结构添加另一个字段,并调整所有记录器功能以将此条目写入 SyncTeX 文件。下一步是调整 SyncTeX 解析器以从 SyncTeX 文件中选取该列。然后,您必须编辑编辑器的源代码,使其知道反向搜索现在也映射到该列。最难的部分是,以上所有操作都必须以向后兼容的方式完成,以便您的编辑器仍然可以读取旧版本的 SyncTeX 文件,并且旧解析器仍然可以读取使用新版本编写的 SyncTeX 文件。
所以,从理论上讲,实现你的想法是可能的,但找到一个实际做到这一点的人可能NP困难。
答案2
首先,synctex 通常是怎样工作的?基本上,在编辑代码时,正向同步是通过调用
synctex view -i line:column:[page_hint:]input
它根据输入文件中的行和列进行操作,并尝试在输出中找到位置。因此,至少前向同步可以按照您想要的方式进行。
对于向后同步,查看器调用
synctex edit -o page:x:y:file -x editor-command
它代表页码、鼠标事件的 x 和 y 坐标以及文件名。在编辑器命令中,您实际上可以使用%{column}
它将列传递给编辑器。但请注意,列支持相当脆弱。
根据手册页框和记录(current、kern、glue、math)有列支持,但这是可选的。因此,基本上引擎允许将列输出到 synctex 文件。但实际上,您会注意到链接部分仅由标签(框或记录的内部表示/id)和行号组成,因此您必须为此添加引擎支持。
这也是为什么您的环境不会提供任何帮助的原因,因为基本上 TeX 的“解释器”,引擎并不知道这一点。这就是您必须努力的方向,请记住,有些编辑器可能也不支持列输入。
答案3
\documentclass{article}
\newcommand{\AND}{\par}
\obeyspaces\obeylines
\begingroup\lccode`\~=`\ \lowercase{\endgroup\let~}\AND
\begingroup\lccode`\~=`\^^M\lowercase{\endgroup\let~}\AND
\begin{document}
Blah blah blah. This is a sentence blah! Blah Blah!
\bigskip
Line1:
Blah blah blah. This is a sentence blah! Blah Blah!
Line2:
\end{document}