Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add gitconfig #19

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion server/common/parser/strings.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package parser

import "strings"
import (
"regexp"
"strings"
)

type ParseFeatures struct {
ParseDoubleQuotes bool
ParseEscapedCharacters bool
TrimWhitespace bool
Replacements *map[string]string
}

var FullFeatures = ParseFeatures{
ParseDoubleQuotes: true,
ParseEscapedCharacters: true,
TrimWhitespace: false,
Replacements: &map[string]string{},
}

Expand All @@ -29,6 +34,10 @@ func ParseRawString(
value = ParseReplacements(value, *features.Replacements)
}

if features.TrimWhitespace {
value = TrimWhitespace(value, features.ParseDoubleQuotes)
}

// Parse double quotes
if features.ParseDoubleQuotes {
value = ParseDoubleQuotes(value)
Expand All @@ -45,6 +54,55 @@ func ParseRawString(
}
}

var trimPattern = regexp.MustCompile(`\s+`)

func TrimWhitespace(
raw string,
respectDoubleQuotes bool,
) string {
if !respectDoubleQuotes {
return trimPattern.ReplaceAllString(
strings.TrimSpace(raw),
" ",
)
}

value := strings.TrimSpace(raw)
currentIndex := 0

for {
nextStart, found := findNextDoubleQuote(value, currentIndex)

if found {
part := trimPattern.ReplaceAllString(
value[:nextStart],
" ",
)

value = modifyString(value, 0, nextStart, part)
} else {
break
}

nextEnd, found := findNextDoubleQuote(value, nextStart+1)

if !found {
break
}

currentIndex = nextEnd + 1
}

// last part
if currentIndex < len(value) {
part := value[currentIndex:]

value = modifyString(value, currentIndex, len(value), part)
}

return value
}

func ParseDoubleQuotes(
raw string,
) string {
Expand Down
26 changes: 26 additions & 0 deletions server/common/parser/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,32 @@ func TestStringsMultipleQuotesFullFeatures(
}
}

func TestTrimWhitespaceNoQuotes(
t *testing.T,
) {
input := " hello world "
expected := "hello world"

actual := TrimWhitespace(input, false)

if expected != actual {
t.Errorf("Expected %v, got %v", expected, actual)
}
}

func TestTrimWhitespaceQuotes(
t *testing.T,
) {
input := ` "hello world" `
expected := `"hello world"`

actual := TrimWhitespace(input, true)

if expected != actual {
t.Errorf("Expected %v, got %v", expected, actual)
}
}

func TestStringsSimpleEscapedFullFeatures(
t *testing.T,
) {
Expand Down
23 changes: 23 additions & 0 deletions server/common/strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package common

var UnicodeWhitespace = map[rune]struct{}{
'\u0020': {}, // Space
'\u0009': {}, // Horizontal tab
'\u000A': {}, // Line feed
'\u000B': {}, // Vertical tab
'\u000C': {}, // Form feed
'\u000D': {}, // Carriage return
'\u0085': {}, // Next line
'\u00A0': {}, // No-break space
'\u1680': {}, // Ogham space mark
'\u2000': {}, // En quad
'\u2001': {}, // Em quad
'\u2002': {}, // En space
'\u2003': {}, // Em space
'\u2004': {}, // Three-per-em space
'\u2005': {}, // Four-per-em space
'\u2006': {}, // Six-per-em space
'\u2007': {}, // Figure space
'\u2008': {}, // Punctuation space
'\u2009': {}, // Thin space
}
211 changes: 211 additions & 0 deletions server/common/virtual-line.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
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
}
Loading