-
Notifications
You must be signed in to change notification settings - Fork 843
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
rich's print module breaks nearby scrollable boxes. #3921
Comments
Could you provide more detail about what you're printing here? If you're able to provide a MRE so someone can reproduce the issue, it would really help find a solution. |
when you have the following code from rich import print then in a work thread (or any function/button event) you print anything that has COLORED text, your boxes will break. Here is all my code to better explain (I'm very bad at explaining) import time
from textual.app import App, ComposeResult
from textual.containers import Container, Horizontal, ScrollableContainer
from textual.widgets import Footer, Header, Button, Static, Placeholder, Log, Pretty
from textual.widget import Widget
from textual.events import Print
from textual.reactive import Reactive
from textual.binding import Binding
from rich.syntax import Syntax
from rich import print
from textual import work
from dataclasses import dataclass
@dataclass
class settings:
debug: bool = False
class Code_Console1(Static):
code: str = Reactive("test")
def compose(self) -> ComposeResult:
yield Log()
class Code_Console2(Static):
def compose(self) -> ComposeResult:
with open("tests\\test_1.bat", "r") as f:
code = f.read()
yield Static(
Syntax(code, "bat", theme="monokai", line_numbers=True, word_wrap=True),
)
class Obfuscator(Static):
def compose(self) -> ComposeResult:
yield Button("Obfuscate", id="start", variant="success")
class SomalifuscatorV2(App):
CSS_PATH = "style.tcss"
BINDINGS = [Binding("d", "toggle_debug", "Toggle Debug")]
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "start":
print("Obfuscating")
else:
print("Unknown button pressed!")
def compose(self) -> ComposeResult:
yield Header()
yield Footer()
with Container(id="MainContainer"):
yield Horizontal(
ScrollableContainer(Code_Console1()),
ScrollableContainer(Code_Console2()),
)
yield Obfuscator()
def action_toggle_debug(self) -> None:
settings.debug = not settings.debug
print(f"Debug is now {settings.debug}")
def on_print(self, event: Print) -> None:
self.query_one(Log).write(event.text)
def on_mount(self) -> None:
self.run_my_worker()
@work(thread=True)
def run_my_worker(self):
self.begin_capture_print(self, True, True)
if __name__ == "__main__":
app = SomalifuscatorV2()
app.run() if you need anything else please let me know and thank you for the help. |
Here is a video of what I mean Desktop.2023.12.22.-.19.29.59.01.mp4 |
You will be capturing the escape sequences from Rich, which are going to throw off the width calculations. The solution would be to print |
from_ansi returns a Text object which can't be written into Log. Also wouldn't it remove the colors? If it does, is there a way I can keep the colors using something else such as a text area, etc? |
Something like TextArea would be perfect but it doesn't seem to be supported anymore. |
I'd recommend having a look at the FAQ (https://textual.textualize.io/FAQ/#no-widget-called-textlog) and perhaps another read through the docs. There's a number of things I'm afraid I don't understand about your code above - perhaps there's some important context missing. Why do you need to capture print statements, as it looks like these aren't coming from 'outside'...? |
I'm capturing the print statements to redirect all terminal "terminal" text into the box to make it look cool. If you have any other questions let me know. |
So it is purely for style, am I reading that correctly? There's not an external process you need to capture print from? In any case, hopefully from the docs/FAQ you'll have discovered the RichLog which can write more than just text. |
bruh... that is exactly what I was looking for thank you. Also no, I'm not looking for any external processes or anything I'm doing all of this just for aesthetic |
Don't forget to star the repository! Follow @textualizeio for Textual updates. |
Glad to have helped. In that case, you really don't need rich print at all, rather something like this? from dataclasses import dataclass
from rich.syntax import Syntax
from rich.text import Text
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.containers import Center, Horizontal, ScrollableContainer
from textual.widgets import Button, Footer, Header, RichLog, Static
@dataclass
class settings:
debug: bool = False
MOCK_BAT = """\
@echo off
title This is your first batch script!
echo Welcome to batch scripting!
pause\
"""
class CodeDisplay(ScrollableContainer):
# Unfortunately I don't think there's currently a read-only mode for the
# TextArea widget, but when that's released you could replace this!
def compose(self) -> ComposeResult:
yield Static(
Syntax(
MOCK_BAT,
"bat",
theme="monokai",
line_numbers=True,
word_wrap=True,
)
)
class SomalifuscatorV2(App):
BINDINGS = [Binding("d", "toggle_debug", "Toggle Debug")]
CSS = """
CodeDisplay {
border: solid $primary-background-lighten-3;
overflow: scroll scroll;
}
CodeDisplay:focus {
border: solid $accent;
}
RichLog {
border: solid $primary-background-lighten-3;
overflow: scroll scroll;
}
RichLog:focus {
border: solid $accent;
}
Center {
padding: 2;
}
"""
def compose(self) -> ComposeResult:
yield Header()
with Horizontal():
yield RichLog() # logs are already scrollable
yield CodeDisplay()
with Center():
yield Button("Obfuscate", variant="success")
yield Footer()
def on_mount(self) -> None:
self.query_one(RichLog).border_title = "Log"
self.query_one(CodeDisplay).border_title = "Code"
self.query_one(Button).focus()
def on_button_pressed(self, _: Button.Pressed) -> None:
self.query_one(RichLog).write("Obfuscating...")
def action_toggle_debug(self) -> None:
settings.debug = not settings.debug
color = "red" if not settings.debug else "green"
debug_msg = Text.from_markup(
f"Debug is now [{color} italic]{settings.debug}[/]"
)
self.query_one(RichLog).write(debug_msg)
if __name__ == "__main__":
app = SomalifuscatorV2()
app.run() |
@TomJGooding Random question but does the rich progress count as a renderable? Or do I have to use the textual progress bar instead? |
You don't need to log from Rich at all. Just use what is provided by Textual. |
Textual Diagnostics
Versions
Python
Operating System
Terminal
Rich Console options
SOMETIMES it breaks just by adding text to the LOG box on the left side, it will also ALWAYS break when resizing the screen.
The text from the LOG box is being added from a on_print function. The following code is provided below.
If you need any more of the code for context just let me know I can send the rest.
The text was updated successfully, but these errors were encountered: