@@ -11,6 +11,7 @@ import c from 'picocolors'
1111import type { BundledLanguage , ShikiTransformer } from 'shiki'
1212import { createHighlighter , guessEmbeddedLanguages , isSpecialLang } from 'shiki'
1313import type { Logger } from 'vite'
14+ import { isShell } from '../../shared'
1415import type { MarkdownOptions , ThemeOptions } from '../markdown'
1516
1617const nanoid = customAlphabet ( 'abcdefghijklmnopqrstuvwxyz' , 10 )
@@ -47,6 +48,40 @@ function attrsToLines(attrs: string): TransformerCompactLineOption[] {
4748 } ) )
4849}
4950
51+ /**
52+ * Prevents the leading '$' symbol etc from being selectable/copyable. Also
53+ * normalizes its syntax so there's no leading spaces, and only a single
54+ * trailing space.
55+ *
56+ * NOTE: Any changes to this function may also need to update
57+ * `src/client/app/composables/copyCode.ts`
58+ */
59+ function transformerDisableShellSymbolSelect ( ) : ShikiTransformer {
60+ return {
61+ name : 'vitepress:disable-shell-symbol-select' ,
62+ tokens ( tokensByLine ) {
63+ if ( ! isShell ( this . options . lang ) ) return
64+
65+ for ( const tokens of tokensByLine ) {
66+ if ( tokens . length < 2 ) continue
67+
68+ // The first token should only be a symbol token
69+ const firstTokenText = tokens [ 0 ] . content . trim ( )
70+ if ( firstTokenText !== '$' && firstTokenText !== '>' ) continue
71+
72+ // The second token must have a leading space (separates the symbol)
73+ if ( tokens [ 1 ] . content [ 0 ] !== ' ' ) continue
74+
75+ tokens [ 0 ] . content = firstTokenText + ' '
76+ tokens [ 0 ] . htmlStyle ??= { }
77+ tokens [ 0 ] . htmlStyle [ 'user-select' ] = 'none'
78+ tokens [ 0 ] . htmlStyle [ '-webkit-user-select' ] = 'none'
79+ tokens [ 1 ] . content = tokens [ 1 ] . content . slice ( 1 )
80+ }
81+ }
82+ }
83+ }
84+
5085export async function highlight (
5186 theme : ThemeOptions ,
5287 options : MarkdownOptions ,
@@ -83,6 +118,7 @@ export async function highlight(
83118 } ) ,
84119 transformerNotationHighlight ( ) ,
85120 transformerNotationErrorLevel ( ) ,
121+ transformerDisableShellSymbolSelect ( ) ,
86122 {
87123 name : 'vitepress:add-dir' ,
88124 pre ( node ) {
0 commit comments