feat(coding-agent): add configurable assistant output padding
Closes #6168
This commit is contained in:
@@ -14,6 +14,7 @@ export class AssistantMessageComponent extends Container {
|
||||
private hideThinkingBlock: boolean;
|
||||
private markdownTheme: MarkdownTheme;
|
||||
private hiddenThinkingLabel: string;
|
||||
private outputPad: number;
|
||||
private lastMessage?: AssistantMessage;
|
||||
private hasToolCalls = false;
|
||||
|
||||
@@ -22,12 +23,14 @@ export class AssistantMessageComponent extends Container {
|
||||
hideThinkingBlock = false,
|
||||
markdownTheme: MarkdownTheme = getMarkdownTheme(),
|
||||
hiddenThinkingLabel = "Thinking...",
|
||||
outputPad = 1,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.hideThinkingBlock = hideThinkingBlock;
|
||||
this.markdownTheme = markdownTheme;
|
||||
this.hiddenThinkingLabel = hiddenThinkingLabel;
|
||||
this.outputPad = outputPad;
|
||||
|
||||
// Container for text/thinking content
|
||||
this.contentContainer = new Container();
|
||||
@@ -59,6 +62,13 @@ export class AssistantMessageComponent extends Container {
|
||||
}
|
||||
}
|
||||
|
||||
setOutputPad(padding: number): void {
|
||||
this.outputPad = padding;
|
||||
if (this.lastMessage) {
|
||||
this.updateContent(this.lastMessage);
|
||||
}
|
||||
}
|
||||
|
||||
override render(width: number): string[] {
|
||||
const lines = super.render(width);
|
||||
if (this.hasToolCalls || lines.length === 0) {
|
||||
@@ -90,7 +100,7 @@ export class AssistantMessageComponent extends Container {
|
||||
if (content.type === "text" && content.text.trim()) {
|
||||
// Assistant text messages with no background - trim the text
|
||||
// Set paddingY=0 to avoid extra spacing before tool executions
|
||||
this.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, this.markdownTheme));
|
||||
this.contentContainer.addChild(new Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme));
|
||||
} else if (content.type === "thinking" && content.thinking.trim()) {
|
||||
// Add spacing only when another visible assistant content block follows.
|
||||
// This avoids a superfluous blank line before separately-rendered tool execution blocks.
|
||||
@@ -109,7 +119,7 @@ export class AssistantMessageComponent extends Container {
|
||||
} else {
|
||||
// Thinking traces in thinkingText color, italic
|
||||
this.contentContainer.addChild(
|
||||
new Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {
|
||||
new Markdown(content.thinking.trim(), this.outputPad, 0, this.markdownTheme, {
|
||||
color: (text: string) => theme.fg("thinkingText", text),
|
||||
italic: true,
|
||||
}),
|
||||
|
||||
@@ -71,6 +71,7 @@ export interface SettingsConfig {
|
||||
treeFilterMode: "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||
showHardwareCursor: boolean;
|
||||
editorPaddingX: number;
|
||||
outputPad: 0 | 1;
|
||||
autocompleteMaxVisible: number;
|
||||
quietStartup: boolean;
|
||||
defaultProjectTrust: DefaultProjectTrust;
|
||||
@@ -100,6 +101,7 @@ export interface SettingsCallbacks {
|
||||
onTreeFilterModeChange: (mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all") => void;
|
||||
onShowHardwareCursorChange: (enabled: boolean) => void;
|
||||
onEditorPaddingXChange: (padding: number) => void;
|
||||
onOutputPadChange: (padding: 0 | 1) => void;
|
||||
onAutocompleteMaxVisibleChange: (maxVisible: number) => void;
|
||||
onQuietStartupChange: (enabled: boolean) => void;
|
||||
onDefaultProjectTrustChange: (defaultProjectTrust: DefaultProjectTrust) => void;
|
||||
@@ -676,9 +678,19 @@ export class SettingsSelectorComponent extends Container {
|
||||
values: ["0", "1", "2", "3"],
|
||||
});
|
||||
|
||||
// Autocomplete max visible toggle (insert after editor-padding)
|
||||
// Output padding toggle (insert after editor-padding)
|
||||
const editorPaddingIndex = items.findIndex((item) => item.id === "editor-padding");
|
||||
items.splice(editorPaddingIndex + 1, 0, {
|
||||
id: "output-padding",
|
||||
label: "Output padding",
|
||||
description: "Horizontal padding for assistant messages and thinking",
|
||||
currentValue: String(config.outputPad),
|
||||
values: ["0", "1"],
|
||||
});
|
||||
|
||||
// Autocomplete max visible toggle (insert after output-padding)
|
||||
const outputPaddingIndex = items.findIndex((item) => item.id === "output-padding");
|
||||
items.splice(outputPaddingIndex + 1, 0, {
|
||||
id: "autocomplete-max-visible",
|
||||
label: "Autocomplete max items",
|
||||
description: "Max visible items in autocomplete dropdown (3-20)",
|
||||
@@ -782,6 +794,9 @@ export class SettingsSelectorComponent extends Container {
|
||||
case "editor-padding":
|
||||
callbacks.onEditorPaddingXChange(parseInt(newValue, 10));
|
||||
break;
|
||||
case "output-padding":
|
||||
callbacks.onOutputPadChange(newValue === "0" ? 0 : 1);
|
||||
break;
|
||||
case "autocomplete-max-visible":
|
||||
callbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));
|
||||
break;
|
||||
|
||||
@@ -321,6 +321,7 @@ export class InteractiveMode {
|
||||
|
||||
// Thinking block visibility state
|
||||
private hideThinkingBlock = false;
|
||||
private outputPad = 1;
|
||||
|
||||
// Skill commands: command name -> skill file path
|
||||
private skillCommands = new Map<string, string>();
|
||||
@@ -429,6 +430,7 @@ export class InteractiveMode {
|
||||
|
||||
// Load hide thinking block setting
|
||||
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
||||
this.outputPad = this.settingsManager.getOutputPad();
|
||||
|
||||
// Register themes from resource loader and initialize
|
||||
setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
|
||||
@@ -1624,6 +1626,7 @@ export class InteractiveMode {
|
||||
this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
|
||||
this.footerDataProvider.setCwd(this.sessionManager.getCwd());
|
||||
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
||||
this.outputPad = this.settingsManager.getOutputPad();
|
||||
this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
|
||||
const clearOnShrink = this.settingsManager.getClearOnShrink();
|
||||
this.ui.setClearOnShrink(clearOnShrink);
|
||||
@@ -2803,6 +2806,7 @@ export class InteractiveMode {
|
||||
this.hideThinkingBlock,
|
||||
this.getMarkdownThemeWithSettings(),
|
||||
this.hiddenThinkingLabel,
|
||||
this.outputPad,
|
||||
);
|
||||
this.streamingMessage = event.message;
|
||||
this.chatContainer.addChild(this.streamingComponent);
|
||||
@@ -3143,6 +3147,7 @@ export class InteractiveMode {
|
||||
this.hideThinkingBlock,
|
||||
this.getMarkdownThemeWithSettings(),
|
||||
this.hiddenThinkingLabel,
|
||||
this.outputPad,
|
||||
);
|
||||
this.chatContainer.addChild(assistantComponent);
|
||||
break;
|
||||
@@ -3959,6 +3964,7 @@ export class InteractiveMode {
|
||||
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
||||
defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),
|
||||
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
||||
outputPad: this.settingsManager.getOutputPad(),
|
||||
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
||||
quietStartup: this.settingsManager.getQuietStartup(),
|
||||
clearOnShrink: this.settingsManager.getClearOnShrink(),
|
||||
@@ -4061,6 +4067,19 @@ export class InteractiveMode {
|
||||
this.editor.setPaddingX(padding);
|
||||
}
|
||||
},
|
||||
onOutputPadChange: (padding) => {
|
||||
this.settingsManager.setOutputPad(padding);
|
||||
this.outputPad = padding;
|
||||
for (const child of this.chatContainer.children) {
|
||||
if (child instanceof AssistantMessageComponent) {
|
||||
child.setOutputPad(padding);
|
||||
}
|
||||
}
|
||||
if (this.streamingComponent) {
|
||||
this.streamingComponent.setOutputPad(padding);
|
||||
}
|
||||
this.ui.requestRender();
|
||||
},
|
||||
onAutocompleteMaxVisibleChange: (maxVisible) => {
|
||||
this.settingsManager.setAutocompleteMaxVisible(maxVisible);
|
||||
this.defaultEditor.setAutocompleteMaxVisible(maxVisible);
|
||||
@@ -5043,6 +5062,7 @@ export class InteractiveMode {
|
||||
return;
|
||||
}
|
||||
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
||||
this.outputPad = this.settingsManager.getOutputPad();
|
||||
this.rebuildChatFromMessages();
|
||||
chatRestoredBeforeSessionStart = true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user