@@ -11,6 +11,191 @@ type StyleType = 'atom-one-dark' | 'base16/edge-dark' | 'base16/tomorrow-night'
1111// 定义语言类型
1212type LanguageType = 'english' | 'chinese' ;
1313
14+ // 定义代码前缀显示状态
15+ type PrefixMode = 'with-prefix' | 'without-prefix' ;
16+
17+ // 存储原始代码(带前缀)
18+ const originalCodeCache = new Map < string , string > ( ) ;
19+
20+ // 存储当前前缀模式
21+ let currentPrefixMode : PrefixMode = 'with-prefix' ;
22+
23+ // 从代码中移除Python交互式前缀(保留前缀后的缩进,去除行首多余空格)
24+ function removePythonPrefixes ( code : string ) : string {
25+ // 分割代码为行
26+ const lines = code . split ( '\n' ) ;
27+ // 存储处理后的代码行
28+ const resultLines : string [ ] = [ ] ;
29+
30+ // 处理每一行
31+ for ( const line of lines ) {
32+ // 检查是否是只有前缀的行(需要保留为空行)
33+ const trimmedLine = line . trim ( ) ;
34+ if ( trimmedLine === '>>>' || trimmedLine === '>>>' || trimmedLine === '...' ) {
35+ resultLines . push ( '' ) ; // 保留为空行
36+ continue ;
37+ }
38+
39+ // 检查是否包含前缀
40+ const hasPythonPrefix = line . includes ( '>>>' ) || line . includes ( '>>>' ) || line . includes ( '...' ) ;
41+
42+ // 输出行:前面不含>>>或者...的行
43+ if ( ! hasPythonPrefix ) {
44+ continue ; // 移除输出行
45+ }
46+
47+ // 处理包含前缀的代码行
48+ let cleanedLine = line ;
49+
50+ // 不使用正则表达式处理前缀,保留前缀后的缩进
51+ if ( line . includes ( '>>>' ) && ! line . includes ( '>>>' ) ) {
52+ // 处理 >>> 前缀
53+ const prefixIndex = line . indexOf ( '>>>' ) ;
54+ // 从prefixIndex+3开始,获取前缀后的内容
55+ cleanedLine = line . substring ( prefixIndex + 3 ) ;
56+ } else if ( line . includes ( '>>>' ) ) {
57+ // 处理HTML转义的 >>> 前缀
58+ const prefixIndex = line . indexOf ( '>>>' ) ;
59+ cleanedLine = line . substring ( prefixIndex + 10 ) ; // '>>>'长度为10
60+ } else if ( line . includes ( '...' ) ) {
61+ // 处理 ... 前缀
62+ const prefixIndex = line . indexOf ( '...' ) ;
63+ cleanedLine = line . substring ( prefixIndex + 3 ) ;
64+ }
65+
66+ // 去除行首可能存在的多余空格
67+ if ( cleanedLine . startsWith ( ' ' ) ) {
68+ cleanedLine = cleanedLine . substring ( 1 ) ;
69+ }
70+
71+ // 只添加非空的代码行
72+ if ( cleanedLine . trim ( ) !== '' ) {
73+ resultLines . push ( cleanedLine ) ;
74+ }
75+ }
76+
77+ return resultLines . join ( '\n' ) ;
78+ }
79+
80+ // 为代码块添加复制按钮和处理前缀切换
81+ function setupCodeBlocks ( ) : void {
82+ const codeBlocks = document . querySelectorAll ( 'pre code' ) ;
83+
84+ codeBlocks . forEach ( ( block , index ) => {
85+ // 确保这是一个Python代码块
86+ if ( block . textContent && ( block . className . includes ( 'python' ) || block . textContent . includes ( '>>>' ) ) ) {
87+ const blockId = `code-block-${ index } ` ;
88+ block . id = blockId ;
89+
90+ // 存储原始代码(带前缀)
91+ const originalCode = block . textContent ;
92+ originalCodeCache . set ( blockId , originalCode ) ;
93+
94+ // 获取父元素pre
95+ const preElement = block . parentElement ;
96+ if ( preElement && preElement . tagName === 'PRE' ) {
97+ // 设置pre元素的相对定位,以便按钮可以绝对定位
98+ preElement . style . position = 'relative' ;
99+
100+ // 创建复制按钮
101+ const copyButton = document . createElement ( 'button' ) ;
102+ copyButton . className = 'button is-small mt-2 mr-2 is-white' ;
103+
104+ const buttonIcon = document . createElement ( 'span' ) ;
105+ copyButton . appendChild ( buttonIcon )
106+ buttonIcon . innerHTML = '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><path d="M256 938.666667c-12.8 0-21.333333-4.266667-29.866667-12.8l-128-128c-17.066667-17.066667-17.066667-42.666667 0-59.733334l640-640c17.066667-17.066667 42.666667-17.066667 59.733334 0l128 128c17.066667 17.066667 17.066667 42.666667 0 59.733334l-640 640c-8.533333 8.533333-17.066667 12.8-29.866667 12.8z m-68.266667-170.666667L256 836.266667 836.266667 256 768 187.733333 187.733333 768z" fill="#000000"></path><path d="M768 426.666667c-12.8 0-21.333333-4.266667-29.866667-12.8l-128-128c-17.066667-17.066667-17.066667-42.666667 0-59.733334s42.666667-17.066667 59.733334 0l128 128c17.066667 17.066667 17.066667 42.666667 0 59.733334-8.533333 8.533333-17.066667 12.8-29.866667 12.8zM384 341.333333c-25.6 0-42.666667-17.066667-42.666667-42.666666s-17.066667-42.666667-42.666666-42.666667-42.666667-17.066667-42.666667-42.666667 17.066667-42.666667 42.666667-42.666666 42.666667-17.066667 42.666666-42.666667 17.066667-42.666667 42.666667-42.666667 42.666667 17.066667 42.666667 42.666667 17.066667 42.666667 42.666666 42.666667 42.666667 17.066667 42.666667 42.666666-17.066667 42.666667-42.666667 42.666667-42.666667 17.066667-42.666666 42.666667-17.066667 42.666667-42.666667 42.666666zM810.666667 768c-25.6 0-42.666667-17.066667-42.666667-42.666667s-17.066667-42.666667-42.666667-42.666666-42.666667-17.066667-42.666666-42.666667 17.066667-42.666667 42.666666-42.666667 42.666667-17.066667 42.666667-42.666666 17.066667-42.666667 42.666667-42.666667 42.666667 17.066667 42.666666 42.666667 17.066667 42.666667 42.666667 42.666666 42.666667 17.066667 42.666667 42.666667-17.066667 42.666667-42.666667 42.666667-42.666667 17.066667-42.666667 42.666666-17.066667 42.666667-42.666666 42.666667z" fill="#000000"></path></svg>' ;
107+ buttonIcon . className = 'icon is-small'
108+
109+ copyButton . title = 'Remove prefix' ;
110+ copyButton . style . position = 'absolute' ;
111+ copyButton . style . top = '17px' ;
112+ copyButton . style . right = '20px' ;
113+ copyButton . style . cursor = 'pointer' ;
114+
115+ // 添加点击事件
116+ copyButton . addEventListener ( 'click' , function ( ) {
117+ // 切换当前代码块的前缀显示
118+ toggleCodePrefix ( blockId ) ;
119+ } ) ;
120+
121+ // 添加按钮到pre元素
122+ preElement . appendChild ( copyButton ) ;
123+ }
124+ }
125+ } ) ;
126+
127+ // 应用当前前缀模式
128+ applyPrefixMode ( currentPrefixMode ) ;
129+ }
130+
131+ // 切换单个代码块的前缀显示
132+ function toggleCodePrefix ( blockId : string ) : void {
133+ const codeBlock = document . getElementById ( blockId ) ;
134+ if ( codeBlock && originalCodeCache . has ( blockId ) ) {
135+ const originalCode = originalCodeCache . get ( blockId ) ! ;
136+ const currentText = codeBlock . textContent || '' ;
137+
138+ // 判断当前状态并切换(检查更多可能的前缀模式)
139+ if ( currentText . includes ( '>>>' ) || currentText . includes ( '>>>' ) || currentText . includes ( '...' ) ) {
140+ codeBlock . textContent = removePythonPrefixes ( originalCode ) ;
141+ console . log ( removePythonPrefixes ( originalCode ) )
142+ } else {
143+ codeBlock . textContent = originalCode ;
144+ }
145+
146+
147+ // 确保元素类型正确并重新高亮代码
148+ if ( ( window as any ) . hljs && typeof ( window as any ) . hljs . highlightElement === 'function' && codeBlock instanceof HTMLElement ) {
149+ try {
150+ // 先移除已高亮标记,以便重新高亮
151+ delete codeBlock . dataset . highlighted ;
152+
153+ ( window as any ) . hljs . highlightElement ( codeBlock ) ;
154+ } catch ( error ) {
155+ console . error ( 'Error highlighting code:' , error ) ;
156+ }
157+ }
158+ }
159+ }
160+
161+ // 应用全局前缀模式
162+ function applyPrefixMode ( mode : PrefixMode ) : void {
163+ currentPrefixMode = mode ;
164+
165+ document . querySelectorAll ( 'pre code[id^="code-block-"]' ) . forEach ( block => {
166+ const blockId = block . id ;
167+ if ( originalCodeCache . has ( blockId ) ) {
168+ const originalCode = originalCodeCache . get ( blockId ) ! ;
169+
170+ if ( mode === 'without-prefix' ) {
171+ block . textContent = removePythonPrefixes ( originalCode ) ;
172+ } else {
173+ block . textContent = originalCode ;
174+ }
175+ }
176+
177+ // 移除已高亮标记,以便重新高亮
178+ if ( block instanceof HTMLElement ) {
179+ delete block . dataset . highlighted ;
180+ }
181+ } ) ;
182+
183+ // 重新高亮所有代码
184+ if ( ( window as any ) . hljs && typeof ( window as any ) . hljs . highlightAll === 'function' ) {
185+ try {
186+ ( window as any ) . hljs . highlightAll ( ) ;
187+ } catch ( error ) {
188+ console . error ( 'Error highlighting code:' , error ) ;
189+ }
190+ }
191+
192+ // 更新全局切换按钮的文本
193+ const prefixToggleButton = document . getElementById ( 'prefix-toggle-button' ) ;
194+ if ( prefixToggleButton ) {
195+ prefixToggleButton . textContent = mode === 'with-prefix' ? 'Show without prefix' : 'Show with prefix' ;
196+ }
197+ }
198+
14199// 动态加载HTML内容的函数
15200function loadContent ( language : LanguageType ) : void {
16201 // 设置当前语言显示
@@ -19,6 +204,9 @@ function loadContent(language: LanguageType): void {
19204 languageTextElement . textContent = language === 'english' ? 'English' : '中文' ;
20205 }
21206
207+ // 清空代码缓存
208+ originalCodeCache . clear ( ) ;
209+
22210 // 更新URL参数但不刷新页面
23211 const style : StyleType = ( getURLParameter ( 'hl_style' ) as StyleType ) || 'atom-one-dark' ;
24212 const url = new URL ( window . location . href ) ;
@@ -48,6 +236,9 @@ function loadContent(language: LanguageType): void {
48236 contentContainer . innerHTML = html ;
49237 }
50238
239+ // 设置代码块(添加按钮和处理前缀)
240+ setupCodeBlocks ( ) ;
241+
51242 // 高亮代码
52243 if ( ( window as any ) . hljs && typeof ( window as any ) . hljs . highlightAll === 'function' ) {
53244 ( window as any ) . hljs . highlightAll ( ) ;
@@ -65,6 +256,32 @@ function loadContent(language: LanguageType): void {
65256
66257// 等待DOM完全加载后执行代码
67258document . addEventListener ( 'DOMContentLoaded' , function ( ) {
259+ // 创建全局前缀切换按钮
260+ function createGlobalPrefixToggleButton ( ) {
261+ const buttonContainer = document . createElement ( 'div' ) ;
262+ buttonContainer . className = 'prefix-toggle-container' ;
263+ buttonContainer . style . display = 'inline-block' ;
264+ buttonContainer . style . marginRight = '1rem' ;
265+
266+ const toggleButton = document . createElement ( 'button' ) ;
267+ toggleButton . id = 'prefix-toggle-button' ;
268+ toggleButton . className = 'button' ;
269+ toggleButton . textContent = 'Show without prefix' ;
270+ toggleButton . addEventListener ( 'click' , function ( ) {
271+ // 切换全局前缀模式
272+ const newMode = currentPrefixMode === 'with-prefix' ? 'without-prefix' : 'with-prefix' ;
273+ applyPrefixMode ( newMode ) ;
274+ } ) ;
275+
276+ buttonContainer . appendChild ( toggleButton ) ;
277+
278+ // 将按钮添加到下拉菜单旁边
279+ const languageDropdown = document . getElementById ( 'language' ) ;
280+ if ( languageDropdown && languageDropdown . parentNode ) {
281+ languageDropdown . parentNode . insertBefore ( buttonContainer , languageDropdown ) ;
282+ }
283+ }
284+
68285 // 初始化主题选择器
69286 const hlStyleParam : StyleType = ( getURLParameter ( 'hl_style' ) as StyleType ) || 'atom-one-dark' ;
70287 const hlStyleNameMap : Record < StyleType , string > = {
@@ -188,6 +405,13 @@ document.addEventListener('DOMContentLoaded', function() {
188405 }
189406 } ;
190407
408+ // 创建全局前缀切换按钮
409+ createGlobalPrefixToggleButton ( ) ;
410+
191411 // 初始加载内容
192412 loadContent ( languageParam ) ;
193- } ) ;
413+ } ) ;
414+
415+ // 暴露全局函数供外部调用
416+ ( window as any ) . applyPrefixMode = applyPrefixMode ;
417+ ( window as any ) . toggleCodePrefix = toggleCodePrefix ;
0 commit comments