Edit 4: It turns out that this is actually just a limitation of TTY input in general; there’s nothing specific about OCaml, Coq, or Emacs which is causing the problem.
I’m working on a Coq program using Proof General in Emacs, and I’ve found a bug with input that’s too long. If a region to submit to coqtop through Proof General contains more than 1023 characters, Proof General (though not Emacs) hangs while waiting for a response, and the *coq* buffer contains one extra ^G character for every character over 1023. For instance, if a 1025-character region was sent to coqtop, then the *coq* buffer would end with the two extra characters ^G^G. I can’t proceed past this point in the file, and I have to kill the coqtop process (either with C-c C-x or a kill/killall from the terminal).
Something about this limitation arises from coqtop itself. If one generates a 1024-character or longer string and pipes it in, such as by running
perl -e 'print ("Eval simpl in " . (" " x 1024) . "1.\n")' | coqtop
then everything works fine. (Similarly, coqc works fine as well.) However, if I run coqtop in a terminal, I can’t type more than 1024 characters on one line, including the ending return character. Thus, typing a 1023-character line and then hitting return works; but after typing 1024 characters, hitting any key, including return (but not including delete, etc.), does nothing but produce a beep. And it turns out that ocaml (the OCaml toplevel) has the same behavior:
perl -e 'print ((" " x 1024) . "1;;")' | ocaml
works fine, but I can’t type more than 1024 characters on one line if running ocaml from a terminal. Since my understanding is that coqtop relies on the OCaml toplevel (more obviously when run as coqtop -byte), I imagine this is a related limitation.
The relevant software versions are:
- OCaml 3.12.1 from Homebrew;
- Coq 8.3pl3 (and 8.3pl2) from Homebrew;
- Proof General 4.1;
- The build of GNU Emacs 24.1.1 from Emacs for Mac OS X; and
- Mac OS X 10.6.7.
And my questions are:
- What about
ocamlandcoqtopis enforcing this character limit? And why only for input from the terminal or Emacs, as opposed to input from a pipe or a file? - Why does Proof General’s (apparent) ignorance of this limit cause hanging errors and mysterious
^Gs? - How can I work around this limitation? My end goal is to use Coq inside Proof General/Emacs, so workarounds which dodge the underlying issue are fine.
Edit 3: After finding that the 1024-character input limitation also exists in the Ocaml toplevel (something which I imagine is related), I’ve added that information and deleted the original problem description, as it’s been completely obscured and superseded. (See the edit history if necessary).
I reported this as issue 5678 on the OCaml bug tracker, and the user dim explained that this wasn’t a problem with OCaml per se, but was a limitation of TTY input. The issue is this. Since text isn’t sent to running commands until the user hits return, all that waiting input must be stored somewhere. The buffer it’s stored in, called the input queue or the type-ahead buffer, has a fixed size, which is controlled by the C constant
MAX_INPUT. This constant is equal to 1024 on Mac OS X. Buffering like this allows useful processing of input, such as deleting characters before they’re sent. All commands run from the terminal which don’t do something special (such as using thereadlinelibrary) will exhibit this behavior; for example,catchokes in exactly the same way.To avoid this behavior, one can unset the
ICANONflag, for instance by runningstty -icanon; this puts the TTY into non-canonical input mode, where input is not processed at all before being sent to the command. This means that editing becomes impossible: delete, left and right arrows, and so on all enter their literal equivalents (^?,^[[D,^[[C, …); similarly, ⌃D no longer sends an EOF, but merely a literal control character. However, for my particular use case, this (so far!) seems to be ideal, since Emacs is handling all my input for me. (Edit: But there’s a better option!) (Libraries likereadline, as I understand it, change this setting as well, but watch for control characters and handle editing, etc., themselves.) To restore canonical mode, one can runstty icanon.The
ledittool wraps line editing around the program given to it as an argument, soledit coqtopworks fine (if oddly; I preferledit -l 65536to avoid its scrolling), but interacted oddly with Emacs. Therlwraptool does the same thing, but leaves the other program reading from a TTY; thus, while it can receive longer inputs, hitting enter and sending them to the wrapped command behaves very strangely and ends up necessitating that the command be killed.Edit: In my specific use-case, I can also simply tell Emacs to use a pipe instead of a PTY, solving the problems at a stroke. The Emacs variable
process-connection-typecontrols how subsidiary processes are communicated with;nilmeans to use a pipe, and non-nilmeans to use a TTY. Proof General uses the variableproof-shell-process-connection-typeto determine how this should be set. Using a pipe solves all the 1024-character-limit problems.