GoPLS Viewer

Home|gopls/internal/diff/ndiff.go
1// Copyright 2022 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package diff
6
7import (
8    "bytes"
9    "unicode/utf8"
10
11    "golang.org/x/tools/internal/diff/lcs"
12)
13
14// Strings computes the differences between two strings.
15// The resulting edits respect rune boundaries.
16func Strings(beforeafter string) []Edit {
17    if before == after {
18        return nil // common case
19    }
20
21    if stringIsASCII(before) && stringIsASCII(after) {
22        // TODO(adonovan): opt: specialize diffASCII for strings.
23        return diffASCII([]byte(before), []byte(after))
24    }
25    return diffRunes([]rune(before), []rune(after))
26}
27
28// Bytes computes the differences between two byte slices.
29// The resulting edits respect rune boundaries.
30func Bytes(beforeafter []byte) []Edit {
31    if bytes.Equal(beforeafter) {
32        return nil // common case
33    }
34
35    if bytesIsASCII(before) && bytesIsASCII(after) {
36        return diffASCII(beforeafter)
37    }
38    return diffRunes(runes(before), runes(after))
39}
40
41func diffASCII(beforeafter []byte) []Edit {
42    diffs := lcs.DiffBytes(beforeafter)
43
44    // Convert from LCS diffs.
45    res := make([]Editlen(diffs))
46    for id := range diffs {
47        res[i] = Edit{d.Startd.Endstring(after[d.ReplStart:d.ReplEnd])}
48    }
49    return res
50}
51
52func diffRunes(beforeafter []rune) []Edit {
53    diffs := lcs.DiffRunes(beforeafter)
54
55    // The diffs returned by the lcs package use indexes
56    // into whatever slice was passed in.
57    // Convert rune offsets to byte offsets.
58    res := make([]Editlen(diffs))
59    lastEnd := 0
60    utf8Len := 0
61    for id := range diffs {
62        utf8Len += runesLen(before[lastEnd:d.Start]) // text between edits
63        start := utf8Len
64        utf8Len += runesLen(before[d.Start:d.End]) // text deleted by this edit
65        res[i] = Edit{startutf8Lenstring(after[d.ReplStart:d.ReplEnd])}
66        lastEnd = d.End
67    }
68    return res
69}
70
71// runes is like []rune(string(bytes)) without the duplicate allocation.
72func runes(bytes []byte) []rune {
73    n := utf8.RuneCount(bytes)
74    runes := make([]runen)
75    for i := 0i < ni++ {
76        rsz := utf8.DecodeRune(bytes)
77        bytes = bytes[sz:]
78        runes[i] = r
79    }
80    return runes
81}
82
83// runesLen returns the length in bytes of the UTF-8 encoding of runes.
84func runesLen(runes []rune) (len int) {
85    for _r := range runes {
86        len += utf8.RuneLen(r)
87    }
88    return len
89}
90
91// stringIsASCII reports whether s contains only ASCII.
92// TODO(adonovan): combine when x/tools allows generics.
93func stringIsASCII(s stringbool {
94    for i := 0i < len(s); i++ {
95        if s[i] >= utf8.RuneSelf {
96            return false
97        }
98    }
99    return true
100}
101
102func bytesIsASCII(s []bytebool {
103    for i := 0i < len(s); i++ {
104        if s[i] >= utf8.RuneSelf {
105            return false
106        }
107    }
108    return true
109}
110
MembersX
diffRunes
runes.runes
stringIsASCII
Strings.after
Bytes.before
diffASCII.after
diffASCII.RangeStmt_1172.i
bytesIsASCII.s
diffASCII
diffRunes.RangeStmt_1569.i
runesLen.RangeStmt_2253.r
stringIsASCII.s
runesLen.len
bytes
diffASCII.RangeStmt_1172.d
diffRunes.RangeStmt_1569.d
runes.BlockStmt.sz
diffRunes.after
diffRunes.res
runes.BlockStmt.r
bytesIsASCII
Bytes
diffRunes.diffs
runesLen.runes
lcs
Strings
diffASCII.diffs
diffRunes.RangeStmt_1569.BlockStmt.start
diffRunes.lastEnd
diffRunes.utf8Len
runes
runes.bytes
Bytes.after
diffASCII.before
diffASCII.res
diffRunes.before
runes.n
runes.i
stringIsASCII.i
Strings.before
runesLen
bytesIsASCII.i
Members
X