From 9378d97b751fb42a6f1a0f16204fd1979037a523 Mon Sep 17 00:00:00 2001 From: Ethan Hou Date: Mon, 18 May 2026 15:21:16 +0800 Subject: [PATCH 1/2] fix: Add layout refresher callback to ChatInputTextViewer for dynamic input height adjustments --- .../copilot/eclipse/ui/chat/ActionBar.java | 12 +++++++ .../eclipse/ui/chat/ChatInputTextViewer.java | 31 +++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java index b2be770f..c0845306 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java @@ -216,6 +216,18 @@ public ActionBar(Composite parent, int style, ChatServiceManager chatServiceMana ChatInputTextViewer tv = new ChatInputTextViewer(borderedActionBar, chatServiceManager); tv.setEditable(true); + // Relayout the chat view container so the new ActionBar preferred height is honored when the input grows or + // shrinks (e.g., recalling a long history entry with Up arrow, wrapping a long line, or clearing the input). + // Avoids a brittle fixed-depth parent traversal inside ChatInputTextViewer (see issue #215). + tv.setLayoutRefreshCallback(() -> { + if (ActionBar.this.isDisposed()) { + return; + } + Composite layoutTarget = ActionBar.this.getParent(); + if (layoutTarget != null && !layoutTarget.isDisposed()) { + layoutTarget.layout(true, false); + } + }); tv.addTextListener(new ITextListener() { @Override public void textChanged(TextEvent event) { diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java index 91f47dc0..bff41e40 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java @@ -58,6 +58,8 @@ public class ChatInputTextViewer extends UndoableTextViewer implements PaintList private Color placeholderColor; + private Runnable layoutRefreshCallback; + /** * Constructs a new ChatInputTextViewer. * @@ -77,6 +79,17 @@ public void setSendMessageHandler(Consumer handler) { this.sendMessageHandler = handler; } + /** + * Registers a callback invoked after the input area's preferred height changes, so the owner can relayout the + * enclosing chat view container. This avoids a brittle fixed-depth parent traversal that breaks whenever the input + * area is rewrapped in a new composite (see issue #215). + * + * @param callback the layout-refresh callback; may be {@code null} to clear + */ + public void setLayoutRefreshCallback(Runnable callback) { + this.layoutRefreshCallback = callback; + } + public String getContent() { return this.getDocument().get(); } @@ -188,15 +201,29 @@ private boolean isInsertLineBreakOnly(TextEvent event) { private void refreshHeightLayout() { StyledText tvw = this.getTextWidget(); + if (tvw == null || tvw.isDisposed()) { + return; + } // If the width is not initialized, use SWT.DEFAULT to compute the size // otherwise, swt will think that each line can only have one character. int widthHint = tvw.getSize().x == 0 ? SWT.DEFAULT : tvw.getSize().x; Point size = tvw.computeSize(widthHint, SWT.DEFAULT); GridData gd = (GridData) tvw.getLayoutData(); - gd.heightHint = Math.min(tvw.getLineHeight() * MAX_INPUT_ROWS, size.y); + int newHeightHint = Math.min(tvw.getLineHeight() * MAX_INPUT_ROWS, size.y); + if (gd.heightHint == newHeightHint) { + return; + } + gd.heightHint = newHeightHint; + // Delegate the relayout to the owner (e.g., ActionBar) so the chat view container reserves space for the + // updated input height. Falling back to a local requestLayout() keeps things working when no owner is wired + // up (e.g., in unit tests with a synthetic parent hierarchy). // TODO: An very interesting bug here, if we call layout(true, true), even no changes, // The width of welcome view will become shorter and shorter, may investigate it later - ChatInputTextViewer.this.parent.getParent().getParent().layout(true, false); + if (this.layoutRefreshCallback != null) { + this.layoutRefreshCallback.run(); + } else if (this.parent != null && !this.parent.isDisposed()) { + this.parent.layout(true, false); + } } private void onKeyPressed(KeyEvent e) { From 1b3567e190df46bbdefc5d8675b44b6a14c4a157 Mon Sep 17 00:00:00 2001 From: Ethan Hou Date: Mon, 18 May 2026 15:32:07 +0800 Subject: [PATCH 2/2] Address comments. --- .../com/microsoft/copilot/eclipse/ui/chat/ActionBar.java | 2 ++ .../copilot/eclipse/ui/chat/ChatInputTextViewer.java | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java index c0845306..3cb66e8d 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ActionBar.java @@ -225,6 +225,8 @@ public ActionBar(Composite parent, int style, ChatServiceManager chatServiceMana } Composite layoutTarget = ActionBar.this.getParent(); if (layoutTarget != null && !layoutTarget.isDisposed()) { + // TODO: An very interesting bug here, if we call layout(true, true), even no changes, + // The width of welcome view will become shorter and shorter, may investigate it later layoutTarget.layout(true, false); } }); diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java index bff41e40..adec34dc 100644 --- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java +++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ChatInputTextViewer.java @@ -215,14 +215,9 @@ private void refreshHeightLayout() { } gd.heightHint = newHeightHint; // Delegate the relayout to the owner (e.g., ActionBar) so the chat view container reserves space for the - // updated input height. Falling back to a local requestLayout() keeps things working when no owner is wired - // up (e.g., in unit tests with a synthetic parent hierarchy). - // TODO: An very interesting bug here, if we call layout(true, true), even no changes, - // The width of welcome view will become shorter and shorter, may investigate it later + // updated input height. if (this.layoutRefreshCallback != null) { this.layoutRefreshCallback.run(); - } else if (this.parent != null && !this.parent.isDisposed()) { - this.parent.layout(true, false); } }