8000 Support editing LaTeX in an external editor by LordMZTE · Pull Request #6476 · xournalpp/xournalpp · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support editing LaTeX in an external editor #6476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

LordMZTE
Copy link

This adds support for editing LaTeX in a user-configurable external editor instead of the built-in one (disabled by default).

This also includes a small refactor where LatexController is kept as shared_ptr instead of a unique_ptr because without the dialog (necessarily) around, we would otherwise run into a scenario where the controller is destroyed before we run some callbacks.

Closes #6466

@bhennion
Copy link
Collaborator
bhennion commented Jun 12, 2025

Thanks for the PR!
First, the code looks very clean. That's great! I'll give it a thorough read once the following remarks have been addressed:

  1. The CI is failing on Windows
  2. I tried setting the external editor to either "gedit -w" or "kwrite". It both cases, if I edit the file and save, I get the Invalid Tex message. The problem might be that most editors add a trailling \n at the file. I am not sure though.
  3. Item 2. raises another problem: we no longer get access to compilation errors, nor can we preview the Tex element before adding it.
  4. You can get a segfault by doing:
    1. Open a new document. Add a page.
    2. On the second page, open the Tex editor. Leave it open.
    3. Go to Xournal++'s main window, delete the second page and write something on the first page (to clear the undo stack)
    4. Close the external editor window.
      I'm guessing theLayerController tries to add the Tex element to a destroyed page, leading to a SegFault.

I think both 3. and 4. would be neatly solved by keeping a LatexDialog that would be modal (like the default one) and hence forbid any interaction with the main window.
It would open the external editor, handle the compilation and preview, and show the compilation output (so basically, the current LatexDialog without the Tex Source tab and with an open editor button in case the user is unhappy with the preview).
If you don't want to click the extra "ok" to add the element, you could have a "Close dialog on compilation success" option.

@LordMZTE
Copy link
Author

Thanks for the feedback! I've addressed your requests. I've split the LatexDialog class up into three classes:

  • AbstractLatexDialog which implements the common funcitonality shared by the other two classes
  • LatexDialog was renamed to IntEdLatexDialog which still does the same thing but now inherits from AbstractLatexDialog
  • ExtEdLatexDialog is a lightweight version of the normal modal without the editor and an additional "Continue Editing" button as requested. It also manages the external editor. (This also shows error output now)

I've also written some code that removes a tra 8000 iling newline (which I have confirmed kwrite does add), if any. I haven't been able to get LaTeX running myself as I use Typst instead which doesn't complain about a trailing newline, it would be appreciated if you could give it a test on your LaTeX setup.

An option to automatically confirm like you suggested has also been added.

Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It all seems to works as expected. I have a couple of comments/nitpicks.

Copy link
Collaborator
@bhennion bhennion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It all looks good and works as well.

I'd be more confortable if someone could test this on Windows before we merged

@LordMZTE
Copy link
Author

Thanks! I unfortunately don't have a windows machine to test on.

@rolandlo
Copy link
Member

I have tested it on Windows using gedit. There's some issue with line ending, which makes pdflatex unable to compile the tex.tex file.
See here for the tex-folder tex.zip

Relevant line in the log:

! Text line contains an invalid character.
l.30 ^^@

@LordMZTE
Copy link
Author

That's interesting, it seems like tex.tex contains a null byte after your input. I'm unsure where that came from, but I suspect something must be up with the trailing CRLF removing logic in ExtEdLatexDialog::getBufferContents. I'll investigate.

@LordMZTE
Copy link
Author

Looks like the code used to incorrectly look for \n\r instead of \r\n, which caused your edit.tex to contain z^2\r, which is definitely invalid, but I still have no clue how the null managed to get there. Could you please test again on the latest revision?

@rolandlo
Copy link
Member

Looks like the code used to incorrectly look for \n\r instead of \r\n, which caused your edit.tex to contain z^2\r, which is definitely invalid, but I still have no clue how the null managed to get there. Could you please test again on the latest revision?

We open the file in (text) reading mode. From https://en.cppreference.com/w/cpp/io/c/FILE.html#Binary_and_text_modes

(in particular, C streams on Windows OS convert '\n' to '\r\n' on output, and convert '\r\n' to '\n' on input).
We should account for that in some way.

@rolandlo
Copy link
Member

Looks like the code used to incorrectly look for \n\r instead of \r\n, which caused your edit.tex to contain z^2\r, which is definitely invalid, but I still have no clue how the null managed to get there. Could you please test again on the latest revision?

We open the file in (text) reading mode. From https://en.cppreference.com/w/cpp/io/c/FILE.html#Binary_and_text_modes

(in particular, C streams on Windows OS convert '\n' to '\r\n' on output, and convert '\r\n' to '\n' on input).
We should account for that in some way.

It all works after applying this patch:

