mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
206 lines
4.3 KiB
Go
206 lines
4.3 KiB
Go
package common
|
|
|
|
import (
|
|
"config-lsp/utils"
|
|
)
|
|
|
|
type VirtualLine struct {
|
|
// This is the true location of the text
|
|
// This ranges from the start of the first line and character
|
|
// to the end of the last line and character
|
|
LocationRange
|
|
|
|
Parts []VirtualLinePart
|
|
}
|
|
|
|
func (l VirtualLine) GetText() string {
|
|
text := ""
|
|
|
|
for _, part := range l.Parts {
|
|
text += part.Text
|
|
}
|
|
|
|
return text
|
|
}
|
|
|
|
// GetSubset Get a subset of the virtual line starting from `start` and ending at `end`
|
|
func (l VirtualLine) GetSubset(start uint32, end uint32) VirtualLine {
|
|
parts := make([]VirtualLinePart, 0, 5)
|
|
currentIndex := uint32(0)
|
|
|
|
for _, part := range l.Parts {
|
|
partStart := currentIndex
|
|
partEnd := currentIndex + uint32(len(part.Text))
|
|
|
|
if partEnd < start {
|
|
continue
|
|
}
|
|
|
|
if start <= partEnd {
|
|
var rangeStart uint32
|
|
var rangeEnd uint32
|
|
|
|
if start >= partStart {
|
|
rangeStart = start - partStart
|
|
} else {
|
|
rangeStart = 0
|
|
}
|
|
|
|
if end <= partEnd {
|
|
rangeEnd = end - partStart
|
|
} else {
|
|
rangeEnd = partEnd
|
|
}
|
|
|
|
parts = append(parts, VirtualLinePart{
|
|
LocationRange: LocationRange{
|
|
Start: Location{
|
|
Line: part.Start.Line,
|
|
Character: part.Start.Character + rangeStart,
|
|
},
|
|
End: Location{
|
|
Line: part.Start.Line,
|
|
Character: part.Start.Character + rangeEnd,
|
|
},
|
|
},
|
|
Text: part.Text[rangeStart:rangeEnd],
|
|
})
|
|
}
|
|
|
|
currentIndex = partEnd
|
|
|
|
if currentIndex >= end {
|
|
break
|
|
}
|
|
}
|
|
|
|
return VirtualLine{
|
|
LocationRange: LocationRange{
|
|
Start: parts[0].Start,
|
|
End: parts[len(parts)-1].End,
|
|
},
|
|
Parts: parts,
|
|
}
|
|
}
|
|
|
|
// ConvertRangeToTextRange Convert a given start and end range to a text range
|
|
// start and end are the start and end ranges of the virtual line
|
|
// This will return the start and end ranges of the actual text lines so that they
|
|
// match to the text of the virtual line
|
|
// The `start` and `end` are expected to be within the range of the virtual line
|
|
func (l VirtualLine) ConvertRangeToTextRange(start uint32, end uint32) []LocationRange {
|
|
virtualLine := l.GetSubset(start, end)
|
|
|
|
ranges := make([]LocationRange, 0, 5)
|
|
|
|
for _, part := range virtualLine.Parts {
|
|
ranges = append(ranges, part.LocationRange)
|
|
}
|
|
|
|
return ranges
|
|
}
|
|
|
|
func (l VirtualLine) AsTrimmed() VirtualLine {
|
|
if len(l.Parts) == 0 {
|
|
// There's nothing that could be trimmed, so we can also just
|
|
// return the original line, as it's identical
|
|
return l
|
|
}
|
|
|
|
parts := make([]VirtualLinePart, len(l.Parts))
|
|
|
|
for index, part := range l.Parts {
|
|
parts[index] = part.AsTrimmed()
|
|
}
|
|
|
|
return VirtualLine{
|
|
LocationRange: LocationRange{
|
|
Start: parts[0].Start,
|
|
End: parts[len(parts)-1].End,
|
|
},
|
|
Parts: parts,
|
|
}
|
|
}
|
|
|
|
type VirtualLinePart struct {
|
|
// This is the true location of the text
|
|
LocationRange
|
|
|
|
Text string
|
|
}
|
|
|
|
func (p VirtualLinePart) AsTrimmed() VirtualLinePart {
|
|
firstNonWhitespace := utils.FindFirstNonMatch(p.Text, UnicodeWhitespace, 0)
|
|
|
|
if firstNonWhitespace == -1 {
|
|
// Empty line
|
|
return p
|
|
}
|
|
|
|
lastNonWhitespace := utils.FindLastNonMatch(p.Text, UnicodeWhitespace, len(p.Text)-1)
|
|
|
|
if lastNonWhitespace == -1 {
|
|
lastNonWhitespace = len(p.Text) - 1
|
|
}
|
|
|
|
return VirtualLinePart{
|
|
LocationRange: LocationRange{
|
|
Start: Location{
|
|
Line: p.Start.Line,
|
|
Character: p.Start.Character + uint32(firstNonWhitespace),
|
|
},
|
|
End: Location{
|
|
Line: p.Start.Line,
|
|
Character: p.Start.Character + uint32(lastNonWhitespace) + 1,
|
|
},
|
|
},
|
|
Text: p.Text[firstNonWhitespace : lastNonWhitespace+1],
|
|
}
|
|
}
|
|
|
|
func SplitIntoVirtualLines(input string) []VirtualLine {
|
|
stringLines := utils.SplitIntoVirtualLines(input)
|
|
|
|
lines := make([]VirtualLine, 0, len(stringLines))
|
|
|
|
for rawLineNumber, line := range stringLines {
|
|
parts := make([]VirtualLinePart, 0)
|
|
|
|
for virtualLineNumber, part := range line {
|
|
if part == "" {
|
|
continue
|
|
}
|
|
|
|
lineNumber := uint32(rawLineNumber) + uint32(virtualLineNumber)
|
|
|
|
parts = append(parts, VirtualLinePart{
|
|
LocationRange: LocationRange{
|
|
Start: Location{
|
|
Line: lineNumber,
|
|
Character: 0,
|
|
},
|
|
End: Location{
|
|
Line: lineNumber,
|
|
Character: uint32(len(part)),
|
|
},
|
|
},
|
|
Text: part,
|
|
})
|
|
}
|
|
|
|
if len(parts) == 0 {
|
|
continue
|
|
}
|
|
|
|
lines = append(lines, VirtualLine{
|
|
LocationRange: LocationRange{
|
|
Start: parts[0].Start,
|
|
End: parts[len(parts)-1].End,
|
|
},
|
|
Parts: parts,
|
|
})
|
|
}
|
|
|
|
return lines
|
|
}
|