1+ import chalk from 'chalk'
12import { Text } from 'ink'
23import { marked } from 'marked'
4+ import { markedTerminal } from 'marked-terminal'
35import { useMemo } from 'react'
46
5- // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
6- const TerminalRenderer = require ( 'marked-terminal' ) . default
7-
87import { theme } from './theme.js'
98
109interface Props {
@@ -13,33 +12,36 @@ interface Props {
1312 color ?: string
1413}
1514
16- // marked-terminal 설정 (marked@12 API)
17- marked . setOptions ( {
18- renderer : new TerminalRenderer ( {
19- // 색상 커스터마이징 (Catppuccin 테마와 조화)
20- code : theme . lavender ,
21- blockquote : theme . muted ,
22- html : theme . muted ,
23- heading : theme . primary ,
24- firstHeading : theme . primary ,
25- hr : theme . surface ,
26- listitem : theme . text ,
27- strong : theme . text ,
28- em : theme . subtext ,
29- codespan : theme . lavender ,
30- del : theme . muted ,
31- link : theme . info ,
32- href : theme . info ,
33- // 추가 옵션
15+ // hex 색상을 chalk 함수로 변환
16+ const hex = ( color : string ) => chalk . hex ( color )
17+
18+ // marked-terminal 설정 (marked v12 새 API)
19+ marked . use (
20+ markedTerminal ( {
21+ // 색상은 chalk 함수로 전달해야 함
22+ code : hex ( theme . lavender ) ,
23+ blockquote : hex ( theme . muted ) ,
24+ html : hex ( theme . muted ) ,
25+ heading : hex ( theme . primary ) . bold ,
26+ firstHeading : hex ( theme . primary ) . bold ,
27+ hr : hex ( theme . surface ) ,
28+ listitem : hex ( theme . text ) ,
29+ paragraph : hex ( theme . text ) ,
30+ // 핵심: strong/em은 반드시 함수여야 함
31+ strong : chalk . bold ,
32+ em : chalk . italic ,
33+ codespan : hex ( theme . lavender ) ,
34+ del : hex ( theme . muted ) . strikethrough ,
35+ link : hex ( theme . info ) ,
36+ href : hex ( theme . info ) . underline ,
37+ // 옵션
3438 showSectionPrefix : false ,
3539 reflowText : true ,
3640 width : 80 ,
37- // 이모지 지원
3841 emoji : true ,
39- // 탭 크기
4042 tab : 2
4143 } )
42- } )
44+ )
4345
4446/**
4547 * Markdown renderer for Ink using marked + marked-terminal
@@ -53,31 +55,15 @@ marked.setOptions({
5355 * - Links [text](url)
5456 * - Horizontal rules (---)
5557 */
56- /**
57- * marked-terminal 후처리: 리스트 내부 인라인 마크다운 수동 처리
58- * marked-terminal이 리스트 아이템 내부의 **bold**, `code` 등을 처리 못하는 버그 우회
59- */
60- function postProcessMarkdown ( text : string ) : string {
61- return (
62- text
63- // **bold** → ANSI bold (\x1b[1m...\x1b[22m)
64- . replace ( / \* \* ( [ ^ * ] + ) \* \* / g, '\x1b[1m$1\x1b[22m' )
65- // `code` → ANSI yellow (\x1b[33m...\x1b[39m)
66- . replace ( / ` ( [ ^ ` ] + ) ` / g, '\x1b[33m$1\x1b[39m' )
67- )
68- }
69-
7058export function MarkdownText ( { children, color } : Props ) {
7159 const rendered = useMemo ( ( ) => {
7260 if ( ! children ) return ''
7361
7462 try {
7563 // marked-terminal은 ANSI escape code가 포함된 문자열을 반환
7664 const result = marked . parse ( children , { async : false } ) as string
77- // 후처리: 리스트 내부 인라인 마크다운 처리
78- const processed = postProcessMarkdown ( result )
7965 // 끝의 불필요한 줄바꿈 제거
80- return processed . replace ( / \n + $ / , '' )
66+ return result . replace ( / \n + $ / , '' )
8167 } catch {
8268 // 파싱 실패 시 원본 반환
8369 return children
0 commit comments