Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Resizing problems when importing readline #4448

Closed
imneedle opened this issue Apr 26, 2024 · 1 comment
Closed

Resizing problems when importing readline #4448

imneedle opened this issue Apr 26, 2024 · 1 comment

Comments

@imneedle
Copy link

imneedle commented Apr 26, 2024

Textual application having problems resizing when importing readline

I have developed a Textual-based application that I want to integrate into my main application. I am facing some problems because my main application is calling import readline, which is breaking the Textual application's resizing capabilities.

Some context

  • I have built a TUI using Textual, and now I would like to attach it to my main application.
  • The main application is going to be running some code, such as printing information to stdout and writing to files.
  • What I would like to do is to launch the main application, which itself launches the Textual application, and does so without blocking the main application's code.
  • Additionally, it would be ideal if once I quit the textual application, it restores the stdout to be what it would have been if the textual application was never launched.
  • Basically I want something like this:
import time
from datetime import datetime
from pathlib import Path

from textual.app import App, ComposeResult
from textual.widgets import Static


class DummyApp(App):
    def compose(self) -> ComposeResult:
        for _ in range(15):
            yield Static("This is a dummy Test GUI")


file_path = Path("some-file.txt")
launch_app = True
while True:
    # This is the main application's code doing some work
    print("Hello, doing work from the main application")
    file_path.write("Hello, main application writing to file")
 
    if launch_app:
        launch_app = False  # don't re launch app after
        # HERE start textual application
        app = App()
        app.run()

    time.sleep(5)  # simulate expensive workload

Solution I came up with and it's problem

  • In order to launch a textual app without block the rest of the application's code, the main application launches a Thread. That thread will make a call to subprocess.Popen to run the textual application.
  • The code roughly looks like this:
    import subprocess
    import threading
    import time
    from datetime import datetime
    from pathlib import Path
    
    from textual.app import App, ComposeResult
    from textual.widgets import Static
    
    
    class DummyApp(App):
       def compose(self) -> ComposeResult:
           for _ in range(15):
               yield Static("This is a dummy Test GUI")
    
    
    
    def run_textual_app():
        process = subprocess.Popen(["python3", "app.py"])  # where app.py launches the DummyApp via app.run()
        process.wait()
    
    file_path = Path("some-file.txt")
    launch_app = True
    while True:
        print("Hello, world!")  # simulating doing work in the main application
        file_path.write("Hello, world!")  # writing to files too
    
        if launch_app:
            launch_app = False  # don't re launch app after
            threading.Thread(target=run_textual_app).start()
     
        time.sleep(5)  # simulate expensive workload
  • This partially works, as it does allow to launch the textual application without blocking the main application, however it causes problems because the main application is writing to stdout:
    screenshot_at_2024-04-05_09-33-24

Fix for the stdout problem

  • My idea for this problem was to use os.dup2 to switch the file descriptors of the main application to write to a temporary file instead of writing to stdout.
  • I did this via :
import os
import sys
import subprocess

def run_textual_app():
    original_stdout_fd = sys.stdout.fileno()  # keep reference to original file descriptor of stdout
    temp_stdout_fd = os.dup(original_stdout_fd)  # store that inside temp_stdout_fd so we can restore stdout later
    
    with open("./tmp-stdout.log", "w") as f:
        os.dup2(f.fileno(), original_stdout_fd)  # make stdout of main application write the tmp-stdout.log file
        
        process = subprocess.Popen(["python", "app.py"])
        process.wait()
       
        # Here, the textual application is done running, we restore stdout
        os.dup2(temp_stdout_fd, original_stdout_fd)
        os.close(temp_stdout_fd)

    # Restore stdout to be as if we never launched the application
    with open("./tmp-stdout.log", "r") as f:
        content = f.read()
        sys.stdout.write(content)

# Same code for while True loop:

Despite solving the stdout issue, a new problem arose related to screen resizing after importing the readline module, which seems to affect the application's ability to adjust to terminal size changes

The resizing problem

My main application makes an import to readline (without even using it). This somehow, breaks the application's resizing capabilities.

If I add the following import statement to the previous code (without using the imported module):

import readline
  • Before resizing:
    image
  • After rezising down (making screen smaller): I lose the first line
    image
  • After resizing up (making the screen bigger): The application doesn't resize:
    image

All I did was add an import readline att the start of the previous code, and it breaks the rezising. I don't even use the module, I simply import it
If I remove the import readline, the resizing works:
image

I can't figure out why this is happening. Please help.

Note: If you have a better idea than launching a threading.Thread and calling subprocess, please do share.

Copy link

We found the following entry in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory

@Textualize Textualize locked and limited conversation to collaborators Apr 30, 2024
@willmcgugan willmcgugan converted this issue into discussion #4465 Apr 30, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant