- หน้าแรก
- Documentation
- TUI
- เอกสารอ้างอิงการปรับแต่งธีม
เอกสารอ้างอิงการปรับแต่งธีม
เอกสารนี้อธิบายการทำงานของระบบธีมใน coding-agent ในปัจจุบัน ได้แก่ สคีมา การโหลด พฤติกรรมระหว่างรันไทม์ และรูปแบบความล้มเหลว
สิ่งที่ระบบธีมควบคุม
หัวข้อที่มีชื่อว่า “สิ่งที่ระบบธีมควบคุม”ระบบธีมขับเคลื่อน:
- โทเค็นสีพื้นหน้า/พื้นหลังที่ใช้ทั่วทั้ง TUI
- อะแดปเตอร์การจัดรูปแบบ markdown (
getMarkdownTheme()) - อะแดปเตอร์รายการตัวเลือก/ตัวแก้ไข/รายการการตั้งค่า (
getSelectListTheme(),getEditorTheme(),getSettingsListTheme()) - ชุดสัญลักษณ์พรีเซ็ต + การแทนที่สัญลักษณ์ (
unicode,nerd,ascii) - สีการไฮไลต์ไวยากรณ์ที่ใช้โดย native highlighter (
@f5-sales-demo/pi-natives) - สีของเซกเมนต์บรรทัดสถานะ
การดำเนินการหลัก: src/modes/theme/theme.ts
รูปแบบ JSON ของธีม
หัวข้อที่มีชื่อว่า “รูปแบบ JSON ของธีม”ไฟล์ธีมเป็นออบเจ็กต์ JSON ที่ถูกตรวจสอบความถูกต้องกับสคีมารันไทม์ใน theme.ts (ThemeJsonSchema) และสะท้อนโดย src/modes/theme/theme-schema.json
ฟิลด์ระดับบนสุด:
name(จำเป็น)colors(จำเป็น; โทเค็นสีทั้งหมดจำเป็น)vars(ไม่บังคับ; ตัวแปรสีที่ใช้ซ้ำได้)export(ไม่บังคับ; สีสำหรับการส่งออก HTML)symbols(ไม่บังคับ)preset(ไม่บังคับ:unicode | nerd | ascii)overrides(ไม่บังคับ: การแทนที่ค่าคีย์สำหรับSymbolKey)
ค่าสีรองรับ:
- สตริง hex (
"#RRGGBB") - ดัชนีสี 256 สี (
0..255) - สตริงอ้างอิงตัวแปร (แก้ไขผ่าน
vars) - สตริงว่าง (
"") หมายถึงค่าเริ่มต้นของเทอร์มินัล (\x1b[39mfg,\x1b[49mbg)
โทเค็นสีที่จำเป็น (ปัจจุบัน)
หัวข้อที่มีชื่อว่า “โทเค็นสีที่จำเป็น (ปัจจุบัน)”โทเค็นทั้งหมดด้านล่างจำเป็นต้องมีใน colors
ข้อความหลักและขอบ (11)
หัวข้อที่มีชื่อว่า “ข้อความหลักและขอบ (11)”accent, border, borderAccent, borderMuted, success, error, warning, muted, dim, text, thinkingText
บล็อกพื้นหลัง (7)
หัวข้อที่มีชื่อว่า “บล็อกพื้นหลัง (7)”selectedBg, userMessageBg, customMessageBg, toolPendingBg, toolSuccessBg, toolErrorBg, statusLineBg
ข้อความข้อความ/เครื่องมือ (5)
หัวข้อที่มีชื่อว่า “ข้อความข้อความ/เครื่องมือ (5)”userMessageText, customMessageText, customMessageLabel, toolTitle, toolOutput
Markdown (10)
หัวข้อที่มีชื่อว่า “Markdown (10)”mdHeading, mdLink, mdLinkUrl, mdCode, mdCodeBlock, mdCodeBlockBorder, mdQuote, mdQuoteBorder, mdHr, mdListBullet
Tool diff + การไฮไลต์ไวยากรณ์ (12)
หัวข้อที่มีชื่อว่า “Tool diff + การไฮไลต์ไวยากรณ์ (12)”toolDiffAdded, toolDiffRemoved, toolDiffContext,
syntaxComment, syntaxKeyword, syntaxFunction, syntaxVariable, syntaxString, syntaxNumber, syntaxType, syntaxOperator, syntaxPunctuation
ขอบโหมด/การคิด (8)
หัวข้อที่มีชื่อว่า “ขอบโหมด/การคิด (8)”thinkingOff, thinkingMinimal, thinkingLow, thinkingMedium, thinkingHigh, thinkingXhigh, bashMode, pythonMode
สีของเซกเมนต์บรรทัดสถานะ (14)
หัวข้อที่มีชื่อว่า “สีของเซกเมนต์บรรทัดสถานะ (14)”statusLineSep, statusLineModel, statusLinePath, statusLineGitClean, statusLineGitDirty, statusLineContext, statusLineSpend, statusLineStaged, statusLineDirty, statusLineUntracked, statusLineOutput, statusLineCost, statusLineSubagents
โทเค็นที่ไม่บังคับ
หัวข้อที่มีชื่อว่า “โทเค็นที่ไม่บังคับ”ส่วน export (ไม่บังคับ)
หัวข้อที่มีชื่อว่า “ส่วน export (ไม่บังคับ)”ใช้สำหรับตัวช่วยการปรับแต่งธีมการส่งออก HTML:
export.pageBgexport.cardBgexport.infoBg
หากละไว้ โค้ดส่งออกจะดึงค่าเริ่มต้นจากสีธีมที่แก้ไขแล้ว
ส่วน symbols (ไม่บังคับ)
หัวข้อที่มีชื่อว่า “ส่วน symbols (ไม่บังคับ)”symbols.presetกำหนดชุดสัญลักษณ์เริ่มต้นระดับธีมsymbols.overridesสามารถแทนที่ค่าSymbolKeyแต่ละค่าได้
ลำดับความสำคัญรันไทม์:
- การแทนที่
symbolPresetในการตั้งค่า (ถ้ากำหนดไว้) symbols.presetใน theme JSON- ค่าสำรอง
"unicode"
คีย์การแทนที่ที่ไม่ถูกต้องจะถูกละเว้นและบันทึกลอก (logger.debug)
แหล่งธีมในตัว vs ธีมที่กำหนดเอง
หัวข้อที่มีชื่อว่า “แหล่งธีมในตัว vs ธีมที่กำหนดเอง”ลำดับการค้นหาธีม (loadThemeJson):
- ธีมที่ฝังในตัว (
defaults/xcsh-dark.jsonและdefaults/xcsh-light.jsonที่คอมไพล์เป็นdefaultThemes) - ไฟล์ธีมที่กำหนดเอง:
<customThemesDir>/<name>.json
ไดเรกทอรีธีมที่กำหนดเองมาจาก getCustomThemesDir():
- ค่าเริ่มต้น:
~/.xcsh/agent/themes - แทนที่ด้วย
PI_CODING_AGENT_DIR($PI_CODING_AGENT_DIR/themes)
getAvailableThemes() ส่งคืนชื่อที่รวมธีมในตัว + ธีมที่กำหนดเองเรียงลำดับแล้ว โดยธีมในตัวมีความสำคัญก่อนเมื่อชื่อซ้ำกัน
การโหลด การตรวจสอบ และการแก้ไข
หัวข้อที่มีชื่อว่า “การโหลด การตรวจสอบ และการแก้ไข”สำหรับไฟล์ธีมที่กำหนดเอง:
- อ่าน JSON
- แยกวิเคราะห์ JSON
- ตรวจสอบกับ
ThemeJsonSchema - แก้ไขการอ้างอิง
varsแบบเรียกซ้ำ - แปลงค่าที่แก้ไขแล้วเป็น ANSI ตามโหมดความสามารถของเทอร์มินัล
พฤติกรรมการตรวจสอบ:
- โทเค็นสีที่จำเป็นขาดหายไป: ข้อความแสดงข้อผิดพลาดแบบจัดกลุ่มชัดเจน
- ประเภท/ค่าโทเค็นไม่ถูกต้อง: ข้อผิดพลาดการตรวจสอบพร้อมพาธ JSON
- ไม่พบไฟล์ธีม:
Theme not found: <name>
พฤติกรรมการอ้างอิงตัวแปร:
- รองรับการอ้างอิงแบบซ้อน
- ส่งข้อผิดพลาดเมื่อการอ้างอิงตัวแปรขาดหายไป
- ส่งข้อผิดพลาดเมื่อมีการอ้างอิงแบบวงกลม
พฤติกรรมโหมดสีของเทอร์มินัล
หัวข้อที่มีชื่อว่า “พฤติกรรมโหมดสีของเทอร์มินัล”การตรวจจับโหมดสี (detectColorMode):
COLORTERM=truecolor|24bit=> truecolorWT_SESSION=> truecolorTERMในdumb,linux, หรือว่างเปล่า => 256color- มิฉะนั้น => truecolor
พฤติกรรมการแปลง:
- hex ->
Bun.color(..., "ansi-16m" | "ansi-256") - ตัวเลข ->
38;5/48;5ANSI ""-> รีเซ็ต fg/bg เริ่มต้น
พฤติกรรมการสลับระหว่างรันไทม์
หัวข้อที่มีชื่อว่า “พฤติกรรมการสลับระหว่างรันไทม์”ธีมเริ่มต้น (initTheme)
หัวข้อที่มีชื่อว่า “ธีมเริ่มต้น (initTheme)”main.ts เริ่มต้นธีมด้วยการตั้งค่า:
symbolPresetcolorBlindModetheme.darktheme.light
การเลือกสล็อตธีมอัตโนมัติใช้การตรวจจับพื้นหลัง COLORFGBG:
- แยกวิเคราะห์ดัชนีพื้นหลังจาก
COLORFGBG < 8=> สล็อตมืด (theme.dark)>= 8=> สล็อตสว่าง (theme.light)- การแยกวิเคราะห์ล้มเหลว => สล็อตมืด
ค่าเริ่มต้นปัจจุบันจากสคีมาการตั้งค่า:
theme.dark = "xcsh-dark"theme.light = "xcsh-light"symbolPreset = "unicode"colorBlindMode = false
การสลับโดยตรง (setTheme)
หัวข้อที่มีชื่อว่า “การสลับโดยตรง (setTheme)”- โหลดธีมที่เลือก
- อัปเดต singleton
themeส่วนกลาง - เริ่มต้น watcher ตามต้องการ
- เรียกใช้ callback
onThemeChange
เมื่อล้มเหลว:
- ใช้ธีม
darkในตัวเป็นตัวสำรอง - ส่งคืน
{ success: false, error }
การสลับตัวอย่าง (previewTheme)
หัวข้อที่มีชื่อว่า “การสลับตัวอย่าง (previewTheme)”- ใช้ธีมตัวอย่างชั่วคราวกับ
themeส่วนกลาง - ไม่ เปลี่ยนแปลงการตั้งค่าที่บันทึกไว้ด้วยตัวเอง
- ส่งคืนสำเร็จ/ข้อผิดพลาดโดยไม่มีการแทนที่ fallback
UI การตั้งค่าใช้สิ่งนี้สำหรับการแสดงตัวอย่างแบบสด และกู้คืนธีมก่อนหน้าเมื่อยกเลิก
Watchers และการโหลดซ้ำแบบสด
หัวข้อที่มีชื่อว่า “Watchers และการโหลดซ้ำแบบสด”เมื่อเปิดใช้งาน watcher (setTheme(..., true) / การเริ่มต้นแบบอินเทอร์แอคทีฟ):
- ดูเฉพาะพาธไฟล์ที่กำหนดเอง
<customThemesDir>/<currentTheme>.json - ธีมในตัวแทบไม่ถูกดู
- ไฟล์
change: พยายามโหลดซ้ำ (debounced) - ไฟล์
rename/ลบ: ใช้darkเป็นตัวสำรอง ปิด watcher
โหมดอัตโนมัติยังติดตั้ง listener SIGWINCH และสามารถประเมินการแมปสล็อตมืด/สว่างใหม่เมื่อสถานะเทอร์มินัลเปลี่ยนแปลง
พฤติกรรมโหมดตาบอดสี
หัวข้อที่มีชื่อว่า “พฤติกรรมโหมดตาบอดสี”colorBlindMode เปลี่ยนเพียงหนึ่งโทเค็นระหว่างรันไทม์:
toolDiffAddedถูกปรับด้วย HSV (เขียวเปลี่ยนไปทางน้ำเงิน)- การปรับใช้เฉพาะเมื่อค่าที่แก้ไขแล้วเป็นสตริง hex
โทเค็นอื่นไม่เปลี่ยนแปลง
ตำแหน่งที่บันทึกการตั้งค่าธีม
หัวข้อที่มีชื่อว่า “ตำแหน่งที่บันทึกการตั้งค่าธีม”การตั้งค่าที่เกี่ยวข้องกับธีมถูกบันทึกโดย Settings ไปยัง YAML การกำหนดค่าส่วนกลาง:
- พาธ:
<agentDir>/config.yml - ไดเรกทอรี agent เริ่มต้น:
~/.xcsh/agent - ไฟล์เริ่มต้นที่มีผล:
~/.xcsh/agent/config.yml
คีย์ที่บันทึก:
theme.darktheme.lightsymbolPresetcolorBlindMode
มีการย้ายข้อมูลเดิม: theme: "name" แบบแบนเดิมถูกย้ายไปเป็น theme.dark หรือ theme.light แบบซ้อนตามการตรวจจับความสว่าง
การสร้างธีมที่กำหนดเอง (เชิงปฏิบัติ)
หัวข้อที่มีชื่อว่า “การสร้างธีมที่กำหนดเอง (เชิงปฏิบัติ)”- สร้างไฟล์ในไดเรกทอรีธีมที่กำหนดเอง เช่น
~/.xcsh/agent/themes/my-theme.json - รวม
name,varsที่ไม่บังคับ และโทเค็นcolorsทั้งหมดที่จำเป็น - รวม
symbolsและexportตามต้องการ - เลือกธีมในการตั้งค่า (
Display -> Dark themeหรือDisplay -> Light theme) ขึ้นอยู่กับสล็อตอัตโนมัติที่ต้องการ
โครงสร้างขั้นต่ำ ทุกคีย์ใน colors จำเป็น — ตัวตรวจสอบรันไทม์
(additionalProperties: false) ปฏิเสธทั้งคีย์ที่ขาดหายไปและคีย์ที่ไม่รู้จัก
สำหรับการดำเนินการอ้างอิงที่จัดส่งแล้ว ดูที่
packages/coding-agent/src/modes/theme/defaults/xcsh-dark.json
และ xcsh-light.json
บรรทัดสถานะมีระบบสีสองแบบคู่ขนานที่บันทึกไว้ในปัญหา #242:
- สีข้อความ hex (
statusLinePath,statusLineGitClean,statusLineGitDirty,statusLineStaged,statusLineDirty,statusLineUntracked) ขับเคลื่อนการเรนเดอร์แบบไม่ใช้ powerline - ดัชนีพาเลตต์สี 256 สี (
statusLine<Segment>Bg/statusLine<Segment>Fg) ขับเคลื่อนการเติม powerline segment เป็นอิสระจากคีย์ hex ด้านบน — ทั้งสองต้องถูกกำหนด
{ "name": "my-theme", "vars": { "accent": "#7aa2f7", "muted": 244 }, "colors": { "accent": "accent", "chromeAccent": "accent", "spinnerAccent": "accent", "contentAccent": "muted", "border": "#4c566a", "borderAccent": "accent", "borderMuted": "muted", "success": "#9ece6a", "error": "#f7768e", "warning": "#e0af68", "muted": "muted", "dim": 240, "gutterSuccess": "#7dcfff", "gutterWarning": "#e0af68", "text": "", "thinkingText": "muted",
"selectedBg": "#2a2f45", "userMessageBg": "#1f2335", "userMessageText": "", "customMessageBg": "#24283b", "customMessageText": "", "customMessageLabel": "accent", "toolPendingBg": "#1f2335", "toolSuccessBg": "#1f2d2a", "toolErrorBg": "#2d1f2a", "toolTitle": "", "toolOutput": "muted",
"mdHeading": "accent", "mdLink": "accent", "mdLinkUrl": "muted", "mdCode": "#c0caf5", "mdCodeBlock": "#c0caf5", "mdCodeBlockBorder": "muted", "mdQuote": "muted", "mdQuoteBorder": "muted", "mdHr": "muted", "mdListBullet": "accent",
"toolDiffAdded": "#9ece6a", "toolDiffRemoved": "#f7768e", "toolDiffContext": "muted",
"syntaxComment": "#565f89", "syntaxKeyword": "#bb9af7", "syntaxFunction": "#7aa2f7", "syntaxVariable": "#c0caf5", "syntaxString": "#9ece6a", "syntaxNumber": "#ff9e64", "syntaxType": "#2ac3de", "syntaxOperator": "#89ddff", "syntaxPunctuation": "#9aa5ce", "syntaxControl": "#bb9af7",
"thinkingOff": 240, "thinkingMinimal": 244, "thinkingLow": "#7aa2f7", "thinkingMedium": "#2ac3de", "thinkingHigh": "#bb9af7", "thinkingXhigh": "#f7768e",
"bashMode": "#2ac3de", "pythonMode": "#bb9af7",
"statusLineBg": "#16161e", "statusLineSep": 240, "statusLineModel": "#bb9af7", "statusLinePath": "#7aa2f7", "statusLineGitClean": "#9ece6a", "statusLineGitDirty": "#e0af68", "statusLineContext": "#2ac3de", "statusLineSpend": "#7dcfff", "statusLineStaged": "#9ece6a", "statusLineDirty": "#e0af68", "statusLineUntracked": "#f7768e", "statusLineOutput": "#c0caf5", "statusLineCost": "#ff9e64", "statusLineSubagents": "#bb9af7",
"statusLineOsIconBg": 7, "statusLineOsIconFg": 232, "statusLinePathBg": 4, "statusLinePathFg": 254, "statusLineGitCleanBg": 2, "statusLineGitCleanFg": 0, "statusLineGitDirtyBg": 3, "statusLineGitDirtyFg": 0, "statusLineGitStagedBg": 64, "statusLineGitStagedFg": 0, "statusLineGitUntrackedBg": 39, "statusLineGitUntrackedFg": 0, "statusLineGitConflictBg": 1, "statusLineGitConflictFg": 7, "statusLinePlanModeBg": 236, "statusLinePlanModeFg": 117, "statusLineProfileXcshBg": "accent", "statusLineProfileXcshFg": 231 }}การทดสอบธีมที่กำหนดเอง
หัวข้อที่มีชื่อว่า “การทดสอบธีมที่กำหนดเอง”ใช้ขั้นตอนนี้:
- เริ่มโหมดอินเทอร์แอคทีฟ (เปิดใช้งาน watcher ตั้งแต่เริ่มต้น)
- เปิดการตั้งค่าและดูตัวอย่างค่าธีม (สด
previewTheme) - สำหรับไฟล์ธีมที่กำหนดเอง ให้แก้ไข JSON ขณะรันและยืนยันการโหลดซ้ำอัตโนมัติเมื่อบันทึก
- ทดสอบพื้นผิวสำคัญ:
- การเรนเดอร์ markdown
- บล็อก tool (pending/success/error)
- การเรนเดอร์ diff (added/removed/context)
- ความอ่านออกได้ของบรรทัดสถานะ
- การเปลี่ยนแปลงขอบระดับการคิด
- สีขอบโหมด bash/python
- ตรวจสอบชุดสัญลักษณ์ทั้งสองหากธีมของคุณขึ้นอยู่กับความกว้าง/ลักษณะของ glyph
ข้อจำกัดและข้อควรระวังที่แท้จริง
หัวข้อที่มีชื่อว่า “ข้อจำกัดและข้อควรระวังที่แท้จริง”- โทเค็น
colorsทั้งหมดจำเป็นสำหรับธีมที่กำหนดเอง exportและsymbolsไม่บังคับ$schemaใน theme JSON เป็นเพียงข้อมูล; การตรวจสอบรันไทม์ถูกบังคับใช้โดยสคีมา TypeBox ที่คอมไพล์แล้วในโค้ด- ความล้มเหลวของ
setThemeใช้darkเป็นตัวสำรอง; ความล้มเหลวของpreviewThemeไม่แทนที่ธีมปัจจุบัน - ข้อผิดพลาดการโหลดซ้ำของ file watcher จะรักษาธีมที่โหลดอยู่ปัจจุบันจนกว่าการโหลดซ้ำสำเร็จหรือมีการเรียกพาธ fallback