termqt icon indicating copy to clipboard operation
termqt copied to clipboard

The SSH's pty written in your project cannot run properly

Open hanyoukuang opened this issue 7 months ago • 7 comments

The SSH's pty written in your project cannot run properly I wrote a ssh's pty based on your project, but it has problems with misalignment and disappearance of characters when used in editors such as nano. The resize function also fails when the window is full screen. Sometimes the input suddenly freezes Thank you for giving me this excellent project. If you are available, please help me solve these problems.

import sys
import logging
from PyQt6.QtCore import pyqtSignal
from qtpy.QtWidgets import QApplication, QWidget, QHBoxLayout, QScrollBar
from qtpy.QtCore import Qt, QCoreApplication
from qtpy import QT_VERSION
from termqt import Terminal
import asyncio
import threading
import asyncssh


class QTerminal(Terminal):
    def __init__(self, process, h, w, logger):
        super().__init__(h, w, logger=logger)
        self.process = process

    def keyPressEvent(self, event):
        self.process.stdin.write(event.text())


class MyTerminal(QWidget):
    msg = pyqtSignal(str)

    def __init__(self, host, port, username, password):
        super().__init__()
        self.loop = asyncio.new_event_loop()
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.ssh = self.loop.run_until_complete(
            asyncssh.connect(host=host, port=port, username=username, password=password, known_hosts=None))
        self.process = self.loop.run_until_complete(self.ssh.create_process(term_type="xterm"))
        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        handler = logging.StreamHandler()
        formatter = logging.Formatter(
            "[%(asctime)s] > "
            "[%(filename)s:%(lineno)d] %(message)s"
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)

        if QT_VERSION.startswith("5"):
            QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
        # window = QWidget()
        import platform
        self.setWindowTitle("termqt on {}".format(platform.system()))
        layout = QHBoxLayout()
        self.terminal = QTerminal(self.process, 800, 600, logger=logger)
        self.terminal.set_font()
        self.terminal.maximum_line_history = 2000
        scroll = QScrollBar(Qt.Vertical, self.terminal)
        self.terminal.connect_scroll_bar(scroll)

        layout.addWidget(self.terminal)
        layout.addWidget(scroll)
        layout.setSpacing(0)
        self.setLayout(layout)

        auto_wrap_enabled = True

        platform = platform.system()

        if platform in ["Linux", "Darwin"]:
            bin = "/bin/bash"

            from termqt import TerminalPOSIXExecIO

            self.terminal_io = TerminalPOSIXExecIO(
                self.terminal.row_len,
                self.terminal.col_len,
                bin,
                logger=logger
            )
        elif platform == "Windows":
            bin = "cmd"

            from termqt import TerminalWinptyIO

            self.terminal_io = TerminalWinptyIO(
                self.terminal.row_len,
                self.terminal.col_len,
                bin,
                logger=logger
            )

            # it turned out that cmd prefers to handle resize by itself
            # see https://github.com/TerryGeng/termqt/issues/7
            auto_wrap_enabled = True
        else:
            logger.error(f"Not supported platform: {platform}")
            sys.exit(-1)
        self.terminal.enable_auto_wrap(auto_wrap_enabled)
        self.terminal_io.stdout_callback = self.terminal.stdout
        self.terminal.stdin_callback = self.terminal_io.write
        self.terminal.resize_callback = self.terminal_io.resize
        self.terminal_io.spawn()
        threading.Thread(target=self.loop.run_forever, args=()).start()
        threading.Thread(target=self.get_output, args=()).start()

    def get_output(self):
        _ = asyncio.run_coroutine_threadsafe(self.output(), self.loop).result()

    async def output(self):
        while True:
            value = await self.process.stdout.read(4096)
            if len(value) == 0:
                break
            self.msg.emit(value)
            self.terminal.stdout(value.encode())

hanyoukuang avatar Sep 11 '25 00:09 hanyoukuang

I first thank you for your interest in this little project.

If you have gone through the README, you probably would notice my humbleness in it --- termqt was originally designed to run simple TTY programs like ipython, so the handling of complicated features might not work 100% percent as expected. But that's okay. Supporting more features is always one of my goals, and the project itself is moving towards that direction, thanks to the feedback from all the volunteers.

Now, coming to your comments: You are exactly trying to push this project to its limit: running things like nano is not child's play for a terminal emulator to handle.

The SSH's pty written in your project cannot run properly I wrote a ssh's pty based on your project, but it has problems with misalignment and disappearance of characters when used in editors such as nano.

Can you be more specific about when the misalignment and disappearance of characters happen? Can you use script command to record the exact stdin and stdout of nano and termqt and isolate the problematic control sequence?

The resize function also fails when the window is full screen.

This puzzles me: how do you resize if you are already in full screen?

Sometimes the input suddenly freezes

What do you mean by "sometimes"?

I would welcome more constructive bug reports because testing and reproducing bugs is not an easy job. I would appreciate your effort in helping troubleshoot those issues.

TerryGeng avatar Sep 11 '25 02:09 TerryGeng

Also, in case you didn't notice, GitHub keeps the edit history of issues, and it is visible to everyone... Please take immediate security measures if you haven't...

TerryGeng avatar Sep 11 '25 02:09 TerryGeng

I have already changed my password. Thank you for your sincere reminder. I am a freshman and considering switching majors. So I want to do something to prove my computer skills. Although I have won the National Olympiad in Informatics award, I still wrote a fast SFTP transmitter as an additional highlight of my interview. Thank you for your reminder and suggestions, and I will continue to contribute to this project.

hanyoukuang avatar Sep 11 '25 05:09 hanyoukuang

When the program is in a window state, as long as the user clicks the full screen button, the text originally in the terminal will disappear and fall into a black screen, and only by sliding the touchpad can the text content be viewed again. This issue also appears in your start.py example.

hanyoukuang avatar Sep 11 '25 05:09 hanyoukuang

Regarding the issue of character misalignment, you can use the start.by program to open the system's built-in SSH command to login to a host, then use Nano to open multiple lines of text, hold down the backspace key, and you will find that the terminal output does not match your expectations.

hanyoukuang avatar Sep 11 '25 06:09 hanyoukuang

If you want to practice and showcase your programming skills, I think helping with debugging this library is going to be a great experience. The codebase here is not trivial, but also not overly cluttered. While, for all its worth, I was also not a CS major.

For the resizing issue, there might be something wrong with the paint logic, and I would think it is an easy fix.

I can try to have a look at the issues you mentioned in the next two weeks, but my time commitment is not guaranteed.

TerryGeng avatar Sep 11 '25 12:09 TerryGeng

Thank you for your kindness. There is still a long time before switching majors. You don't need to be too hasty, after all, a happy life is more important than anything else. Before using your library, I had already written a program. This is enough to handle transferring majors. I just wanted to add icing on the cake, I didn't expect to receive your reply so quickly. Finally, I would like to express my gratitude again.

hanyoukuang avatar Sep 11 '25 13:09 hanyoukuang