Skip to content

Commit 3520b75

Browse files
committed
Merge branch 'main' into extend-terminal-guesswork
2 parents 4e11bb3 + 5b09e7b commit 3520b75

8 files changed

Lines changed: 197 additions & 97 deletions

File tree

poetry.lock

Lines changed: 159 additions & 89 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "textual-dev"
3-
version = "1.2.0"
3+
version = "1.2.1"
44
homepage = "https://github.com/Textualize/textual-dev"
55
description = "Development tools for working with Textual"
66
authors = ["Will McGugan <will@textualize.io>", "Dave Pearson <dave@textualize.io>"]
@@ -28,7 +28,7 @@ include = [
2828

2929
[tool.poetry.dependencies]
3030
python = "^3.7"
31-
textual = ">=0.33.0"
31+
textual = ">=0.36.0"
3232
aiohttp = ">=3.8.1"
3333
click = ">=8.1.2"
3434
msgpack = ">=1.0.3"

src/textual_dev/cli.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import click
77
from importlib_metadata import version
8-
from textual.constants import DEVTOOLS_PORT
8+
from textual.constants import DEVTOOLS_HOST, DEVTOOLS_PORT
99

1010
from .tools.run import exec_command, run_app
1111

@@ -91,13 +91,21 @@ def _pre_run_warnings() -> None:
9191
)
9292
@click.argument("import_name", metavar="FILE or FILE:APP")
9393
@click.option("--dev", "dev", help="Enable development mode.", is_flag=True)
94+
@click.option(
95+
"--host",
96+
"host",
97+
type=str,
98+
default=None,
99+
metavar="HOST",
100+
help=f"Host where the development console is running. Defaults to {DEVTOOLS_HOST}.",
101+
)
94102
@click.option(
95103
"--port",
96104
"port",
97105
type=int,
98106
default=None,
99107
metavar="PORT",
100-
help=f"Port to use for the development mode console. Defaults to {DEVTOOLS_PORT}.",
108+
help=f"Port where the development console is running. Defaults to {DEVTOOLS_PORT}.",
101109
)
102110
@click.option(
103111
"--press", "press", default=None, help="Comma separated keys to simulate press."
@@ -131,6 +139,7 @@ def _pre_run_warnings() -> None:
131139
def _run_app(
132140
import_name: str,
133141
dev: bool,
142+
host: str | None,
134143
port: int | None,
135144
press: str | None,
136145
screenshot: int | None,
@@ -176,6 +185,8 @@ def _run_app(
176185
features.add("devtools")
177186

178187
environment["TEXTUAL"] = ",".join(sorted(features))
188+
if host is not None:
189+
environment["TEXTUAL_DEVTOOLS_HOST"] = str(host)
179190
if port is not None:
180191
environment["TEXTUAL_DEVTOOLS_PORT"] = str(port)
181192
if press is not None:

src/textual_dev/client.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from textual._log import LogGroup, LogVerbosity
1818
from textual.constants import DEVTOOLS_PORT
1919

20+
READY_TIMEOUT = 0.5
2021
WEBSOCKET_CONNECT_TIMEOUT = 3
2122
LOG_QUEUE_MAXSIZE = 512
2223

@@ -102,6 +103,7 @@ def __init__(self, host: str = "127.0.0.1", port: int | None = None) -> None:
102103
self.log_queue: Queue[str | bytes | Type[ClientShutdown]] | None = None
103104
self.spillover: int = 0
104105
self.verbose: bool = False
106+
self._ready_event: asyncio.Event = asyncio.Event()
105107

106108
async def connect(self) -> None:
107109
"""Connect to the devtools server.
@@ -139,6 +141,7 @@ async def update_console() -> None:
139141
self.console.width = payload["width"]
140142
self.console.height = payload["height"]
141143
self.verbose = payload.get("verbose", False)
144+
self._ready_event.set()
142145

143146
async def send_queued_logs():
144147
"""Coroutine function which is scheduled as a Task, which consumes
@@ -156,9 +159,18 @@ async def send_queued_logs():
156159
await websocket.send_bytes(log)
157160
log_queue.task_done()
158161

162+
async def server_info_received() -> None:
163+
"""Wait for the first server info message to be received and handled."""
164+
try:
165+
await asyncio.wait_for(self._ready_event.wait(), timeout=READY_TIMEOUT)
166+
except asyncio.TimeoutError:
167+
return
168+
159169
self.log_queue_task = asyncio.create_task(send_queued_logs())
160170
self.update_console_task = asyncio.create_task(update_console())
161171

172+
await server_info_received()
173+
162174
async def _stop_log_queue_processing(self) -> None:
163175
"""Schedule end of processing of the log queue, meaning that any messages a
164176
user logs will be added to the queue, but not consumed and sent to

src/textual_dev/previews/borders.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from typing import cast
2+
23
from textual.app import App, ComposeResult
34
from textual.containers import Vertical
45
from textual.css.constants import VALID_BORDER

src/textual_dev/previews/easing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
from rich.console import RenderableType
44
from textual._easing import EASING
55
from textual.app import App, ComposeResult
6-
from textual_dev.previews.borders import TEXT
76
from textual.containers import Horizontal, Vertical
87
from textual.reactive import reactive, var
98
from textual.scrollbar import ScrollBarRender
109
from textual.widget import Widget
1110
from textual.widgets import Button, Footer, Input, Label
1211

12+
from textual_dev.previews.borders import TEXT
13+
1314
VIRTUAL_SIZE = 100
1415
WINDOW_SIZE = 10
1516
START_POSITION = 0.0

src/textual_dev/redirect_output.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from __future__ import annotations
22

33
import inspect
4+
from types import FrameType
45
from typing import TYPE_CHECKING, cast
56

67
from textual._log import LogGroup, LogVerbosity
8+
79
from .client import DevtoolsLog
810

911
if TYPE_CHECKING:
@@ -27,19 +29,20 @@ def __init__(self, devtools: DevtoolsClient) -> None:
2729
self.devtools = devtools
2830
self._buffer: list[DevtoolsLog] = []
2931

30-
def write(self, string: str) -> None:
32+
def write(self, string: str, current_frame: FrameType | None = None) -> None:
3133
"""Write the log string to the internal buffer. If the string contains
3234
a newline character `\n`, the whole string will be buffered and then the
3335
buffer will be flushed immediately after.
3436
3537
Args:
3638
string: The string to write to the buffer.
39+
current_frame: The optional frame of the caller, used in logging.
3740
"""
3841

3942
if not self.devtools.is_connected:
4043
return
4144

42-
current_frame = inspect.currentframe()
45+
current_frame = current_frame or inspect.currentframe()
4346
assert current_frame is not None
4447
previous_frame = current_frame.f_back
4548
assert previous_frame is not None

src/textual_dev/tools/diagnose.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ def _console() -> None:
160160

161161
def diagnose() -> None:
162162
"""Print information about Textual and its environment to help diagnose problems."""
163-
print("<!-- This is valid Markdown, do not quote! -->")
163+
print(
164+
"<!-- This is valid Markdown, please paste the following directly in to a GitHub issue -->"
165+
)
164166
print("# Textual Diagnostics")
165167
print()
166168
_versions()

0 commit comments

Comments
 (0)