1 // Copyright 2019 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.
13 // ToUTF16Column calculates the utf16 column expressed by the point given the
14 // supplied file contents.
15 // This is used to convert from the native (always in bytes) column
16 // representation and the utf16 counts used by some editors.
17 func ToUTF16Column(p Point, content []byte) (int, error) {
19 return -1, fmt.Errorf("ToUTF16Column: point is missing position")
22 return -1, fmt.Errorf("ToUTF16Column: point is missing offset")
24 offset := p.Offset() // 0-based
25 colZero := p.Column() - 1 // 0-based
27 // 0-based column 0, so it must be chr 1
29 } else if colZero < 0 {
30 return -1, fmt.Errorf("ToUTF16Column: column is invalid (%v)", colZero)
32 // work out the offset at the start of the line using the column
33 lineOffset := offset - colZero
34 if lineOffset < 0 || offset > len(content) {
35 return -1, fmt.Errorf("ToUTF16Column: offsets %v-%v outside file contents (%v)", lineOffset, offset, len(content))
37 // Use the offset to pick out the line start.
38 // This cannot panic: offset > len(content) and lineOffset < offset.
39 start := content[lineOffset:]
41 // Now, truncate down to the supplied column.
42 start = start[:colZero]
44 // and count the number of utf16 characters
45 // in theory we could do this by hand more efficiently...
46 return len(utf16.Encode([]rune(string(start)))) + 1, nil
49 // FromUTF16Column advances the point by the utf16 character offset given the
50 // supplied line contents.
51 // This is used to convert from the utf16 counts used by some editors to the
52 // native (always in bytes) column representation.
53 func FromUTF16Column(p Point, chr int, content []byte) (Point, error) {
55 return Point{}, fmt.Errorf("FromUTF16Column: point is missing offset")
57 // if chr is 1 then no adjustment needed
61 if p.Offset() >= len(content) {
62 return p, fmt.Errorf("FromUTF16Column: offset (%v) greater than length of content (%v)", p.Offset(), len(content))
64 remains := content[p.Offset():]
65 // scan forward the specified number of characters
66 for count := 1; count < chr; count++ {
67 if len(remains) <= 0 {
68 return Point{}, fmt.Errorf("FromUTF16Column: chr goes beyond the content")
70 r, w := utf8.DecodeRune(remains)
74 // > If the character value is greater than the line length it
75 // > defaults back to the line length.
82 // if we finished in a two point rune, do not advance past the first