Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private Constants() {
public static final String CHAT_CHANNEL = "chatProgress";
public static final String AUTO_SHOW_WHAT_IS_NEW = "autoShowWhatsNew";
public static final String AUTO_BREAKPOINT_RESPONSE = "autoBreakpointResponse";
public static final String AUTO_SCROLL_TO_NEW_DIALOG = "autoScrollToNewDialog";
public static final String GITHUB_JOBS_VIEW_ID = "com.microsoft.copilot.eclipse.ui.jobs.JobsView";
public static final String SUPPRESS_TERMINAL_DEPENDENCY_DIALOG = "suppressTerminalDependencyDialog";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.ui.PlatformUI;
import org.osgi.service.event.EventHandler;

import com.microsoft.copilot.eclipse.core.Constants;
import com.microsoft.copilot.eclipse.core.CopilotCore;
import com.microsoft.copilot.eclipse.core.chat.ConfirmationContent;
import com.microsoft.copilot.eclipse.core.events.CopilotEventConstants;
Expand All @@ -36,6 +37,7 @@
import com.microsoft.copilot.eclipse.core.persistence.CopilotTurnData.EditAgentRoundData;
import com.microsoft.copilot.eclipse.core.persistence.CopilotTurnData.ReplyData;
import com.microsoft.copilot.eclipse.core.persistence.CopilotTurnData.ToolCallData;
import com.microsoft.copilot.eclipse.ui.CopilotUi;
import com.microsoft.copilot.eclipse.ui.chat.services.AvatarService;
import com.microsoft.copilot.eclipse.ui.chat.services.ChatServiceManager;
import com.microsoft.copilot.eclipse.ui.utils.SwtUtils;
Expand Down Expand Up @@ -627,9 +629,24 @@ protected void createWarnDialog(String message, int code, String modelProviderNa
&& quotaStatus.premiumInteractions().overagePermitted();
canUpgradePlan = quotaStatus.canUpgradePlan();
}
new WarnWidget(this, SWT.NONE, displayMessage, planForActions, overageEnabled, canUpgradePlan);
WarnWidget warnWidget = new WarnWidget(this, SWT.NONE, displayMessage, planForActions, overageEnabled, canUpgradePlan);
ensureFooterAtBottom();
requestLayout();
// Ensure the chat content viewer scrolls to show the newly created warning banner. Walk up the composite hierarchy
// to find a ChatContentViewer and request scrolling. Use async exec because layout needs to complete first.
SwtUtils.invokeOnDisplayThreadAsync(() -> {
if (!isAutoScrollPromptsEnabled()) {
return;
}
ChatContentViewer viewer = SwtUtils.findParentOfType(this.getParent(), ChatContentViewer.class);
if (viewer != null) {
viewer.refreshScrollerLayout();
if (warnWidget != null && !warnWidget.isDisposed()) {
viewer.showControl(warnWidget);
}
}

}, this.getParent());
}

