From 6d509234e5638209a08d8abf36a592eae02b791f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Sun, 5 Apr 2026 17:06:27 +0900 Subject: [PATCH 1/5] editor: add an experimental lookup-file message --- emacs/texpresso.el | 2 ++ src/frontend/editor.c | 21 +++++++++++++++++++++ src/frontend/editor.h | 1 + src/frontend/engine_tex.c | 3 +++ 4 files changed, 27 insertions(+) diff --git a/emacs/texpresso.el b/emacs/texpresso.el index 979c7ad..af91d03 100644 --- a/emacs/texpresso.el +++ b/emacs/texpresso.el @@ -319,6 +319,8 @@ standard output. This function interprets one of these." ((eq tag 'input-file)) + ((eq tag 'lookup-file)) + (t (message "Unknown message in texpresso output: %S" expr))))) (defun texpresso--stdout-filter (process text) diff --git a/src/frontend/editor.c b/src/frontend/editor.c index dac5b1d..184bc42 100644 --- a/src/frontend/editor.c +++ b/src/frontend/editor.c @@ -586,3 +586,24 @@ void editor_notify_file_opened(int index, const char *path, int len) case EDITOR_JSON: fprintf(stdout, "\"]\n"); break; } } + +void editor_notify_lookup(const char *path, int len, bool read, bool success) +{ + const char *kind = read ? "read" : "write"; + const char *status = success ? "successful" : "failed"; + switch (protocol) + { + case EDITOR_SEXP: + fprintf(stdout, "(lookup-file %s %s \"", kind, status); + break; + case EDITOR_JSON: + fprintf(stdout, "[\"lookup-file\", \"%s\", \"%s\", \"", kind, status); + break; + } + output_data_string(stdout, path, len); + switch (protocol) + { + case EDITOR_SEXP: fprintf(stdout, "\")\n"); break; + case EDITOR_JSON: fprintf(stdout, "\"]\n"); break; + } +} diff --git a/src/frontend/editor.h b/src/frontend/editor.h index 6aef93f..025faed 100644 --- a/src/frontend/editor.h +++ b/src/frontend/editor.h @@ -136,5 +136,6 @@ void editor_flush(void); void editor_synctex(const char *dirname, const char *basename, int basename_len, int line, int column); void editor_reset_sync(void); void editor_notify_file_opened(int index, const char *path, int len); +void editor_notify_lookup(const char *path, int len, bool read, bool success); #endif // EDITOR_H_ diff --git a/src/frontend/engine_tex.c b/src/frontend/engine_tex.c index 7651017..0850c84 100644 --- a/src/frontend/engine_tex.c +++ b/src/frontend/engine_tex.c @@ -496,6 +496,7 @@ static void answer_query(fz_context *ctx, struct tex_engine *self, query_t *q) log_fileentry(ctx, self->log, e); record_seen(self, e, INT_MAX, q->time); a.tag = A_PASS; + editor_notify_lookup(q->open.path, strlen(q->open.path), q->tag == Q_OPRD, false); channel_write_answer(self->c, p->fd, &a); break; } @@ -529,6 +530,7 @@ static void answer_query(fz_context *ctx, struct tex_engine *self, query_t *q) log_fileentry(ctx, self->log, e); record_seen(self, e, INT_MAX, q->time); a.tag = A_PASS; + editor_notify_lookup(q->open.path, strlen(q->open.path), q->tag == Q_OPRD, false); channel_write_answer(self->c, p->fd, &a); break; } @@ -620,6 +622,7 @@ static void answer_query(fz_context *ctx, struct tex_engine *self, query_t *q) int n = strlen(q->open.path); a.open.path_len = n; a.tag = A_OPEN; + editor_notify_lookup(q->open.path, n, q->tag == Q_OPRD, true); memmove(channel_get_buffer(self->c, n), q->open.path, n); channel_write_answer(self->c, p->fd, &a); break; From b2a92a30c59b66c6cf6f7e0196b722bb281c8289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Tue, 7 Apr 2026 18:24:01 +0900 Subject: [PATCH 2/5] Document the change --- CHANGELOG.md | 1 + EDITOR-PROTOCOL.md | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0adccf6..0ee578a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # NEXT +- add `(lookup-file)` message to notify editor of file lookups - fix TeX build date to use SOURCE_DATE_EPOCH if set, otherwise falling back to the current date (previously hardcoded to Feb 8, 2025). - fix zealous JSON escaping diff --git a/EDITOR-PROTOCOL.md b/EDITOR-PROTOCOL.md index 2eb25f7..4b5180f 100644 --- a/EDITOR-PROTOCOL.md +++ b/EDITOR-PROTOCOL.md @@ -209,3 +209,14 @@ The paths are printed relative to the root file. They might be non-existent on t Right now, this is implemented by hooking into SyncTeX: - only text files are tracked (not graphics) - the indices printed are the SyncTex input indices; they should be attributed no other meaning than being monotonic and useful to detect backtracking occurrences + +### File lookups + +``` +(lookup-file kind status "path") +``` + +Output by TeXpresso when it tries to look up a file. +- `kind`: either `read` or `write`. +- `status`: either `successful` or `failed`. +- `path`: the path to the file. From d9cba10e554206e3f24838816c0541821119ffd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Wed, 15 Apr 2026 11:12:35 +0900 Subject: [PATCH 3/5] nitpicking: cleanup build message --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index c435c28..d71a9b7 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,6 @@ all: @echo "# Or:" @echo "# build/texpresso -texlive test/simple.tex" @echo "# build/texpresso -tectonic test/simple.tex" - @echo "#" common: $(MAKE) -C src/common From da1a517f65967d9ffafa5844b791b8ec1f20016a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bour?= Date: Wed, 15 Apr 2026 11:22:45 +0900 Subject: [PATCH 4/5] initialize_only: try to produce at least one page Imported from a larger change by @merv1n34k as part of "Stream mode: Phase 3" (#125). --- src/frontend/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/frontend/main.c b/src/frontend/main.c index cbe436a..658ec0c 100644 --- a/src/frontend/main.c +++ b/src/frontend/main.c @@ -1461,7 +1461,9 @@ bool texpresso_main(struct persistent_state *ps) break; } } - if (ps->initialize_only) + if (ps->initialize_only && + (send(page_count, ui->eng) > 0 || + (send(get_status, ui->eng) == DOC_TERMINATED && stdin_eof))) { fprintf(stderr, "[info] Initialize mode: terminating engine process\n"); quit = 1; From e6233136902a4af7f93ed03e0829ad0790675a8d Mon Sep 17 00:00:00 2001 From: Oleksii Stroganov Date: Thu, 2 Apr 2026 16:51:37 +0300 Subject: [PATCH 5/5] chore: add request-file integration test --- Makefile | 5 +++- test/request-file.tex | 5 ++++ test/test-request-file.sh | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/request-file.tex create mode 100755 test/test-request-file.sh diff --git a/Makefile b/Makefile index d71a9b7..9be3c6c 100644 --- a/Makefile +++ b/Makefile @@ -109,4 +109,7 @@ test-stream: test-stream-pipe: test/test_stream.sh -.PHONY: all dev clean config texpresso common texpresso-xetex re2c compile_commands.json fill-tectonic-cache test-texlive test-tectonic test-texpresso test-stream test-stream-pipe test-open-base64 +test-request-file: + bash test/test-request-file.sh + +.PHONY: all dev clean config texpresso common texpresso-xetex re2c compile_commands.json fill-tectonic-cache test-texlive test-tectonic test-texpresso test-stream test-stream-pipe test-open-base64 test-request-file diff --git a/test/request-file.tex b/test/request-file.tex new file mode 100644 index 0000000..4219056 --- /dev/null +++ b/test/request-file.tex @@ -0,0 +1,5 @@ +\documentclass[12pt]{article} +\begin{document} +Hello. +\input{texpresso_ci_missing_file.tex} +\end{document} diff --git a/test/test-request-file.sh b/test/test-request-file.sh new file mode 100755 index 0000000..73460b3 --- /dev/null +++ b/test/test-request-file.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# Test request-file: engine requests a missing file via Q_OPRL (non-blocking), +# test provides the file, engine restarts and processes it successfully. +set -e + +FIFO=$(mktemp -u /tmp/texpresso-fifo-XXXXXX) +OUTFILE=$(mktemp /tmp/texpresso-out-XXXXXX) +mkfifo "$FIFO" +trap 'rm -f "$FIFO" "$OUTFILE"; kill "$PID" 2>/dev/null || true' EXIT + +TARGET="texpresso_ci_missing_file.tex" + +# Start texpresso in background, reading stdin from FIFO, stdout to file +SDL_VIDEODRIVER=dummy build/texpresso -test-initialize test/request-file.tex \ + < "$FIFO" > "$OUTFILE" 2>/dev/null & +PID=$! + +# Open FIFO for writing (unblocks texpresso's stdin) +exec 3>"$FIFO" + +# Wait for request-file for the target file (ignore .aux etc.) +TIMEOUT=120 +while ! grep -q "request-file \"$TARGET\"" "$OUTFILE" 2>/dev/null; do + sleep 0.5 + TIMEOUT=$((TIMEOUT - 1)) + if [ $TIMEOUT -le 0 ]; then + echo "FAIL: timeout waiting for request-file" + echo "stdout contents:" + cat "$OUTFILE" + exit 1 + fi + if ! kill -0 "$PID" 2>/dev/null; then + echo "FAIL: texpresso exited before emitting request-file for $TARGET" + echo "stdout contents:" + cat "$OUTFILE" + exit 1 + fi +done + +echo "Got request-file for: $TARGET" + +# Provide the missing file content +printf '(open "%s" "Included content.\\n")\n' "$TARGET" >&3 +exec 3>&- + +# Wait for texpresso to finish (it exits after page_count > 0 in -test-initialize mode) +if wait "$PID"; then + echo "PASS: request-file test" +else + echo "FAIL: texpresso exited with error" + exit 1 +fi