config-lsp/server/common/virtual-line.go
2024-10-12 16:53:01 +02:00

212 lines
4.6 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 {
// End of the part
rangeEnd = partEnd - partStart
}
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
// }
//
// var text string
// lastNonWhitespace := utils.FindLastNonMatch(p.Text, UnicodeWhitespace, len(p.Text)-1)
//
// // Allow one space at the end
// if lastNonWhitespace == -1 {
// lastNonWhitespace = len(p.Text) - 1
// text = p.Text[firstNonWhitespace:]
// } else {
// text = p.Text[firstNonWhitespace : lastNonWhitespace+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: text,
// }
// }
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
}