package diff // keepDeleted is how many blocks of a run of deletions an excerpt shows // before summing up the rest. In a rewrite, a long run of removed // paragraphs would otherwise use up the excerpt before the new text. const keepDeleted = 2 // Excerpt keeps the changed ops of a full diff, with up to context unchanged // blocks around each, and folds the other unchanged runs into gap ops. Runs // of deleted blocks longer than keepDeleted are cut to a "removed" gap. It // stops after maxChanged changed ops and reports whether it cut anything. func Excerpt(ops []Op, context, maxChanged int) ([]Op, bool) { keep := make([]bool, len(ops)) for i, op := range ops { if op.Op == OpEq { continue } keep[i] = true for k := 1; k <= context; k++ { if i-k >= 0 && ops[i-k].Op == OpEq { keep[i-k] = true } if i+k < len(ops) && ops[i+k].Op == OpEq { keep[i+k] = true } } } var out []Op gap, changed, deleted := 0, 0, 0 for i, op := range ops { if !keep[i] { gap++ continue } if op.Op == OpDelete { deleted++ if deleted > keepDeleted { if n := len(out); n > 0 && out[n-1].Op == OpGap && out[n-1].Removed { out[n-1].Count++ } else { out = append(out, Op{Op: OpGap, Count: 1, Removed: true}) } continue } } else { deleted = 0 } if op.Op != OpEq { if changed == maxChanged { return out, true } changed++ } if gap > 0 { out = append(out, Op{Op: OpGap, Count: gap}) gap = 0 } out = append(out, op) } if gap > 0 && len(out) > 0 { out = append(out, Op{Op: OpGap, Count: gap}) } return out, false }