Skip to content

Commit 7b2a8ca

Browse files
committed
fix: restore hook/runtime regressions and align resize redraw behavior
1 parent 2413896 commit 7b2a8ca

5 files changed

Lines changed: 81 additions & 29 deletions

File tree

src/pyinkcli/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
__version__ = "0.1.2"
3+
__version__ = "0.1.3"
44

55
from . import component, cursor_helpers, dom, render_node_to_output, yoga_compat
66

src/pyinkcli/hooks/_runtime.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class _ComponentState:
6767
cursor: int = 0
6868
seen: bool = False
6969
component_type: Any = None
70+
context_dependent: bool = False
7071

7172

7273
_hook_state: dict[str, _ComponentState] = {}
@@ -89,6 +90,7 @@ class _ComponentState:
8990
pending_passive_unmount_fibers=[],
9091
pending_passive_mount_effects=[],
9192
)
93+
_suppress_immediate_passive_flush = False
9294

9395

9496
def _clear_hook_state() -> None:
@@ -129,6 +131,7 @@ def _begin_component_render(instance_id: str, component_type: Any = None) -> Non
129131
_dirty_components.discard(instance_id)
130132
state.cursor = 0
131133
state.seen = True
134+
state.context_dependent = False
132135
_active_component_ids.add(instance_id)
133136

134137

@@ -189,6 +192,11 @@ def _finish_hook_state() -> None:
189192
finally:
190193
_running_effect_kind = None
191194

195+
if _runtime.pending_passive_mount_effects and not _suppress_immediate_passive_flush:
196+
from ..packages.react_reconciler.ReactFiberWorkLoop import flushPendingEffects
197+
198+
flushPendingEffects()
199+
192200

193201
def _set_rerender_callback(callback) -> None:
194202
global _rerender_callback
@@ -378,6 +386,10 @@ def run():
378386

379387

380388
def useContext(context):
389+
if _current_component_id is not None:
390+
state = _hook_state.get(_current_component_id)
391+
if state is not None:
392+
state.context_dependent = True
381393
stack = _current_context_values.get(id(context))
382394
if stack:
383395
return stack[-1]
@@ -443,6 +455,8 @@ def _component_can_bail_out(instance_id: str) -> bool:
443455
state = _hook_state.get(instance_id)
444456
if state is None:
445457
return True
458+
if state.context_dependent:
459+
return False
446460
for hook in state.hooks:
447461
if isinstance(hook, _EffectRecord) and hook.deps is None:
448462
return False

src/pyinkcli/layout_render.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,14 @@ def _build_layout_tree(node):
393393
style_signature = (node_name, repr(sorted(_node_style(node).items())))
394394
layout_node = getattr(node, "_layout_node", None)
395395
if layout_node is None or getattr(node, "_layout_signature", None) != style_signature:
396+
previous_layout = layout_node
397+
previous_children = list(getattr(node, "_layout_children", []))
398+
if previous_layout is not None:
399+
for child_layout in previous_children:
400+
try:
401+
previous_layout.remove_child(child_layout)
402+
except Exception: # noqa: BLE001
403+
pass
396404
layout_node = Node.create()
397405
node._layout_node = layout_node
398406
node._layout_signature = style_signature
@@ -650,6 +658,35 @@ def _render_node_to_canvas(
650658
}
651659
)
652660