--- a/src/util/PathUtil.cpp
+++ b/src/util/PathUtil.cpp
@@ -63,11 +63,10 @@ auto Util::getLongPath(const fs::path& path) -> fs::path { return path; }
 auto Util::readString(fs::path const& path, bool showErrorToUser, std::ios_base::openmode openmode)
         -> std::optional<std::string> {
     try {
-        std::string s;
+        std::stringstream buffer;
         std::ifstream ifs{path, openmode};
-        s.resize(fs::file_size(path));
-        ifs.read(s.data(), as_signed(s.size()));
-        return {std::move(s)};
+        buffer << ifs.rdbuf();
+        return buffer.str();
     } catch (const fs::filesystem_error& e) {
         if (showErrorToUser) {
             XojMsgBox::showErrorToUser(nullptr, e.what());

@LordMZTE
Copy link
Author

Thank you! I've applied your patch!

@rolandlo
Copy link
Member

I tested on MacOS ARM.

  • With editor command nano nothing showed up (and there was no error message either).
  • With editor command open /Applications/TeX/TeXShop.app the TeXShop app showed up and I could modify the formula. However after saving and quitting, the preview wasn't updated. Only after I hit Continue editing the preview updated. Not sure how this should be handled.

@bhennion
Copy link
Collaborator
  • With editor command open /Applications/TeX/TeXShop.app the TeXShop app showed up and I could modify the formula. However after saving and quitting, the preview wasn't updated. Only after I hit Continue editing the preview updated. Not sure how this should be handled.

I'm guessing that TeXShop returns straight away (and its main process has been forked). So, on our end, the GSubprocess returns immediately, so the preview gets updated right after the editor is opened instead of after its termination.

I don't see a way to handle this kind of cases (other than running texshop with some kind of no-fork flag, if any is implemented).

@rolandlo
Copy link
Member
  • With editor command open /Applications/TeX/TeXShop.app the TeXShop app showed up and I could modify the formula. However after saving and quitting, the preview wasn't updated. Only after I hit Continue editing the preview updated. Not sure how this should be handled.

I'm guessing that TeXShop returns straight away (and its main process has been forked). So, on our end, the GSubprocess returns immediately, so the preview gets updated right after the editor is opened instead of after its termination.

I don't see a way to handle this kind of cases (other than running texshop with some kind of no-fork flag, if any is implemented).

Could it be the open command that returns straight away after launching TeXShop? Maybe I need to use the -W option to wait for the application to quit. See https://www.jviotti.com/2022/11/28/launching-macos-applications-from-the-command-line.html. I will test once I return home.

@rolandlo
Copy link
Member
  • With editor command open /Applications/TeX/TeXShop.app the TeXShop app showed up and I could modify the formula. However after saving and quitting, the preview wasn't updated. Only after I hit Continue editing the preview updated. Not sure how this should be handled.

I'm guessing that TeXShop returns straight away (and its main process has been forked). So, on our end, the GSubprocess returns immediately, so the preview gets updated right after the editor is opened instead of after its termination.
I don't see a way to handle this kind of cases (other than running texshop with some kind of no-fork flag, if any is implemented).

Could it be the open command that returns straight away after launching TeXShop? Maybe I need to use the -W option to wait for the application to quit. See https://www.jviotti.com/2022/11/28/launching-macos-applications-from-the-command-line.html. I will test once I return home.

Unfortunately using the -W option with the open command didn't solve the problem. It waits indefinitely after closing the editor, even if I run it from the terminal. That's not how it's supposed to work, I think, but it does so on my system.

@LordMZTE
Copy link
Author

Unfortunately using the -W option with the open command didn't solve the problem. It waits indefinitely after closing the editor, even if I run it from the terminal. That's not how it's supposed to work, I think, but it does so on my system.

Perhaps TeXShop forks off additionally to open? Could you check if it has a command line option regarding this?

(note that I have absolutely no experience with MacOS)

@rolandlo
Copy link
Member

Unfortunately using the -W option with the open command didn't solve the problem. It waits indefinitely after closing the editor, even if I run it from the terminal. That's not how it's supposed to work, I think, but it does so on my system.

Perhaps TeXShop forks off additionally to open? Could you check if it has a command line option regarding this?

(note that I have absolutely no experience with MacOS)

There are no command line options for TeXShop on MacOS. See

#6476 (comment)

It also cannot be started via /path/to/bundle.app/Contents/MacOS/name-of-binary like other app-bundles (e.g. Xournal++.app) for some reason. Same applies to the default text editor (TextEdit.app).

@rolandlo
Copy link
Member

I have also tried Texifier. This one can also be run directly through the binary: /Applications/Texifier.app/Contents/MacOS/Texifier. Neither that nor opening the app bundle via open or open -W worked. The preview didn't update after I closed the Texifier app. I haven't found any command line arguments. Seems like that's more of a Linux/open source cross platform thing than something integrated into common MacOS GUI apps.

@bhennion
Copy link
Collaborator

One possible solution could be to switch from "I wait until the app terminates" to "I wait until the file is saved" using a GFileMonitor.

@LordMZTE
Copy link
Author
LordMZTE commented Jun 19, 2025

One possible solution could be to switch from "I wait until the app terminates" to "I wait until the file is saved" using a GFileMonitor.

This poses quite a few questions:

  • Some editors save files by deleting the old file, then creating a new one (neovim). If we use g_file_monitor_file that may cause us to miss events, if we use g_file_monitor_directory that function isn't supported on all platforms:

    This may fail if directory monitoring is not supported.

    (that remark isn't present for g_file_monitor_file)

  • How should this interact with the auto-confirm option? We now have no way of knowing when the user is actually finished editing, as there might just be intermediate saves (or even autosaves).

  • How should this interact with the "Continue Editing" button? We now don't know when to disable it and when it should be available.

  • This may cause some strange behavior if the user:

    1. Adds a LaTeX element, pressing Ok on the dialog while the editor is still open (which would normally kill the editor but we now can't do that since it's forked off)
    2. Adds another LaTeX element. Now we have two editors open editing the same file, which may cause confusion.
  • What if the user closes the dialog with the editor open like above, but then keeps editing the file while expecting the LaTeX element to keep updating? If we want this to work, we'd have to do some major refactoring.

    • If we did want to implement this, how do we know when to stop watching the file (i.e. when the user is actually done)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Option to edit LaTeX code in external editor
3 participants
0