无法为OCaml顶层和coqtop(以及Proof General)提供长(1024+个字符)输入

时间:2012-07-04 02:52:04

标签: emacs ocaml tty coq proof-general

编辑4 :事实证明这实际上只是TTY输入的限制;没有具体的OCaml,Coq或Emacs导致问题。


我正在使用Emacs中的Proof General处理Coq程序,我发现输入的错误太长了。如果通过Proof General提交到coqtop的区域包含超过1023个字符,则在等待响应时,Proof General(虽然不是Emacs)会挂起,而*coq*缓冲区包含一个额外的^G每个字符超过1023的字符。例如,如果将一个1025个字符的区域发送到coqtop,则*coq*缓冲区将以两个额外字符^G^G结束。我无法在文件中继续这一点,我必须终止coqtop进程(使用 Cc Cx kill / killall终端)。

关于这种限制的一些事情来自于coqtop本身。如果生成一个1024个字符或更长的字符串并将其输入,例如运行

perl -e 'print ("Eval simpl in " . (" " x 1024) . "1.\n")' | coqtop

然后一切正常。 (同样,coqc也可以正常工作。)然而,如果我在终端中运行coqtop,我就不能在一行上输入超过1024个字符,包括结束返回字符。因此,输入一个1023个字符的行然后点击返回工作;但是在输入1024个字符后,点击任何键,包括返回(但不包括删除等),除了产生哔声之外什么都不做。事实证明ocaml(OCaml toplevel)具有相同的行为:

perl -e 'print ((" " x 1024) . "1;;")' | ocaml

工作正常,但如果从终端运行ocaml,我不能在一行上输入超过1024个字符。由于我的理解是coqtop依赖于OCaml顶层(更明显地当作为coqtop -byte运行时),我想这是一个相关的限制。

相关软件版本为:

我的问题是:

  • ocamlcoqtop如何强制执行此字符限制?为什么只有来自终端或Emacs的输入,而不是来自管道或文件的输入?
  • 为什么Proof General(明显)对此限制的无知会导致挂起错误和神秘的^G
  • 我如何解决这个限制?我的最终目标是在Proof General / Emacs中使用Coq,因此可以解决潜在问题的解决方法很好。

编辑3:在发现Ocaml toplevel中存在1024个字符的输入限制(我想象的相关)之后,我添加了该信息并删除了原始问题描述,因为它已被完全模糊和取代。 (如有必要,请参阅the edit history。)

2 个答案:

答案 0 :(得分:5)

我在OCaml错误跟踪器上将此报告为issue 5678,并且用户dim解释说这不是OCaml 本身的问题,而是TTY输入的限制。问题是这个。由于文本不会发送到正在运行的命令,直到用户返回,所有等待输入必须存储在某处。它所存储的缓冲区(称为输入队列或预先输入缓冲区)具有固定大小,由C常量MAX_INPUT控制。 This constant is equal to 1024 on Mac OS X。像这样的缓冲允许有用的输入处理,例如在发送之前删除字符。从终端运行的所有不执行特殊操作的命令(例如使用readline库)都会出现此行为;例如,cat以完全相同的方式窒息。

要避免此行为,可以取消设置ICANON标志,例如运行stty -icanon;这会将TTY放入non-canonical input mode,在发送到命令之前根本不处理输入。这意味着编辑变得不可能:删除,左箭头和右箭头等等都输入它们的文字等价物(^?^[[D^[[C,...);类似地, ^ D 不再发送EOF,而只是一个文字控制字符。但是,对于我的特定用例,这个(到目前为止!)似乎是理想的,因为Emacs正在处理我的所有输入。 (编辑:但是有一个更好的选择!)(据我所知,readline这样的库也改变了这个设置,但是要注意控制字符和处理编辑等等。)要恢复规范模式,可以运行stty icanon

ledit工具围绕作为参数赋予它的程序进行行编辑,因此ledit coqtop工作正常(如果奇怪;我更喜欢ledit -l 65536以避免其滚动),但是相互作用与Emacs奇怪的是。 rlwrap工具执行相同的操作,但让其他程序从TTY读取;因此,虽然可以接收更长的输入,但是输入并将它们发送到包装的命令会表现得非常奇怪并最终导致命令被杀死。

编辑:在我的具体用例中,我还可以简单地告诉Emacs使用管道而不是PTY,一次解决问题。 Emacs变量process-connection-type控制子流程如何与之通信; nil表示使用管道,非nil表示使用管道。 Proof General使用变量proof-shell-process-connection-type来确定应如何设置。使用管道解决了所有1024个字符限制的问题。

答案 1 :(得分:4)

我不确定Emacs / coqtop交互如何在这里播放,但我相信确实有一个OCaml顶级错误,应该报告in the OCaml bugtracker。你准备报告了吗?如果没有,我可以照顾它。

  

ocaml和coqtop如何强制执行此字符限制?

在顶层代码中有各种输入缓冲区,其中一些长度为1024;在快速查看代码之后,如果输入太大,则会有一个调整大小的逻辑,因此应该工作。我已经能够重现“在交互式顶层中不能输入超过N个字符”的问题(当不使用rlwrap时),但是N = 4096限制而不是N = 1024,所以我是不确定这是完全相同的问题。

  

为什么只有来自终端或Emacs的输入,而不是来自管道或文件的输入?

顶级代码区分交互式和非交互式输入; IIRC。例如,它会影响错误位置的打印方式。

  

为什么证明一般(明显)忽略这个限制会导致悬挂错误和神秘的^ Gs?

我不知道。您观察到的coqtop问题甚至可能是由类似的缓冲逻辑导致的不同的错误(比ocaml错误。)

  

我如何解决这个限制?

如何在Proof General中不立即发送过长的输入?也许您可以将代码分解为使用中间定义或其他东西,以保持在限制之下。

关于“上游修复”的情况:我相信,OCaml和Coq都很快就会获得新版本。如果人们对bug有足够的兴趣来尽快得到修复(特别是,如果你自己找到修复),它可以合理地快速集成到上游。否则,您将不得不等待下一个发布周期,并可能在此期间维护本地分支以避免此问题。实际上,“改变我的Coq开发”的选择可能是最省力的解决方案,但它不会对整个人类有益!

修改(回答评论)

我想到的调整大小逻辑位于Lexing.lex_refill中,位于stdlib/lexing.ml中,由Lexing.from_function创建的闭包调用,从toplevel/toploop.ml调用。

我有另一个“解决方法”的想法:将您的长短语写入外部文件foo.v,并使用Load foo.来获取顶级文件以读取文件本身。我怀疑这可以解决尺寸限制,但尚未测试。