|
5 | 5 | package repo
|
6 | 6 |
|
7 | 7 | import (
|
| 8 | + "bufio" |
8 | 9 | "fmt"
|
| 10 | + "html" |
9 | 11 | "path"
|
| 12 | + "path/filepath" |
10 | 13 | "strings"
|
11 | 14 |
|
12 | 15 | "code.gitea.io/gitea/models"
|
13 | 16 | "code.gitea.io/gitea/modules/base"
|
14 | 17 | "code.gitea.io/gitea/modules/context"
|
15 | 18 | "code.gitea.io/gitea/modules/git"
|
| 19 | + "code.gitea.io/gitea/modules/highlight" |
16 | 20 | "code.gitea.io/gitea/modules/log"
|
17 | 21 | "code.gitea.io/gitea/modules/setting"
|
18 | 22 | "code.gitea.io/gitea/services/gitdiff"
|
19 | 23 | )
|
20 | 24 |
|
21 | 25 | const (
|
22 |
| - tplCompare base.TplName = "repo/diff/compare" |
| 26 | + tplCompare base.TplName = "repo/diff/compare" |
| 27 | + tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" |
23 | 28 | )
|
24 | 29 |
|
25 | 30 | // setPathsCompareContext sets context data for source and raw paths
|
@@ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) {
|
434 | 439 |
|
435 | 440 | ctx.HTML(200, tplCompare)
|
436 | 441 | }
|
| 442 | + |
| 443 | +// ExcerptBlob render blob excerpt contents |
| 444 | +func ExcerptBlob(ctx *context.Context) { |
| 445 | + commitID := ctx.Params("sha") |
| 446 | + lastLeft := ctx.QueryInt("last_left") |
| 447 | + lastRight := ctx.QueryInt("last_right") |
| 448 | + idxLeft := ctx.QueryInt("left") |
| 449 | + idxRight := ctx.QueryInt("right") |
| 450 | + leftHunkSize := ctx.QueryInt("left_hunk_size") |
| 451 | + rightHunkSize := ctx.QueryInt("right_hunk_size") |
| 452 | + anchor := ctx.Query("anchor") |
| 453 | + direction := ctx.Query("direction") |
| 454 | + filePath := ctx.Query("path") |
| 455 | + gitRepo := ctx.Repo.GitRepo |
| 456 | + chunkSize := gitdiff.BlobExceprtChunkSize |
| 457 | + commit, err := gitRepo.GetCommit(commitID) |
| 458 | + if err != nil { |
| 459 | + ctx.Error(500, "GetCommit") |
| 460 | + return |
| 461 | + } |
| 462 | + section := &gitdiff.DiffSection{ |
| 463 | + Name: filePath, |
| 464 | + } |
| 465 | + if direction == "up" && (idxLeft-lastLeft) > chunkSize { |
| 466 | + idxLeft -= chunkSize |
| 467 | + idxRight -= chunkSize |
| 468 | + leftHunkSize += chunkSize |
| 469 | + rightHunkSize += chunkSize |
| 470 | + section.Lines, err = getExcerptLines(commit, filePath, idxLeft-1, idxRight-1, chunkSize) |
| 471 | + } else if direction == "down" && (idxLeft-lastLeft) > chunkSize { |
| 472 | + section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, chunkSize) |
| 473 | + lastLeft += chunkSize |
| 474 | + lastRight += chunkSize |
| 475 | + } else { |
| 476 | + section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, idxRight-lastRight-1) |
| 477 | + leftHunkSize = 0 |
| 478 | + rightHunkSize = 0 |
| 479 | + idxLeft = lastLeft |
| 480 | + idxRight = lastRight |
| 481 | + } |
| 482 | + if err != nil { |
| 483 | + ctx.Error(500, "getExcerptLines") |
| 484 | + return |
| 485 | + } |
| 486 | + if idxRight > lastRight { |
| 487 | + lineText := " " |
| 488 | + if rightHunkSize > 0 || leftHunkSize > 0 { |
| 489 | + lineText = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize) |
| 490 | + } |
| 491 | + lineText = html.EscapeString(lineText) |
| 492 | + lineSection := &gitdiff.DiffLine{ |
| 493 | + Type: gitdiff.DiffLineSection, |
| 494 | + Content: lineText, |
| 495 | + SectionInfo: &gitdiff.DiffLineSectionInfo{ |
| 496 | + Path: filePath, |
| 497 | + LastLeftIdx: lastLeft, |
| 498 | + LastRightIdx: lastRight, |
| 499 | + LeftIdx: idxLeft, |
| 500 | + RightIdx: idxRight, |
| 501 | + LeftHunkSize: leftHunkSize, |
| 502 | + RightHunkSize: rightHunkSize, |
| 503 | + }} |
| 504 | + if direction == "up" { |
| 505 | + section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...) |
| 506 | + } else if direction == "down" { |
| 507 | + section.Lines = append(section.Lines, lineSection) |
| 508 | + } |
| 509 | + } |
| 510 | + ctx.Data["section"] = section |
| 511 | + ctx.Data["fileName"] = filePath |
| 512 | + ctx.Data["highlightClass"] = highlight.FileNameToHighlightClass(filepath.Base(filePath)) |
| 513 | + ctx.Data["AfterCommitID"] = commitID |
| 514 | + ctx.Data["Anchor"] = anchor |
| 515 | + ctx.HTML(200, tplBlobExcerpt) |
| 516 | +} |
| 517 | + |
| 518 | +func getExcerptLines(commit *git.Commit, filePath string, idxLeft int, idxRight int, chunkSize int) ([]*gitdiff.DiffLine, error) { |
| 519 | + blob, err := commit.Tree.GetBlobByPath(filePath) |
| 520 | + if err != nil { |
| 521 | + return nil, err |
| 522 | + } |
| 523 | + reader, err := blob.DataAsync() |
| 524 | + if err != nil { |
| 525 | + return nil, err |
| 526 | + } |
| 527 | + defer reader.Close() |
| 528 | + scanner := bufio.NewScanner(reader) |
| 529 | + var diffLines []*gitdiff.DiffLine |
| 530 | + for line := 0; line < idxRight+chunkSize; line++ { |
| 531 | + if ok := scanner.Scan(); !ok { |
| 532 | + break |
| 533 | + } |
| 534 | + if line < idxRight { |
| 535 | + continue |
| 536 | + } |
| 537 | + lineText := scanner.Text() |
| 538 | + diffLine := &gitdiff.DiffLine{ |
| 539 | + LeftIdx: idxLeft + (line - idxRight) + 1, |
| 540 | + RightIdx: line + 1, |
| 541 | + Type: gitdiff.DiffLinePlain, |
| 542 | + Content: " " + lineText, |
| 543 | + } |
| 544 | + diffLines = append(diffLines, diffLine) |
| 545 | + } |
| 546 | + return diffLines, nil |
| 547 | +} |
0 commit comments