/**
Expand Down Expand Up @@ -666,6 +683,23 @@ public CompletableFuture<LanguageModelToolConfirmationResult> requestToolExecuti

this.getParent().requestLayout();

// Ensure the chat content viewer scrolls to show the newly created confirmation
// dialog. Walk up the composite hierarchy to find a ChatContentViewer
// and request scrolling. Use async exec because layout needs to complete first.
SwtUtils.invokeOnDisplayThreadAsync(() -> {
if (!isAutoScrollPromptsEnabled()) {
return;
}
ChatContentViewer viewer = SwtUtils.findParentOfType(this.getParent(), ChatContentViewer.class);
if (viewer != null) {
viewer.refreshScrollerLayout();
if (this.confirmDialog != null && !this.confirmDialog.isDisposed()) {
viewer.showControl(this.confirmDialog);
}
}

}, this.getParent());

return toolConfirmationFuture;
}

Expand Down Expand Up @@ -710,4 +744,8 @@ public void dispose() {
this.cancelMsgEventHandler = null;
}
}

public static boolean isAutoScrollPromptsEnabled() {
return CopilotUi.getPlugin().getPreferenceStore().getBoolean(Constants.AUTO_SCROLL_TO_NEW_DIALOG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,9 @@ public BaseTurnWidget getTurnWidget(String turnId) {
private void renderWarnMessageWithUpgradePlanButton(String errorMessage, int code, String modelProviderName) {
latestTurnWidget.createWarnDialog(errorMessage, code, modelProviderName);
refreshScrollerLayout();
scrollToLatestUserTurn();
if (!BaseTurnWidget.isAutoScrollPromptsEnabled()) {
scrollToLatestUserTurn();
}
}

/**
Expand All @@ -433,7 +435,19 @@ public void renderErrorMessage(String errorMessage) {
}
this.errorWidget = new ErrorWidget(cmpContent, SWT.BOTTOM, errorMessage);
refreshScrollerLayout();
scrollToLatestUserTurn();
// Ensure the chat content viewer scrolls to show the newly created error banner.
SwtUtils.invokeOnDisplayThreadAsync(() -> {
if (!BaseTurnWidget.isAutoScrollPromptsEnabled()) {
return;
}
if (this.errorWidget != null && !this.errorWidget.isDisposed()) {
this.showControl(this.errorWidget);
}
}, this.getParent());

if (!BaseTurnWidget.isAutoScrollPromptsEnabled()) {
scrollToLatestUserTurn();
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public void initializeDefaultPreferences() {
pref.setDefault(Constants.CUSTOM_INSTRUCTIONS_CHAT_LOAD_SCOPE,
CustomInstructionsChatLoadScope.DEFAULT_VALUE.getValue());
pref.setDefault(Constants.AUTO_BREAKPOINT_RESPONSE, false);
pref.setDefault(Constants.AUTO_SCROLL_TO_NEW_DIALOG, true);
pref.setDefault(Constants.MCP, """
{
"servers": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ public void createFieldEditors() {
showWhatsNewField.getDescriptionControl(whatsNewComposite)
.setToolTipText(Messages.preferences_page_enable_whats_new_tooltip);
addField(showWhatsNewField);

// Chat group
Group grpChat = new Group(parent, SWT.NONE);
grpChat.setLayout(gl);
gdf.applyTo(grpChat);
grpChat.setText(Messages.preferences_page_auto_scroll_group);

Composite ctnAutoScroll = new Composite(grpChat, SWT.NONE);
ctnAutoScroll.setLayout(gl);
BooleanFieldEditor bfeAutoScroll = new BooleanFieldEditor(Constants.AUTO_SCROLL_TO_NEW_DIALOG,
Messages.preferences_page_auto_scroll_to_new_dialog, ctnAutoScroll);
bfeAutoScroll.getDescriptionControl(ctnAutoScroll)
.setToolTipText(Messages.preferences_page_auto_scroll_to_new_dialog_tooltip);
addField(bfeAutoScroll);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public class Messages extends NLS {
public static String preferences_page_whats_new_settings;
public static String preferences_page_enable_whats_new;
public static String preferences_page_enable_whats_new_tooltip;

public static String preferences_page_auto_scroll_group;
public static String preferences_page_auto_scroll_to_new_dialog;
public static String preferences_page_auto_scroll_to_new_dialog_tooltip;
public static String preferences_page_github_enterprise;
public static String preferences_page_watched_files;
public static String preferences_page_watched_files_note_content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ preferences_page_enable_strict_ssl= Enable Strict SSL
preferences_page_whats_new_settings= What's New
preferences_page_enable_whats_new= Always display the 'What's New' dialog after GitHub Copilot updates.
preferences_page_enable_whats_new_tooltip= Enable this to automatically display the "What's New" page whenever GitHub Copilot is updated.
preferences_page_auto_scroll_group= Chat
preferences_page_auto_scroll_to_new_dialog= Automatically scroll to new confirmation dialogs/prompts in Chat View.
preferences_page_auto_scroll_to_new_dialog_tooltip= When enabled, the chat view will automatically scroll to show any confirmation dialogs or prompts.
preferences_page_github_enterprise= GitHub Enterprise Authentication Endpoint
preferences_page_mcp= Server Configurations
preferences_page_proxy_config_link= <a>Configure Proxy</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,30 @@ private SwtUtils() {
}

private static final String INLINE_ANNOTATION_COLOR_KEY = "org.eclipse.ui.editors.inlineAnnotationColor";

private static final int DEFAULT_GHOST_TEXT_SCALE = 128;

/**
* Walks up the parent chain of the given control and returns the first ancestor that is an instance of the specified
* type, or {@code null} if none is found.
*
* @param <T> the target type
* @param control the starting control (may be {@code null})
* @param type the class to search for
* @return the first matching ancestor, or {@code null}
*/
@Nullable
public static <T> T findParentOfType(Control control, Class<T> type) {
Comment thread
raghucssit marked this conversation as resolved.
Control current = control;
while (current != null) {
if (type.isInstance(current)) {
return type.cast(current);
}
current = current.getParent();
}
return null;
}

/**
* Invokes the given runnable on the display thread.
*/
Expand Down