tweak(tui): remove italics from thinking labels (#28737)
This commit is contained in:
@@ -49,6 +49,7 @@ type Theme = TuiThemeCurrent & {
|
|||||||
_hasSelectedListItemText: boolean
|
_hasSelectedListItemText: boolean
|
||||||
}
|
}
|
||||||
type ThemeColor = Exclude<keyof TuiThemeCurrent, "thinkingOpacity">
|
type ThemeColor = Exclude<keyof TuiThemeCurrent, "thinkingOpacity">
|
||||||
|
type SyntaxStyleOverrides = Record<string, { italic?: boolean }>
|
||||||
|
|
||||||
export function selectedForeground(theme: Theme, bg?: RGBA): RGBA {
|
export function selectedForeground(theme: Theme, bg?: RGBA): RGBA {
|
||||||
// If theme explicitly defines selectedListItemText, use it
|
// If theme explicitly defines selectedListItemText, use it
|
||||||
@@ -718,16 +719,18 @@ export function generateSyntax(theme: Theme) {
|
|||||||
return SyntaxStyle.fromTheme(getSyntaxRules(theme))
|
return SyntaxStyle.fromTheme(getSyntaxRules(theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateSubtleSyntax(theme: Theme) {
|
export function generateSubtleSyntax(theme: Theme, overrides?: SyntaxStyleOverrides) {
|
||||||
const rules = getSyntaxRules(theme)
|
const rules = getSyntaxRules(theme)
|
||||||
return SyntaxStyle.fromTheme(
|
return SyntaxStyle.fromTheme(
|
||||||
rules.map((rule) => {
|
rules.map((rule) => {
|
||||||
|
const override = rule.scope.reduce((acc, scope) => ({ ...acc, ...overrides?.[scope] }), {})
|
||||||
if (rule.style.foreground) {
|
if (rule.style.foreground) {
|
||||||
const fg = rule.style.foreground
|
const fg = rule.style.foreground
|
||||||
return {
|
return {
|
||||||
...rule,
|
...rule,
|
||||||
style: {
|
style: {
|
||||||
...rule.style,
|
...rule.style,
|
||||||
|
...override,
|
||||||
foreground: RGBA.fromInts(
|
foreground: RGBA.fromInts(
|
||||||
Math.round(fg.r * 255),
|
Math.round(fg.r * 255),
|
||||||
Math.round(fg.g * 255),
|
Math.round(fg.g * 255),
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { useSync } from "@tui/context/sync"
|
|||||||
import { useEvent } from "@tui/context/event"
|
import { useEvent } from "@tui/context/event"
|
||||||
import { SplitBorder } from "@tui/component/border"
|
import { SplitBorder } from "@tui/component/border"
|
||||||
import { Spinner } from "@tui/component/spinner"
|
import { Spinner } from "@tui/component/spinner"
|
||||||
import { selectedForeground, useTheme } from "@tui/context/theme"
|
import { generateSubtleSyntax, selectedForeground, useTheme } from "@tui/context/theme"
|
||||||
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core"
|
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core"
|
||||||
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
||||||
import type {
|
import type {
|
||||||
@@ -1497,7 +1497,7 @@ const PART_MAPPING = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: AssistantMessage }) {
|
function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: AssistantMessage }) {
|
||||||
const { theme, subtleSyntax } = useTheme()
|
const { theme } = useTheme()
|
||||||
const ctx = use()
|
const ctx = use()
|
||||||
// Collapsed by default in hide mode: a single line throughout, so the
|
// Collapsed by default in hide mode: a single line throughout, so the
|
||||||
// layout never shifts. Click to open the full markdown block, click to close.
|
// layout never shifts. Click to open the full markdown block, click to close.
|
||||||
@@ -1519,6 +1519,8 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
|
|||||||
// blocks. Surface the title both while streaming and after settling so the
|
// blocks. Surface the title both while streaming and after settling so the
|
||||||
// collapsed line carries real signal, not just a duration.
|
// collapsed line carries real signal, not just a duration.
|
||||||
const title = createMemo(() => reasoningTitle(content()))
|
const title = createMemo(() => reasoningTitle(content()))
|
||||||
|
// Keep markdown emphasis for the existing thinking color/concealment, but render it without italics.
|
||||||
|
const syntax = createMemo(() => generateSubtleSyntax(theme, { "markup.italic": { italic: false } }))
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
if (!inMinimal()) return
|
if (!inMinimal()) return
|
||||||
@@ -1535,7 +1537,9 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
|
|||||||
filetype="markdown"
|
filetype="markdown"
|
||||||
drawUnstyledText={false}
|
drawUnstyledText={false}
|
||||||
streaming={true}
|
streaming={true}
|
||||||
syntaxStyle={subtleSyntax()}
|
syntaxStyle={syntax()}
|
||||||
|
// `_Thinking:_`/`_Thought:_` still drives markdown emphasis color and conceals the underscores;
|
||||||
|
// the syntax override above removes only the italic attribute from that emphasis token.
|
||||||
content={(inMinimal() ? "- " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
|
content={(inMinimal() ? "- " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
|
||||||
conceal={ctx.conceal()}
|
conceal={ctx.conceal()}
|
||||||
fg={theme.textMuted}
|
fg={theme.textMuted}
|
||||||
@@ -1563,7 +1567,7 @@ function CollapsedReasoningText(props: { title: string | null; duration: number
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<text fg={theme.warning} wrapMode="none">
|
<text fg={theme.warning} wrapMode="none">
|
||||||
<span style={{ fg: theme.warning, italic: true }}>
|
<span style={{ fg: theme.warning }}>
|
||||||
{props.title ? "+ Thought: " + props.title + " · " + duration() : "+ Thought: " + duration()}
|
{props.title ? "+ Thought: " + props.title + " · " + duration() : "+ Thought: " + duration()}
|
||||||
</span>
|
</span>
|
||||||
</text>
|
</text>
|
||||||
|
|||||||
Reference in New Issue
Block a user