77
88<script lang="ts">
99import hljs from ' highlight.js'
10- import { defineComponent , ref , onMounted } from ' vue'
10+ import { defineComponent , ref , onMounted , watch } from ' vue'
1111import { MODIFIED_START_TAG , MODIFIED_CLOSE_TAG } from ' ./utils'
1212import ' highlight.js/styles/monokai.css'
1313
14+ hljs .configure ({
15+ noHighlightRe: new RegExp (` (${MODIFIED_START_TAG }|${MODIFIED_CLOSE_TAG }) ` , ' g' )
16+ })
17+
18+ function escapeHTML (value : string ) {
19+ return value
20+ // .replace(/&/g, '&')
21+ // .replace(/</g, '<')
22+ // .replace(/>/g, '>')
23+ // .replace(/"/g, '"')
24+ // .replace(/'/g, ''')
25+ }
26+
1427export default defineComponent ({
1528 props: {
1629 language: {
@@ -25,14 +38,68 @@ export default defineComponent({
2538 setup (props ) {
2639 const code = ref (' ' )
2740
28- const pureValue = props .value .replace (new RegExp (` (${MODIFIED_START_TAG }|${MODIFIED_CLOSE_TAG }) ` , ' g' ), ' ' )
29- code .value = hljs .highlight (props .language , pureValue ).value
30-
3141 onMounted (() => {
32- const el = document .createElement (' div' )
33- el .innerHTML = code .value
42+ watch (() => props .value , () => {
43+ const hasModifyTags = props .value .match (new RegExp (` (${MODIFIED_START_TAG }|${MODIFIED_CLOSE_TAG }) ` , ' g' ))
44+
45+ if (! hasModifyTags ) {
46+ const { value : highlightCode } = hljs .highlight (props .language , props .value )
47+ code .value = highlightCode
48+ return
49+ }
50+
51+ let highlightCode = ' '
52+ const pureValue = props .value .replace (new RegExp (` (${MODIFIED_START_TAG }|${MODIFIED_CLOSE_TAG }) ` , ' g' ), ' ' ) // without modify tag
53+
54+ const pureHighlightCode = hljs .highlight (props .language , pureValue ).value
55+ let plainCode = escapeHTML (props .value )
56+ highlightCode = plainCode
57+
58+ const pureEl = document .createElement (' pre' )
59+ pureEl .innerHTML = pureHighlightCode
60+ const plainEl = document .createElement (' div' )
61+ plainEl .innerHTML = plainCode
62+
63+ function diff (node : HTMLElement ) {
64+ node .childNodes .forEach (child => {
65+ if (child .nodeType === 1 ) {
66+ diff (child as HTMLElement )
67+ }
68+ if (child .nodeType === 3 ) {
69+ if (! child .textContent ) return
70+
71+ let text = escapeHTML (child .textContent )
72+
73+ let code = ' '
74+
75+ while (text .length ) {
76+ if (plainCode .startsWith (MODIFIED_START_TAG )) {
77+ plainCode = plainCode .slice (MODIFIED_START_TAG .length )
78+ code = code + MODIFIED_START_TAG
79+ continue
80+ }
81+ if (plainCode .startsWith (MODIFIED_CLOSE_TAG )) {
82+ plainCode = plainCode .slice (MODIFIED_CLOSE_TAG .length )
83+ code = code + MODIFIED_CLOSE_TAG
84+ continue
85+ }
86+
87+ code = code + text [0 ]
88+ plainCode = plainCode .slice (1 )
89+ text = text .slice (1 )
90+ }
91+
92+ child .textContent = code
93+ }
94+ })
95+ }
96+ diff (pureEl )
97+
98+ const startEntity = MODIFIED_START_TAG .replace (' <' , ' <' ).replace (' >' , ' >' )
99+ const closeEntity = MODIFIED_CLOSE_TAG .replace (' <' , ' <' ).replace (' >' , ' >' )
34100
35- console .log (el .childNodes )
101+ code .value = pureEl .innerHTML .replace (new RegExp (startEntity , ' g' ), ' <span class="modified">' ).replace (new RegExp (closeEntity , ' g' ), ' </span>' )
102+ }, { immediate: true })
36103 })
37104
38105 return {
0 commit comments