Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit 30abfe8

Browse files
committed
chore: development
1 parent e808175 commit 30abfe8

File tree

5 files changed

+152
-50
lines changed

5 files changed

+152
-50
lines changed

dev/App.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import template from './template'
4848
export default defineComponent({
4949
setup () {
5050
const modes = ref(['split', 'unified'])
51-
const mode = ref('unified')
51+
const mode = ref('split')
5252
const languages = ref(['javascript', 'html', 'css'])
5353
const language = ref('html')
5454
const themes = ref(['light', 'okaidia'])

dev/template_test.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
const javascript1 =
2-
`var a1 = {
2+
`const b2 = {
33
"name": "vue-diff",
4-
"version": "0.0.0",
4+
"version": "0.0.1",
55
"description": "Vue diff viewer",
6-
"private": true
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"test:unit": "vue-cli-service test:unit",
10+
"test:e2e": "vue-cli-service test:e2e",
11+
"lint": "vue-cli-service lint"
12+
}
713
}`
814

915
const javascript2 =
@@ -27,9 +33,10 @@ const html1 =
2733
<meta charset="UTF-8">
2834
<meta name="viewport" content="width=device-width, initial-scale=1.0">
2935
<title>Vue Diff</title>
36+
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
3037
</head>
31-
<body>
32-
<div id="app"></div>
38+
<body class="bg-gray-900">
39+
<div id="app" class="p-12"></div>
3340
<script type="module" src="/dev/main.ts"></script>
3441
</body>
3542
</html>`
@@ -50,10 +57,15 @@ const html2 =
5057
</html>`
5158

5259
const css1 =
53-
`@import '../../node_modules/prismjs/themes/prism-okaidia.css';
60+
`@import 'prismjs/themes/prism-okaidia.css';
61+
62+
div.vue-diff-viewer {
63+
background-color: #666;
64+
}
5465
55-
.vue-diff-viewer {
56-
background-color: #272822;
66+
#vue-diff-viewer {
67+
display: flex;
68+
display: -webkit-flex;
5769
}`
5870

5971
const css2 =

src/Code.vue

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,58 @@
11
<template>
2-
<tr v-if="mode === 'split'">
2+
<tr v-if="mode === 'split'" :class="`vue-diff-row-${mode}`">
33
<template :key="index" v-for="(line, index) in data">
44
<td class="lineNum" :class="`vue-diff-cell-${line.type}`">
55
{{ line.lineNum }}
66
</td>
77
<td class="code" :class="`vue-diff-cell-${line.type}`">
8-
<pre :class="`language-${language}`"><code :class="`language-${language}`" v-html="getHighlight(line.value)"></code></pre>
8+
<pre :class="`language-${language}`"><code
9+
:class="`language-${language}`"
10+
v-html="line.type.match(/added|removed/) ?
11+
getHighlightCode(line.value, data, index) :
12+
getHighlightCode(line.value)"
13+
></code></pre>
914
</td>
1015
</template>
1116
</tr>
1217
<template v-if="mode === 'unified'">
13-
<tr>
18+
<tr :class="`vue-diff-row-${mode}`">
1419
<td class="lineNum" :class="`vue-diff-cell-${data[0].type}`">
1520
{{ data[0].lineNum }}
1621
</td>
1722
<td class="code" :class="`vue-diff-cell-${data[0].type}`">
18-
<pre :class="`language-${language}`"><code :class="`language-${language}`" v-html="getHighlight(data[0].value)"></code></pre>
23+
<pre :class="`language-${language}`"><code :class="`language-${language}`" v-html="getHighlightCode(data[0].value)"></code></pre>
1924
</td>
2025
</tr>
2126
</template>
2227
</template>
2328

2429
<script lang="ts">
2530
import Prism from 'prismjs'
26-
import { defineComponent, PropType, ref, computed } from 'vue'
27-
import { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG } from './utils'
31+
import { defineComponent, PropType } from 'vue'
32+
import { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG, renderWords } from './utils'
2833
29-
import type { Mode, Lines, Line } from './utils'
34+
import type { Mode, Lines } from './utils'
35+
36+
// @ts-ignore
37+
Prism.manual = true
38+
39+
// Prism.hooks.add('before-tokenize', function (env) {
40+
// if (env.code.match(new RegExp(`${MODIFIED_START_TAG}`, 'gi'))) {
41+
// const code = env.code
42+
// const pureCode = env.code
43+
// .replace(new RegExp(`${MODIFIED_START_TAG}`, 'gi'), '')
44+
// .replace(new RegExp(`${MODIFIED_CLOSE_TAG}`, 'gi'), '')
45+
46+
// env._modified = code
47+
// env.code = pureCode
48+
// }
49+
// })
50+
51+
// Prism.hooks.add('after-tokenize', function (env) {
52+
// if (env._modified) {
53+
// console.log(env)
54+
// }
55+
// })
3056
3157
export default defineComponent({
3258
props: {
@@ -39,38 +65,60 @@ export default defineComponent({
3965
required: true
4066
},
4167
data: {
42-
type: Object as PropType<Array<Lines>>,
68+
type: Object as PropType<Lines>,
4369
required: true
4470
}
4571
},
4672
setup (props) {
47-
const getSkipUnified = (line: Line, index: number) => {
48-
return ((index === 0 && line.type === 'equal') || line.type === 'disabled')
49-
}
50-
51-
const getHighlight = (value: string) => {
73+
const getHighlightCode = (value: string, data?: Lines, index?: number) => {
5274
if (!value) return '\n'
5375
54-
return Prism.highlight(value, Prism.languages[props.language], props.language)
55-
// .replace(new RegExp(`${MODIFIED_START_TAG}`, 'gi'), '<span class="token modified">')
56-
// .replace(new RegExp(`${MODIFIED_CLOSE_TAG}`, 'gi'), '</span>')
76+
let code = value
77+
78+
if (data) { // Diff words
79+
const diffIndex = index === 0 ? 1 : 0
80+
const diffValue = data[diffIndex].value
81+
82+
if (diffValue) { // Wrap custom highlight
83+
code = renderWords(diffValue, value)
84+
}
85+
}
86+
87+
const grammer = Prism.languages[props.language]
88+
const highlightCode = Prism.highlight(code, grammer, props.language)
89+
90+
const regexStartTag = Prism.Token.stringify(Prism.util.encode(Prism.tokenize(MODIFIED_START_TAG, grammer)), props.language)
91+
const regexCloseTag = Prism.Token.stringify(Prism.util.encode(Prism.tokenize(MODIFIED_CLOSE_TAG, grammer)), props.language)
92+
93+
return highlightCode
94+
// .replace(new RegExp(`${regexStartTag}`, 'gi'), '<span class="token modified">')
95+
// .replace(new RegExp(`${regexCloseTag}`, 'gi'), '</span>')
96+
}
97+
98+
return {
99+
getHighlightCode
57100
}
58-
return { getSkipUnified, getHighlight }
59101
}
60102
})
61103
</script>
62104

63105
<style scoped lang="scss">
64106
td {
65107
padding: 0 0.5em;
108+
vertical-align: top;
66109
67110
&.lineNum {
68-
width: 2em;
111+
width: 3.5em;
112+
padding-top: .05em;
69113
text-align: right;
70114
color: #999;
71115
font-size: 0.9em;
72116
}
73117
118+
&.code {
119+
width: calc(100% - 2em);
120+
}
121+
74122
pre[class*="language-"]:before {
75123
display: inline-block;
76124
position: absolute;
@@ -80,9 +128,16 @@ td {
80128
}
81129
}
82130
131+
tr.vue-diff-row-split {
132+
td.code {
133+
width: calc(50% - 2em);
134+
}
135+
}
136+
83137
pre[class*="language-"] {
84138
display: block;
85139
position: relative;
140+
max-width: 100%;
86141
margin: 0;
87142
padding: 0;
88143
padding-left: 1.5em;
@@ -91,6 +146,12 @@ pre[class*="language-"] {
91146
border-radius: 0;
92147
}
93148
149+
code {
150+
word-wrap: break-all;
151+
word-break: break-all;
152+
white-space: pre-wrap;
153+
}
154+
94155
td.vue-diff-cell-removed {
95156
background-color: rgba(255, 0, 0, .1);
96157

src/Diff.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,13 @@ export default defineComponent({
6969
}
7070
7171
.vue-diff-viewer {
72-
overflow: auto;
7372
width: 100%;
7473
padding: 1em 0;
7574
border-radius: 0.3em;
7675
}
7776
7877
table {
79-
min-width: 100%;
78+
width: 100%;
8079
table-layout: fixed;
8180
border-collapse: collapse;
8281
}

src/utils.ts

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Prism from 'prismjs'
21
import * as Diff from 'diff'
32

43
import type { Change } from 'diff'
@@ -15,29 +14,14 @@ interface Line {
1514
type Lines = Array<Line>
1615
type Diffs = Array<Change>
1716

18-
// @ts-ignore
19-
Prism.manual = true
17+
const MODIFIED_START_TAG = '<vue-diff-modified>'
18+
const MODIFIED_CLOSE_TAG = '</vue-diff-modified>'
2019

21-
const MODIFIED_START_TAG = '<span class="token modified">'
22-
const MODIFIED_CLOSE_TAG = '</span>'
23-
24-
function getDiffType (diff: Change) {
20+
const getDiffType = (diff: Change) => {
2521
if (!diff.count) return 'disabled'
2622
return diff.added ? 'added' : diff.removed ? 'removed' : 'equal'
2723
}
2824

29-
const renderLine = (diffWords: Array<Change>) => {
30-
return diffWords.filter(word => getDiffType(word) !== 'removed').map(word => {
31-
const type = getDiffType(word)
32-
33-
if (type === 'added') {
34-
return `${MODIFIED_START_TAG}${word.value}${MODIFIED_CLOSE_TAG}`
35-
} else {
36-
return word.value
37-
}
38-
}).join('')
39-
}
40-
4125
const getSplitLines = (diffsMap: Array<Diffs>): Array<Lines> => {
4226
const result: Array<Lines> = [] // Array(0): prev, Array(1): current
4327
const lineNum = {
@@ -130,7 +114,7 @@ const renderLines = (mode: Mode, prev: string, current: string): Array<Lines> =>
130114
}
131115

132116
if (type === 'added') {
133-
if (acc[acc.length - 1][0].removed) {
117+
if (acc.length && acc[acc.length - 1][0] && acc[acc.length - 1][0].removed) {
134118
acc[acc.length - 1].push(curr)
135119
} else {
136120
acc.push([curr])
@@ -163,5 +147,51 @@ const renderLines = (mode: Mode, prev: string, current: string): Array<Lines> =>
163147
}
164148
}
165149

166-
export { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG, renderLines }
150+
const renderWords = (prev: string, current: string) => {
151+
return Diff.diffWords(prev, current).filter(word => getDiffType(word) !== 'removed').map(word => {
152+
const type = getDiffType(word)
153+
if (type === 'added') {
154+
return `${MODIFIED_START_TAG}${word.value}${MODIFIED_CLOSE_TAG}`
155+
} else {
156+
return word.value
157+
}
158+
}).join('')
159+
}
160+
161+
// const renderWords = (prev: string, current: string) => {
162+
// if (!document) {
163+
// throw new Error('This function support client-only')
164+
// }
165+
166+
// let prevEl: HTMLElement | null = document.createElement('div')
167+
// prevEl.innerHTML = prev
168+
169+
// let currentEl: HTMLElement | null = document.createElement('div')
170+
// currentEl.innerHTML = current
171+
172+
// Array.from(currentEl.children).map((node, index) => {
173+
// if (prevEl?.children[index] && (prevEl.children[index].textContent !== node.textContent)) {
174+
// node.innerHTML = `${MODIFIED_START_TAG}${node.textContent}${MODIFIED_CLOSE_TAG}`
175+
// }
176+
// })
177+
178+
// const code = currentEl.innerHTML
179+
180+
// prevEl = null
181+
// currentEl = null
182+
183+
// return code
184+
185+
// // return Diff.diffWords(prev, current).filter(word => getDiffType(word) !== 'removed').map(word => {
186+
// // const type = getDiffType(word)
187+
188+
// // if (type === 'added') {
189+
// // return `${MODIFIED_START_TAG}${word.value}${MODIFIED_CLOSE_TAG}`
190+
// // } else {
191+
// // return word.value
192+
// // }
193+
// // })
194+
// }
195+
196+
export { MODIFIED_START_TAG, MODIFIED_CLOSE_TAG, renderLines, renderWords }
167197
export type { Mode, Role, Change, Lines, Line }

0 commit comments

Comments
 (0)