Skip to content

Commit 78275c2

Browse files
committed
【修改信息】 git diff 优化
1 parent 1e2c631 commit 78275c2

4 files changed

Lines changed: 477 additions & 244 deletions

File tree

ZLGitHubClient/ZLGitHubClient/Class/UI/ZLReuseView/ZLCommitTableViewCell/viewModel/ZLCommitInfoPatchCellData.swift

Lines changed: 266 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class ZLCommitInfoPatchCellData: ZMBaseTableViewCellViewModel {
2323
var isBinary: Bool = false
2424
var isImage: Bool = false
2525

26+
var cacheHtml: String?
27+
2628
lazy var _webView: ZLReportHeightWebViewV2 = {
2729
let frame = CGRect(x: 0,
2830
y: 0,
@@ -65,13 +67,8 @@ class ZLCommitInfoPatchCellData: ZMBaseTableViewCellViewModel {
6567

6668
override func zm_clearCache() {
6769
super.zm_clearCache()
68-
_webView.evaluateJavaScript(renderDiffContentScript()) { (result, error) in
69-
if let error = error {
70-
print("JavaScript 执行错误: \(error)")
71-
} else if let result = result {
72-
print("JavaScript 执行结果: \(result)")
73-
}
74-
}
70+
generateHTML()
71+
_webView.loadHTML(cacheHtml ?? "", baseURL: Bundle.main.bundleURL)
7572
}
7673

7774
init(model: ZLGithubFileModel, cellHeight: CGFloat?) {
@@ -81,29 +78,23 @@ class ZLCommitInfoPatchCellData: ZMBaseTableViewCellViewModel {
8178
if let cellHeight = cellHeight {
8279
self.cellHeight = cellHeight
8380
}
84-
guard let url = Bundle.main.url(forResource: "gitpatchV2", withExtension: "html") else {
85-
return
86-
}
87-
_webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
81+
generateHTML()
82+
_webView.loadHTML(cacheHtml ?? "", baseURL: Bundle.main.bundleURL)
8883
}
8984

9085
func initData(model: ZLGithubFileModel) {
9186
if !model.patch.isEmpty {
92-
var patch = model.patch
93-
patch = patch.replacingOccurrences(of: "`", with: "\\`")
94-
patch = patch.replacingOccurrences(of: "$", with: "\\$")
95-
self.patchStr = patch
87+
let patch = model.patch
88+
self.patchStr = patch.htmlEscaped()
9689
self.isBinary = false
9790
self.isImage = false
9891
} else {
9992
self.isBinary = true
10093
let pathExtension = (model.filename as NSString).pathExtension.lowercased()
10194
if ["png","jpg","jpeg","gif","svg","webp","bmp","icon"].contains(pathExtension) {
10295
self.isImage = true
103-
var imagePath = model.blob_url
104-
imagePath = imagePath.replacingOccurrences(of: "`", with: "\\`")
105-
imagePath = imagePath.replacingOccurrences(of: "$", with: "\\$")
106-
self.imagePath = imagePath
96+
let imagePath = model.raw_url
97+
self.imagePath = imagePath.htmlEscaped()
10798
}
10899
}
109100

@@ -150,3 +141,259 @@ extension ZLCommitInfoPatchCellData: ZLCommitInfoPatchCellSourceAndDelegate {
150141
}
151142
}
152143

144+
extension ZLCommitInfoPatchCellData {
145+
146+
func generateHTML() {
147+
var gitPatchDivContent = ""
148+
if !isBinary {
149+
let tag = parsePatchAndGenerateHTML(patchText: self.patchStr)
150+
gitPatchDivContent = tag?.toHTMLString() ?? ""
151+
} else if isImage {
152+
gitPatchDivContent = "<img src=\"\(imagePath)\" class=\"img_binary\"/>"
153+
} else {
154+
if isLight {
155+
gitPatchDivContent = "<div class=\"div_binary\">Binary File</div>"
156+
} else {
157+
gitPatchDivContent = "<div class=\"div_binary dark\">Binary File</div>"
158+
}
159+
160+
}
161+
162+
let htmlURL: URL? = Bundle.main.url(forResource: "gitpatchV2", withExtension: "html")
163+
164+
if let url = htmlURL {
165+
166+
do {
167+
let htmlStr = try String.init(contentsOf: url)
168+
let newHtmlStr = NSMutableString.init(string: htmlStr)
169+
170+
let htmlRange = (newHtmlStr as NSString).range(of: "<html>")
171+
if htmlRange.location != NSNotFound, !isLight {
172+
newHtmlStr.insert(" class=\"dark\"", at: htmlRange.location + 5 )
173+
}
174+
175+
let divRange = (newHtmlStr as NSString).range(of: "</div>")
176+
if divRange.location != NSNotFound {
177+
newHtmlStr.insert(gitPatchDivContent, at: divRange.location)
178+
}
179+
180+
self.cacheHtml = newHtmlStr as String
181+
182+
} catch {
183+
ZLToastView.showMessage("load Code index html failed")
184+
}
185+
}
186+
}
187+
}
188+
189+
// MARK: - parse and generate html
190+
extension ZLCommitInfoPatchCellData {
191+
192+
class HTMLTag {
193+
let name: String
194+
var classList: [String] = []
195+
var children: [HTMLTag] = []
196+
var textContent: String = ""
197+
198+
init(name: String) {
199+
self.name = name
200+
}
201+
202+
func toHTMLString() -> String {
203+
var html = "<" + name
204+
205+
// 添加class属性
206+
if !classList.isEmpty {
207+
html += " class=\"" + classList.joined(separator: " ") + "\""
208+
}
209+
210+
html += ">"
211+
212+
// 添加文本内容
213+
if !textContent.isEmpty {
214+
html += textContent
215+
}
216+
217+
// 添加子元素
218+
for child in children {
219+
html += child.toHTMLString()
220+
}
221+
222+
html += "</" + name + ">"
223+
224+
return html
225+
}
226+
}
227+
228+
229+
func parsePatchAndGenerateHTML(patchText: String) -> HTMLTag? {
230+
let patchLines = patchText.split(separator: "\n")
231+
guard !patchLines.isEmpty else { return nil }
232+
233+
var currentOldLineNumber = 0;
234+
var currentNewLineNumber = 0;
235+
236+
let tableTag = HTMLTag(name: "table")
237+
let tbody = HTMLTag(name: "tbody")
238+
tableTag.children = [tbody]
239+
240+
241+
patchLines.forEach { line in
242+
243+
if (
244+
line.hasPrefix("diff --git") ||
245+
line.hasPrefix("index") ||
246+
line.hasPrefix("--- a") ||
247+
line.hasPrefix("+++ b")
248+
) {
249+
return;
250+
}
251+
252+
if (line.hasPrefix("@@")) {
253+
let (tr, oldLineNumber, newLineNumber ) = generateFileLineTr(line: String(line));
254+
tbody.children.append(tr)
255+
currentOldLineNumber = oldLineNumber;
256+
currentNewLineNumber = newLineNumber;
257+
258+
} else if (line.hasPrefix("+")) {
259+
let ( tr, newNum ) = generateAdditionTr(
260+
line: String(line),
261+
newLineNumber: currentNewLineNumber
262+
);
263+
tbody.children.append(tr)
264+
currentNewLineNumber = newNum;
265+
} else if (line.hasPrefix("-")) {
266+
let ( tr, oldNum ) = generateDeletionTr(
267+
line: String(line),
268+
oldLineNumber: currentOldLineNumber
269+
);
270+
tbody.children.append(tr);
271+
currentOldLineNumber = oldNum;
272+
} else {
273+
let (tr, oldNum, newNum) = generateNormalTr(
274+
line: String(line),
275+
oldLineNumber: currentOldLineNumber,
276+
newLineNumber: currentNewLineNumber
277+
);
278+
tbody.children.append(tr);
279+
currentOldLineNumber = oldNum;
280+
currentNewLineNumber = newNum;
281+
}
282+
}
283+
284+
return tableTag
285+
}
286+
287+
// @@ -138,28 +136,72 @@ extension ZLCommitInfoController
288+
func generateFileLineTr(line: String) -> (HTMLTag, Int, Int) {
289+
let ( tr, td_lineNumber, td_lineContent, div_lineNumber, div_lineContent ) =
290+
generatePatchLineTr();
291+
292+
let (oldStart, oldLines, newStart, newLines) = parseGitChangeLine(line);
293+
294+
div_lineContent.textContent = line;
295+
296+
td_lineNumber.classList.append("patch");
297+
td_lineContent.classList.append("patch");
298+
299+
return ( tr, oldStart, newStart );
300+
}
301+
302+
// +// func requestDiscussionComment(isLoadNew: Bool) {
303+
func generateAdditionTr(line: String, newLineNumber: Int) -> (HTMLTag, Int) {
304+
let ( tr, td_lineNumber, td_lineContent, div_lineNumber, div_lineContent ) =
305+
generatePatchLineTr();
306+
307+
div_lineNumber.textContent = "\(newLineNumber)"
308+
div_lineContent.textContent = line;
309+
td_lineNumber.classList.append("add");
310+
td_lineContent.classList.append("add");
311+
312+
let newNum = newLineNumber + 1;
313+
314+
return ( tr, newNum );
315+
}
316+
317+
// -// func requestCommitDiffInfo() {
318+
func generateDeletionTr(line: String, oldLineNumber: Int) -> (HTMLTag, Int) {
319+
let (tr, td_lineNumber, td_lineContent, div_lineNumber, div_lineContent) =
320+
generatePatchLineTr();
321+
322+
div_lineNumber.textContent = "\(oldLineNumber)"
323+
div_lineContent.textContent = line;
324+
td_lineNumber.classList.append("delete");
325+
td_lineContent.classList.append("delete");
326+
327+
let oldNum = oldLineNumber + 1;
328+
return ( tr, oldNum );
329+
}
330+
331+
func generateNormalTr(line: String, oldLineNumber: Int, newLineNumber: Int) -> (HTMLTag, Int, Int) {
332+
let ( tr, td_lineNumber, td_lineContent, div_lineNumber, div_lineContent ) =
333+
generatePatchLineTr();
334+
335+
div_lineNumber.textContent = "\(newLineNumber)";
336+
div_lineContent.textContent = line;
337+
338+
let oldNum = oldLineNumber + 1;
339+
let newNum = newLineNumber + 1;
340+
return ( tr, oldNum, newNum );
341+
}
342+
343+
344+
345+
func parseGitChangeLine(_ str: String) -> (Int,Int,Int,Int) {
346+
let pattern = #"^@@ -(\d+),(\d+) \+(\d+),(\d+) @@"#
347+
348+
guard let rangeMatch = str.range(of: pattern, options: .regularExpression) else {
349+
return (0,0,0,0)
350+
}
351+
352+
let numbers = str[rangeMatch].components(separatedBy: CharacterSet.decimalDigits.inverted)
353+
.filter { !$0.isEmpty }
354+
.compactMap { Int($0) }
355+
356+
guard numbers.count == 4 else {
357+
return (0,0,0,0)
358+
}
359+
360+
return (numbers[0],numbers[1],numbers[2],numbers[3])
361+
}
362+
363+
364+
func generatePatchLineTr() -> (HTMLTag,HTMLTag,HTMLTag,HTMLTag,HTMLTag){
365+
let tr = HTMLTag(name: "tr")
366+
let td_lineNumber = HTMLTag(name: "td")
367+
let div_lineNumber = HTMLTag(name:"div")
368+
let td_lineContent = HTMLTag(name:"td")
369+
let div_lineContent = HTMLTag(name:"div")
370+
td_lineNumber.children = [div_lineNumber]
371+
td_lineContent.children = [div_lineContent]
372+
373+
td_lineNumber.classList = ["td_linenum"]
374+
td_lineContent.classList = ["td_lineContent"]
375+
div_lineContent.classList = ["div_lineContent"]
376+
377+
if(!isLight) {
378+
td_lineNumber.classList.append("dark");
379+
td_lineContent.classList.append("dark");
380+
}
381+
382+
tr.children.append(td_lineNumber);
383+
tr.children.append(td_lineContent);
384+
385+
return (tr, td_lineNumber, td_lineContent, div_lineNumber, div_lineContent)
386+
}
387+
388+
}
389+
390+
extension String {
391+
func htmlEscaped() -> String {
392+
return self
393+
.replacingOccurrences(of: "&", with: "&amp;")
394+
.replacingOccurrences(of: "<", with: "&lt;")
395+
.replacingOccurrences(of: ">", with: "&gt;")
396+
.replacingOccurrences(of: "\"", with: "&quot;")
397+
.replacingOccurrences(of: "'", with: "&#39;")
398+
}
399+
}

0 commit comments

Comments
 (0)