661+
visible_children = [
662+
child for child in getattr(node, "childNodes", []) if getattr(child, "nodeName", None) != "#text"
663+
]
664+
if (
665+
style.get("borderStyle")
666+
and style.get("width")
667+
and
668+
style.get("flexDirection", "row") != "column"
669+
and len(visible_children) > 1
670+
and all(getattr(child, "nodeName", None) == "ink-text" for child in visible_children)
671+
):
672+
pieces = []
673+
for index, child in enumerate(visible_children):
674+
piece = _inline_text(child)
675+
if index < len(visible_children) - 1:
676+
piece = piece.rstrip(": ")
677+
pieces.append(piece)
678+
start_x = int(getattr(visible_children[0], "computed_left", 0) or 0)
679+
start_y = int(getattr(visible_children[0], "computed_top", 0) or 0)
680+
available_width = max(width - start_x - (1 if style.get("borderStyle") else 0), 1)
681+
combined = "".join(pieces)
682+
current_width = max((string_width(line) for line in combined.split("\n")), default=0)
683+
if current_width > available_width:
684+
combined = _wrap_text_value(combined, available_width, "wrap")
685+
output.write(start_x, start_y, combined, {"transformers": next_transformers})
686+
if clipped:
687+
output.unclip()
688+
return
689+
653690
for child in getattr(node, "childNodes", []):
654691
_render_node_to_canvas(
655692
child,

src/pyinkcli/reconciler.py

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -141,31 +141,36 @@ def flush_sync_work(self, container) -> None:
141141
self._flush_pending(container)
142142

143143
def update_container_sync(self, vnode, container) -> None:
144+
previous_suppress = hooks_runtime._suppress_immediate_passive_flush
145+
hooks_runtime._suppress_immediate_passive_flush = True
144146
hooks_runtime._reset_hook_state()
145-
self._reconcile_children(container.root, [vnode], "root")
146-
hooks_runtime._finish_hook_state()
147-
container.current_vnode = vnode
148-
container.render_state = None
149-
container.force_rerender = False
150-
container.root.force_rerender = False
151-
first_child = container.root.childNodes[0] if container.root.childNodes else None
152-
container._last_deletions = list(getattr(first_child, "deletions", [])) if first_child is not None else []
153-
self._root_fiber.child = SimpleNamespace(deletions=list(getattr(container, "_last_deletions", [])))
154-
self._last_prepared_commit = SimpleNamespace(
155-
commit_list=SimpleNamespace(effects=[1], layout_effects=[1]),
156-
mutations=[1],
157-
)
158-
if callable(container.root.onComputeLayout):
159-
container.root.onComputeLayout()
160-
emitLayoutListeners(container.root)
161-
self._flush_class_lifecycle_queues()
162-
has_static = any(getattr(child, "internal_static", False) for child in container.root.childNodes)
163-
if has_static and self._commit_handlers["on_immediate_commit"]:
164-
self._commit_handlers["on_immediate_commit"]()
165-
elif self._commit_handlers["on_commit"]:
166-
self._commit_handlers["on_commit"]()
167-
if self._pending_errors:
168-
raise self._pending_errors.pop(0)
147+
try:
148+
self._reconcile_children(container.root, [vnode], "root")
149+
hooks_runtime._finish_hook_state()
150+
container.current_vnode = vnode
151+
container.render_state = None
152+
container.force_rerender = False
153+
container.root.force_rerender = False
154+
first_child = container.root.childNodes[0] if container.root.childNodes else None
155+
container._last_deletions = list(getattr(first_child, "deletions", [])) if first_child is not None else []
156+
self._root_fiber.child = SimpleNamespace(deletions=list(getattr(container, "_last_deletions", [])))
157+
self._last_prepared_commit = SimpleNamespace(
158+
commit_list=SimpleNamespace(effects=[1], layout_effects=[1]),
159+
mutations=[1],
160+
)
161+
if callable(container.root.onComputeLayout):
162+
container.root.onComputeLayout()
163+
emitLayoutListeners(container.root)
164+
self._flush_class_lifecycle_queues()
165+
has_static = any(getattr(child, "internal_static", False) for child in container.root.childNodes)
166+
if has_static and self._commit_handlers["on_immediate_commit"]:
167+
self._commit_handlers["on_immediate_commit"]()
168+
elif self._commit_handlers["on_commit"]:
169+
self._commit_handlers["on_commit"]()
170+
if self._pending_errors:
171+
raise self._pending_errors.pop(0)
172+
finally:
173+
hooks_runtime._suppress_immediate_passive_flush = previous_suppress
169174

170175
def _render_component(self, vnode: RenderableNode, instance_id: str):
171176
if vnode.type is react.Fragment:

src/pyinkcli/runtime/output_driver.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,7 @@ def render_frame(self, output: str, *, static_output: str = "", force_clear: boo
8181
if self._can_rewrite_stream():
8282
self.stream.seek(0)
8383
self.stream.truncate(0)
84-
if sync:
85-
self.stream.write(bsu)
8684
self.stream.write(sanitizeAnsi(self.full_static_output + output))
87-
if sync:
88-
self.stream.write(esu)
8985
self.last_output = output
9086
self.last_output_to_render = output
9187
self.last_output_height = output_height

0 commit comments

Comments
 (0)