mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
refactor(fstab): Overall refactoring to new style
This commit is contained in:
parent
716440cf4c
commit
41239654c8
30
server/handlers/fstab/analyzer/analyzer.go
Normal file
30
server/handlers/fstab/analyzer/analyzer.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/fstab/shared"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
type analyzerContext struct {
|
||||||
|
document *shared.FstabDocument
|
||||||
|
diagnostics []protocol.Diagnostic
|
||||||
|
}
|
||||||
|
|
||||||
|
func Analyze(
|
||||||
|
document *shared.FstabDocument,
|
||||||
|
) []protocol.Diagnostic {
|
||||||
|
ctx := analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeFieldAreFilled(&ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) > 0 {
|
||||||
|
return ctx.diagnostics
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeValuesAreValid(&ctx)
|
||||||
|
|
||||||
|
return ctx.diagnostics
|
||||||
|
}
|
131
server/handlers/fstab/analyzer/fields.go
Normal file
131
server/handlers/fstab/analyzer/fields.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/fstab/ast"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func analyzeFieldAreFilled(
|
||||||
|
ctx *analyzerContext,
|
||||||
|
) {
|
||||||
|
it := ctx.document.Config.Entries.Iterator()
|
||||||
|
for it.Next() {
|
||||||
|
entry := it.Value().(*ast.FstabEntry)
|
||||||
|
|
||||||
|
if entry.Fields.Spec == nil || entry.Fields.Spec.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: 0,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The spec field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Fields.MountPoint == nil || entry.Fields.MountPoint.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Spec.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Spec.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The mount point field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Fields.FilesystemType == nil || entry.Fields.FilesystemType.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.MountPoint.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.MountPoint.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The file system type field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Fields.Options == nil || entry.Fields.Options.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.FilesystemType.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.FilesystemType.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The options field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Fields.Freq == nil || entry.Fields.Freq.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Options.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Options.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The freq field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Fields.Pass == nil || entry.Fields.Pass.Value.Value == "" {
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: protocol.Range{
|
||||||
|
Start: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Freq.End.Character,
|
||||||
|
},
|
||||||
|
End: protocol.Position{
|
||||||
|
Line: entry.Fields.Start.Line,
|
||||||
|
Character: entry.Fields.Freq.End.Character,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "The pass field is missing",
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
server/handlers/fstab/analyzer/fields_test.go
Normal file
38
server/handlers/fstab/analyzer/fields_test.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
testutils_test "config-lsp/handlers/fstab/test_utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFieldsMissingMountPoint(t *testing.T) {
|
||||||
|
document := testutils_test.DocumentFromInput(t, `
|
||||||
|
LABEL=test
|
||||||
|
`)
|
||||||
|
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeFieldAreFilled(ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) != 1 {
|
||||||
|
t.Fatalf("Expected 1 diagnostic, got %d", len(ctx.diagnostics))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidExample(t *testing.T) {
|
||||||
|
document := testutils_test.DocumentFromInput(t, `
|
||||||
|
LABEL=test /mnt/test ext4 defaults 0 0
|
||||||
|
`)
|
||||||
|
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeFieldAreFilled(ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) != 0 {
|
||||||
|
t.Fatalf("Expected 0 diagnostics, got %d", len(ctx.diagnostics))
|
||||||
|
}
|
||||||
|
}
|
46
server/handlers/fstab/analyzer/values.go
Normal file
46
server/handlers/fstab/analyzer/values.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
docvalues "config-lsp/doc-values"
|
||||||
|
"config-lsp/handlers/fstab/ast"
|
||||||
|
"config-lsp/handlers/fstab/fields"
|
||||||
|
|
||||||
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
|
)
|
||||||
|
|
||||||
|
func analyzeValuesAreValid(
|
||||||
|
ctx *analyzerContext,
|
||||||
|
) {
|
||||||
|
it := ctx.document.Config.Entries.Iterator()
|
||||||
|
|
||||||
|
for it.Next() {
|
||||||
|
entry := it.Value().(*ast.FstabEntry)
|
||||||
|
|
||||||
|
checkField(ctx, entry.Fields.Spec, fields.SpecField)
|
||||||
|
checkField(ctx, entry.Fields.MountPoint, fields.MountPointField)
|
||||||
|
checkField(ctx, entry.Fields.FilesystemType, fields.FileSystemTypeField)
|
||||||
|
checkField(ctx, entry.Fields.Options, entry.GetMountOptionsField())
|
||||||
|
checkField(ctx, entry.Fields.Freq, fields.FreqField)
|
||||||
|
checkField(ctx, entry.Fields.Pass, fields.PassField)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkField(
|
||||||
|
ctx *analyzerContext,
|
||||||
|
field *ast.FstabField,
|
||||||
|
docOption docvalues.DeprecatedValue,
|
||||||
|
) {
|
||||||
|
invalidValues := docOption.DeprecatedCheckIsValid(field.Value.Value)
|
||||||
|
|
||||||
|
for _, invalidValue := range invalidValues {
|
||||||
|
err := docvalues.LSPErrorFromInvalidValue(field.Start.Line, *invalidValue)
|
||||||
|
err.ShiftCharacter(field.Start.Character)
|
||||||
|
|
||||||
|
ctx.diagnostics = append(ctx.diagnostics, protocol.Diagnostic{
|
||||||
|
Range: err.Range.ToLSPRange(),
|
||||||
|
Message: err.Err.Error(),
|
||||||
|
Severity: &common.SeverityError,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
61
server/handlers/fstab/analyzer/values_test.go
Normal file
61
server/handlers/fstab/analyzer/values_test.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package analyzer
|
||||||
|
|
||||||
|
import (
|
||||||
|
testutils_test "config-lsp/handlers/fstab/test_utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInvalidMountOptionsExample(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
document := testutils_test.DocumentFromInput(t, `
|
||||||
|
LABEL=test /mnt/test ext4 invalid 0 0
|
||||||
|
`)
|
||||||
|
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeValuesAreValid(ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) == 0 {
|
||||||
|
t.Fatalf("Expected diagnostic, got %d", len(ctx.diagnostics))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExt4IsUsingBtrfsMountOption(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
document := testutils_test.DocumentFromInput(t, `
|
||||||
|
# Valid, but only for btrfs
|
||||||
|
LABEL=test /mnt/test ext4 subvolid=1 0 0
|
||||||
|
`)
|
||||||
|
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeValuesAreValid(ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) == 0 {
|
||||||
|
t.Fatalf("Expected diagnostic, got %d", len(ctx.diagnostics))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidBtrfsIsUsingBtrfsMountOption(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
document := testutils_test.DocumentFromInput(t, `
|
||||||
|
LABEL=test /mnt/test btrfs subvolid=1 0 0
|
||||||
|
`)
|
||||||
|
|
||||||
|
ctx := &analyzerContext{
|
||||||
|
document: document,
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzeValuesAreValid(ctx)
|
||||||
|
|
||||||
|
if len(ctx.diagnostics) != 0 {
|
||||||
|
t.Fatalf("Expected diagnostic, got %d", len(ctx.diagnostics))
|
||||||
|
}
|
||||||
|
}
|
@ -43,4 +43,3 @@ type FstabConfig struct {
|
|||||||
// [uint32]{} - line number to empty struct for comments
|
// [uint32]{} - line number to empty struct for comments
|
||||||
CommentLines map[uint32]struct{}
|
CommentLines map[uint32]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
|
docvalues "config-lsp/doc-values"
|
||||||
|
"config-lsp/handlers/fstab/fields"
|
||||||
|
)
|
||||||
|
|
||||||
// func (c FstabConfig) GetEntry(line uint32) *FstabEntry {
|
// func (c FstabConfig) GetEntry(line uint32) *FstabEntry {
|
||||||
// entry, found := c.Entries.Get(line)
|
// entry, found := c.Entries.Get(line)
|
||||||
//
|
//
|
||||||
@ -10,26 +16,40 @@ package ast
|
|||||||
// return entry.(*FstabEntry)
|
// return entry.(*FstabEntry)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (e FstabEntry) GetFieldAtPosition(cursor uint32) FstabFieldName {
|
func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName {
|
||||||
if e.Fields.Spec == nil || (cursor >= e.Fields.Spec.Start.Character && cursor <= e.Fields.Spec.End.Character) {
|
if e.Fields.Spec == nil || (e.Fields.Spec.ContainsPosition(position)) {
|
||||||
return FstabFieldSpec
|
return FstabFieldSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Fields.MountPoint == nil || (cursor >= e.Fields.MountPoint.Start.Character && cursor <= e.Fields.MountPoint.End.Character) {
|
if e.Fields.MountPoint == nil || (e.Fields.MountPoint.ContainsPosition(position)) {
|
||||||
return FstabFieldMountPoint
|
return FstabFieldMountPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Fields.FilesystemType == nil || (cursor >= e.Fields.FilesystemType.Start.Character && cursor <= e.Fields.FilesystemType.End.Character) {
|
if e.Fields.FilesystemType == nil || (e.Fields.FilesystemType.ContainsPosition(position)) {
|
||||||
return FstabFieldFileSystemType
|
return FstabFieldFileSystemType
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Fields.Options == nil || (cursor >= e.Fields.Options.Start.Character && cursor <= e.Fields.Options.End.Character) {
|
if e.Fields.Options == nil || (e.Fields.Options.ContainsPosition(position)) {
|
||||||
return FstabFieldOptions
|
return FstabFieldOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.Fields.Freq == nil || (cursor >= e.Fields.Freq.Start.Character && cursor <= e.Fields.Freq.End.Character) {
|
if e.Fields.Freq == nil || (e.Fields.Freq.ContainsPosition(position)) {
|
||||||
return FstabFieldFreq
|
return FstabFieldFreq
|
||||||
}
|
}
|
||||||
|
|
||||||
return FstabFieldPass
|
return FstabFieldPass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e FstabEntry) GetMountOptionsField() docvalues.DeprecatedValue {
|
||||||
|
fileSystemType := e.Fields.FilesystemType.Value.Value
|
||||||
|
|
||||||
|
var optionsField docvalues.DeprecatedValue
|
||||||
|
|
||||||
|
if foundField, found := fields.MountOptionsMapField[fileSystemType]; found {
|
||||||
|
optionsField = foundField
|
||||||
|
} else {
|
||||||
|
optionsField = fields.DefaultMountOptionsField
|
||||||
|
}
|
||||||
|
|
||||||
|
return optionsField
|
||||||
|
}
|
||||||
|
@ -88,21 +88,45 @@ func (c *FstabConfig) parseStatement(
|
|||||||
fallthrough
|
fallthrough
|
||||||
case 5:
|
case 5:
|
||||||
freq = parseField(line, input, fields[4])
|
freq = parseField(line, input, fields[4])
|
||||||
|
|
||||||
|
if pass == nil && fields[4][1] < len(input) {
|
||||||
|
pass = createPartialField(line, input, fields[4][1], len(input))
|
||||||
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case 4:
|
case 4:
|
||||||
options = parseField(line, input, fields[3])
|
options = parseField(line, input, fields[3])
|
||||||
|
|
||||||
|
if freq == nil && fields[3][1] < len(input) {
|
||||||
|
freq = createPartialField(line, input, fields[3][1], len(input))
|
||||||
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case 3:
|
case 3:
|
||||||
filesystemType = parseField(line, input, fields[2])
|
filesystemType = parseField(line, input, fields[2])
|
||||||
|
|
||||||
|
if options == nil && fields[2][1] < len(input) {
|
||||||
|
options = createPartialField(line, input, fields[2][1], len(input))
|
||||||
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case 2:
|
case 2:
|
||||||
mountPoint = parseField(line, input, fields[1])
|
mountPoint = parseField(line, input, fields[1])
|
||||||
|
|
||||||
|
if filesystemType == nil && fields[1][1] < len(input) {
|
||||||
|
filesystemType = createPartialField(line, input, fields[1][1], len(input))
|
||||||
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case 1:
|
case 1:
|
||||||
spec = parseField(line, input, fields[0])
|
spec = parseField(line, input, fields[0])
|
||||||
|
|
||||||
|
if mountPoint == nil && fields[0][1] < len(input) {
|
||||||
|
mountPoint = createPartialField(line, input, fields[0][1], len(input))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fstabLine := FstabEntry{
|
fstabLine := &FstabEntry{
|
||||||
Fields: FstabFields{
|
Fields: FstabFields{
|
||||||
LocationRange: common.LocationRange{
|
LocationRange: common.LocationRange{
|
||||||
Start: common.Location{
|
Start: common.Location{
|
||||||
@ -157,3 +181,29 @@ func parseField(
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createPartialField(
|
||||||
|
line uint32,
|
||||||
|
input string,
|
||||||
|
start int,
|
||||||
|
end int,
|
||||||
|
) *FstabField {
|
||||||
|
return nil
|
||||||
|
return &FstabField{
|
||||||
|
LocationRange: common.LocationRange{
|
||||||
|
Start: common.Location{
|
||||||
|
Line: line,
|
||||||
|
Character: uint32(start),
|
||||||
|
},
|
||||||
|
End: common.Location{
|
||||||
|
Line: line,
|
||||||
|
Character: uint32(end),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Value: commonparser.ParseRawString(input[end:end], commonparser.ParseFeatures{
|
||||||
|
ParseEscapedCharacters: true,
|
||||||
|
ParseDoubleQuotes: true,
|
||||||
|
Replacements: &map[string]string{},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -24,7 +25,7 @@ LABEL=test /mnt/test ext4 defaults 0 0
|
|||||||
}
|
}
|
||||||
|
|
||||||
rawFirstEntry, _ := c.Entries.Get(uint32(0))
|
rawFirstEntry, _ := c.Entries.Get(uint32(0))
|
||||||
firstEntry := rawFirstEntry.(FstabEntry)
|
firstEntry := rawFirstEntry.(*FstabEntry)
|
||||||
if !(firstEntry.Fields.Spec.Value.Value == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Value == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Value == "ext4" && firstEntry.Fields.Options.Value.Value == "defaults" && firstEntry.Fields.Freq.Value.Value == "0" && firstEntry.Fields.Pass.Value.Value == "0") {
|
if !(firstEntry.Fields.Spec.Value.Value == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Value == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Value == "ext4" && firstEntry.Fields.Options.Value.Value == "defaults" && firstEntry.Fields.Freq.Value.Value == "0" && firstEntry.Fields.Pass.Value.Value == "0") {
|
||||||
t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults 0 0, got %v", firstEntry)
|
t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults 0 0, got %v", firstEntry)
|
||||||
}
|
}
|
||||||
@ -72,4 +73,66 @@ LABEL=test /mnt/test ext4 defaults 0 0
|
|||||||
if !(firstEntry.Fields.Pass.LocationRange.Start.Line == 0 && firstEntry.Fields.Pass.LocationRange.Start.Character == 37) {
|
if !(firstEntry.Fields.Pass.LocationRange.Start.Line == 0 && firstEntry.Fields.Pass.LocationRange.Start.Character == 37) {
|
||||||
t.Errorf("Expected pass start to be 0:37, got %v", firstEntry.Fields.Pass.LocationRange.Start)
|
t.Errorf("Expected pass start to be 0:37, got %v", firstEntry.Fields.Pass.LocationRange.Start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
field := firstEntry.GetFieldAtPosition(common.IndexPosition(0))
|
||||||
|
if !(field == FstabFieldSpec) {
|
||||||
|
t.Errorf("Expected field to be spec, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(11))
|
||||||
|
if !(field == FstabFieldMountPoint) {
|
||||||
|
t.Errorf("Expected field to be mountpoint, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(33))
|
||||||
|
if !(field == FstabFieldOptions) {
|
||||||
|
t.Errorf("Expected field to be spec, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(35))
|
||||||
|
if !(field == FstabFieldFreq) {
|
||||||
|
t.Errorf("Expected field to be freq, got %v", field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIncompleteExample(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
input := utils.Dedent(`
|
||||||
|
LABEL=test /mnt/test ext4 defaults
|
||||||
|
`)
|
||||||
|
c := NewFstabConfig()
|
||||||
|
|
||||||
|
errors := c.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) != 0 {
|
||||||
|
t.Fatalf("Expected no errors, got %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawFirstEntry, _ := c.Entries.Get(uint32(0))
|
||||||
|
firstEntry := rawFirstEntry.(*FstabEntry)
|
||||||
|
|
||||||
|
if !(firstEntry.Fields.Spec.Value.Raw == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Raw == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Raw == "ext4" && firstEntry.Fields.Options.Value.Raw == "defaults") {
|
||||||
|
t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults, got %v", firstEntry)
|
||||||
|
}
|
||||||
|
|
||||||
|
field := firstEntry.GetFieldAtPosition(common.IndexPosition(0))
|
||||||
|
if !(field == FstabFieldSpec) {
|
||||||
|
t.Errorf("Expected field to be spec, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(11))
|
||||||
|
if !(field == FstabFieldMountPoint) {
|
||||||
|
t.Errorf("Expected field to be mountpoint, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(33))
|
||||||
|
if !(field == FstabFieldOptions) {
|
||||||
|
t.Errorf("Expected field to be spec, got %v", field)
|
||||||
|
}
|
||||||
|
|
||||||
|
field = firstEntry.GetFieldAtPosition(common.IndexPosition(35))
|
||||||
|
if !(field == FstabFieldFreq) {
|
||||||
|
t.Errorf("Expected field to be freq, got %v", field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import docvalues "config-lsp/doc-values"
|
import docvalues "config-lsp/doc-values"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import (
|
import (
|
||||||
docvalues "config-lsp/doc-values"
|
docvalues "config-lsp/doc-values"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import (
|
import (
|
||||||
commondocumentation "config-lsp/common-documentation"
|
commondocumentation "config-lsp/common-documentation"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import docvalues "config-lsp/doc-values"
|
import docvalues "config-lsp/doc-values"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import (
|
import (
|
||||||
docvalues "config-lsp/doc-values"
|
docvalues "config-lsp/doc-values"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fstabdocumentation
|
package fields
|
||||||
|
|
||||||
import (
|
import (
|
||||||
docvalues "config-lsp/doc-values"
|
docvalues "config-lsp/doc-values"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package fstab
|
package fstab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
fstabdocumentation "config-lsp/handlers/fstab/fields"
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/fstab/ast"
|
||||||
|
fields "config-lsp/handlers/fstab/fields"
|
||||||
handlers "config-lsp/handlers/fstab/handlers"
|
handlers "config-lsp/handlers/fstab/handlers"
|
||||||
"config-lsp/handlers/fstab/parser"
|
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -12,22 +13,21 @@ func TestValidBasicExample(t *testing.T) {
|
|||||||
input := utils.Dedent(`
|
input := utils.Dedent(`
|
||||||
LABEL=test /mnt/test ext4 defaults 0 0
|
LABEL=test /mnt/test ext4 defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatal("ParseFromContent failed with error", errors)
|
t.Fatal("Parse failed with error", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get hover for first field
|
// Get hover for first field
|
||||||
rawEntry, _ := p.Entries.Get(uint32(0))
|
rawEntry, _ := p.Entries.Get(uint32(0))
|
||||||
entry := rawEntry.(parser.FstabEntry)
|
entry := rawEntry.(*ast.FstabEntry)
|
||||||
|
|
||||||
println("Getting hover info")
|
println("Getting hover info")
|
||||||
{
|
{
|
||||||
hover, err := handlers.GetHoverInfo(&entry, uint32(0))
|
hover, err := handlers.GetHoverInfo(uint32(0), common.IndexPosition(0), entry)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getHoverInfo failed with error", err)
|
t.Fatal("getHoverInfo failed with error", err)
|
||||||
@ -38,7 +38,7 @@ LABEL=test /mnt/test ext4 defaults 0 0
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get hover for second field
|
// Get hover for second field
|
||||||
hover, err = handlers.GetHoverInfo(&entry, uint32(11))
|
hover, err = handlers.GetHoverInfo(uint32(0), common.IndexPosition(11), entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getHoverInfo failed with error", err)
|
t.Fatal("getHoverInfo failed with error", err)
|
||||||
}
|
}
|
||||||
@ -47,20 +47,16 @@ LABEL=test /mnt/test ext4 defaults 0 0
|
|||||||
t.Fatal("getHoverInfo failed to return correct hover content. Got:", hover.Contents, "but expected:", handlers.MountPointHoverField.Contents)
|
t.Fatal("getHoverInfo failed to return correct hover content. Got:", hover.Contents, "but expected:", handlers.MountPointHoverField.Contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
hover, err = handlers.GetHoverInfo(&entry, uint32(20))
|
hover, err = handlers.GetHoverInfo(uint32(0), common.IndexPosition(20), entry)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getHoverInfo failed with error", err)
|
t.Fatal("getHoverInfo failed with error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hover.Contents != handlers.MountPointHoverField.Contents {
|
|
||||||
t.Fatal("getHoverInfo failed to return correct hover content. Got:", hover.Contents, "but expected:", handlers.MountPointHoverField.Contents)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Getting completions")
|
println("Getting completions")
|
||||||
{
|
{
|
||||||
completions, err := handlers.GetCompletion(entry.Line, uint32(0))
|
completions, err := handlers.GetCompletion(entry, common.CursorPosition(0))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getCompletion failed with error", err)
|
t.Fatal("getCompletion failed with error", err)
|
||||||
@ -79,50 +75,30 @@ LABEL=test /mnt/test ext4 defaults 0 0
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
completions, err := handlers.GetCompletion(entry.Line, uint32(21))
|
completions, err := handlers.GetCompletion(entry, common.CursorPosition(23))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("getCompletion failed with error", err)
|
t.Fatal("getCompletion failed with error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedLength := len(utils.KeysOfMap(fstabdocumentation.MountOptionsMapField))
|
expectedLength := len(utils.KeysOfMap(fields.MountOptionsMapField))
|
||||||
if len(completions) != expectedLength {
|
if len(completions) != expectedLength {
|
||||||
t.Fatal("getCompletion failed to return correct number of completions. Got:", len(completions), "but expected:", expectedLength)
|
t.Fatal("getCompletion failed to return correct number of completions. Got:", len(completions), "but expected:", expectedLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Checking values")
|
|
||||||
{
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Fatal("AnalyzeValues failed with error", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidOptionsExample(t *testing.T) {
|
func TestInvalidOptionsExample(t *testing.T) {
|
||||||
input := utils.Dedent(`
|
input := utils.Dedent(`
|
||||||
LABEL=test /mnt/test btrfs subvol=backup,fat=32 0 0
|
LABEL=test /mnt/test btrfs subvol=backup,fat=32 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatal("ParseFromContent returned error", errors)
|
t.Fatal("ParseFromContent returned error", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get hover for first field
|
|
||||||
println("Checking values")
|
|
||||||
{
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) == 0 {
|
|
||||||
t.Fatal("AnalyzeValues should have returned error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestExample1(t *testing.T) {
|
// func TestExample1(t *testing.T) {
|
||||||
@ -150,20 +126,14 @@ UUID=0a3407de-014b-458b-b5c1-848e92a327a3 / ext4 defaults 0 1
|
|||||||
UUID=f9fe0b69-a280-415d-a03a-a32752370dee none swap defaults 0 0
|
UUID=f9fe0b69-a280-415d-a03a-a32752370dee none swap defaults 0 0
|
||||||
UUID=b411dc99-f0a0-4c87-9e05-184977be8539 /home ext4 defaults 0 2
|
UUID=b411dc99-f0a0-4c87-9e05-184977be8539 /home ext4 defaults 0 2
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchExample2(t *testing.T) {
|
func TestArchExample2(t *testing.T) {
|
||||||
@ -173,10 +143,9 @@ func TestArchExample2(t *testing.T) {
|
|||||||
/dev/sda3 /home ext4 defaults 0 2
|
/dev/sda3 /home ext4 defaults 0 2
|
||||||
/dev/sda4 none swap defaults 0 0
|
/dev/sda4 none swap defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
@ -190,20 +159,14 @@ LABEL=System / ext4 defaults 0 1
|
|||||||
LABEL=Data /home ext4 defaults 0 2
|
LABEL=Data /home ext4 defaults 0 2
|
||||||
LABEL=Swap none swap defaults 0 0
|
LABEL=Swap none swap defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchExample4(t *testing.T) {
|
func TestArchExample4(t *testing.T) {
|
||||||
@ -213,20 +176,13 @@ UUID=0a3407de-014b-458b-b5c1-848e92a327a3 / ext4 defaults 0 1
|
|||||||
UUID=b411dc99-f0a0-4c87-9e05-184977be8539 /home ext4 defaults 0 2
|
UUID=b411dc99-f0a0-4c87-9e05-184977be8539 /home ext4 defaults 0 2
|
||||||
UUID=f9fe0b69-a280-415d-a03a-a32752370dee none swap defaults 0 0
|
UUID=f9fe0b69-a280-415d-a03a-a32752370dee none swap defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchExample5(t *testing.T) {
|
func TestArchExample5(t *testing.T) {
|
||||||
@ -236,20 +192,13 @@ PARTLABEL=GNU/Linux / ext4 defaults 0 1
|
|||||||
PARTLABEL=Home /home ext4 defaults 0 2
|
PARTLABEL=Home /home ext4 defaults 0 2
|
||||||
PARTLABEL=Swap none swap defaults 0 0
|
PARTLABEL=Swap none swap defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArchExample6(t *testing.T) {
|
func TestArchExample6(t *testing.T) {
|
||||||
@ -259,60 +208,39 @@ PARTUUID=98a81274-10f7-40db-872a-03df048df366 / ext4 defaults 0 1
|
|||||||
PARTUUID=7280201c-fc5d-40f2-a9b2-466611d3d49e /home ext4 defaults 0 2
|
PARTUUID=7280201c-fc5d-40f2-a9b2-466611d3d49e /home ext4 defaults 0 2
|
||||||
PARTUUID=039b6c1c-7553-4455-9537-1befbc9fbc5b none swap defaults 0 0
|
PARTUUID=039b6c1c-7553-4455-9537-1befbc9fbc5b none swap defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLinuxConfigExample(t *testing.T) {
|
func TestLinuxConfigExample(t *testing.T) {
|
||||||
input := utils.Dedent(`
|
input := utils.Dedent(`
|
||||||
UUID=80b496fa-ce2d-4dcf-9afc-bcaa731a67f1 /mnt/example ext4 defaults 0 2
|
UUID=80b496fa-ce2d-4dcf-9afc-bcaa731a67f1 /mnt/example ext4 defaults 0 2
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test1(t *testing.T) {
|
func Test1(t *testing.T) {
|
||||||
input := utils.Dedent(`
|
input := utils.Dedent(`
|
||||||
PARTLABEL="rootfs" / ext4 noatime,lazytime,rw 0 0
|
PARTLABEL="rootfs" / ext4 noatime,lazytime,rw 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics := p.AnalyzeValues()
|
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
|
||||||
t.Errorf("AnalyzeValues failed with error %v", diagnostics)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test2(t *testing.T) {
|
func Test2(t *testing.T) {
|
||||||
@ -323,10 +251,9 @@ func Test2(t *testing.T) {
|
|||||||
/dev/sdd /homeD xfs noauto,rw,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
|
/dev/sdd /homeD xfs noauto,rw,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
|
||||||
/dev/sde /homeE xfs defaults 0 0
|
/dev/sde /homeE xfs defaults 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
@ -344,10 +271,9 @@ func Test3(t *testing.T) {
|
|||||||
tmpfs /var tmpfs rw,nosuid,nodev,size=128M,mode=755 0 0
|
tmpfs /var tmpfs rw,nosuid,nodev,size=128M,mode=755 0 0
|
||||||
tmpfs /tmp tmpfs rw,nosuid,nodev,size=150M,mode=1777 0 0
|
tmpfs /tmp tmpfs rw,nosuid,nodev,size=150M,mode=1777 0 0
|
||||||
`)
|
`)
|
||||||
p := parser.FstabParser{}
|
p := ast.NewFstabConfig()
|
||||||
p.Clear()
|
|
||||||
|
|
||||||
errors := p.ParseFromContent(input)
|
errors := p.Parse(input)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
t.Fatalf("ParseFromContent failed with error %v", errors)
|
t.Fatalf("ParseFromContent failed with error %v", errors)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
"config-lsp/doc-values"
|
"config-lsp/doc-values"
|
||||||
"config-lsp/handlers/fstab/ast"
|
"config-lsp/handlers/fstab/ast"
|
||||||
"config-lsp/handlers/fstab/fields"
|
"config-lsp/handlers/fstab/fields"
|
||||||
@ -10,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func GetCompletion(
|
func GetCompletion(
|
||||||
entry *ast.FstabEntry,
|
entry *ast.FstabEntry,
|
||||||
cursor uint32,
|
cursor common.CursorPosition,
|
||||||
) ([]protocol.CompletionItem, error) {
|
) ([]protocol.CompletionItem, error) {
|
||||||
targetField := entry.GetFieldAtPosition(cursor)
|
targetField := entry.GetFieldAtPosition(cursor)
|
||||||
|
|
||||||
@ -18,21 +19,21 @@ func GetCompletion(
|
|||||||
case ast.FstabFieldSpec:
|
case ast.FstabFieldSpec:
|
||||||
value, cursor := getFieldSafely(entry.Fields.Spec, cursor)
|
value, cursor := getFieldSafely(entry.Fields.Spec, cursor)
|
||||||
|
|
||||||
return fstabdocumentation.SpecField.DeprecatedFetchCompletions(
|
return fields.SpecField.DeprecatedFetchCompletions(
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
), nil
|
), nil
|
||||||
case ast.FstabFieldMountPoint:
|
case ast.FstabFieldMountPoint:
|
||||||
value, cursor := getFieldSafely(entry.Fields.MountPoint, cursor)
|
value, cursor := getFieldSafely(entry.Fields.MountPoint, cursor)
|
||||||
|
|
||||||
return fstabdocumentation.MountPointField.DeprecatedFetchCompletions(
|
return fields.MountPointField.DeprecatedFetchCompletions(
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
), nil
|
), nil
|
||||||
case ast.FstabFieldFileSystemType:
|
case ast.FstabFieldFileSystemType:
|
||||||
value, cursor := getFieldSafely(entry.Fields.FilesystemType, cursor)
|
value, cursor := getFieldSafely(entry.Fields.FilesystemType, cursor)
|
||||||
|
|
||||||
return fstabdocumentation.FileSystemTypeField.DeprecatedFetchCompletions(
|
return fields.FileSystemTypeField.DeprecatedFetchCompletions(
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
), nil
|
), nil
|
||||||
@ -41,10 +42,10 @@ func GetCompletion(
|
|||||||
|
|
||||||
var optionsField docvalues.DeprecatedValue
|
var optionsField docvalues.DeprecatedValue
|
||||||
|
|
||||||
if foundField, found := fstabdocumentation.MountOptionsMapField[fileSystemType]; found {
|
if foundField, found := fields.MountOptionsMapField[fileSystemType]; found {
|
||||||
optionsField = foundField
|
optionsField = foundField
|
||||||
} else {
|
} else {
|
||||||
optionsField = fstabdocumentation.DefaultMountOptionsField
|
optionsField = fields.DefaultMountOptionsField
|
||||||
}
|
}
|
||||||
|
|
||||||
value, cursor := getFieldSafely(entry.Fields.Options, cursor)
|
value, cursor := getFieldSafely(entry.Fields.Options, cursor)
|
||||||
@ -58,14 +59,14 @@ func GetCompletion(
|
|||||||
case ast.FstabFieldFreq:
|
case ast.FstabFieldFreq:
|
||||||
value, cursor := getFieldSafely(entry.Fields.Freq, cursor)
|
value, cursor := getFieldSafely(entry.Fields.Freq, cursor)
|
||||||
|
|
||||||
return fstabdocumentation.FreqField.DeprecatedFetchCompletions(
|
return fields.FreqField.DeprecatedFetchCompletions(
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
), nil
|
), nil
|
||||||
case ast.FstabFieldPass:
|
case ast.FstabFieldPass:
|
||||||
value, cursor := getFieldSafely(entry.Fields.Pass, cursor)
|
value, cursor := getFieldSafely(entry.Fields.Pass, cursor)
|
||||||
|
|
||||||
return fstabdocumentation.PassField.DeprecatedFetchCompletions(
|
return fields.PassField.DeprecatedFetchCompletions(
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
), nil
|
), nil
|
||||||
@ -76,7 +77,7 @@ func GetCompletion(
|
|||||||
|
|
||||||
// Safely get value and new cursor position
|
// Safely get value and new cursor position
|
||||||
// If field is nil, return empty string and 0
|
// If field is nil, return empty string and 0
|
||||||
func getFieldSafely(field *ast.FstabField, character uint32) (string, uint32) {
|
func getFieldSafely(field *ast.FstabField, cursor common.CursorPosition) (string, uint32) {
|
||||||
if field == nil {
|
if field == nil {
|
||||||
return "", 0
|
return "", 0
|
||||||
}
|
}
|
||||||
@ -85,5 +86,5 @@ func getFieldSafely(field *ast.FstabField, character uint32) (string, uint32) {
|
|||||||
return "", 0
|
return "", 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return field.Value.Raw, character - field.Start.Character
|
return field.Value.Raw, common.CursorToCharacterIndex(uint32(cursor)) - field.Start.Character
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
"config-lsp/doc-values"
|
"config-lsp/doc-values"
|
||||||
"config-lsp/handlers/fstab/ast"
|
"config-lsp/handlers/fstab/ast"
|
||||||
"config-lsp/handlers/fstab/fields"
|
"config-lsp/handlers/fstab/fields"
|
||||||
@ -11,10 +12,10 @@ import (
|
|||||||
|
|
||||||
func GetHoverInfo(
|
func GetHoverInfo(
|
||||||
line uint32,
|
line uint32,
|
||||||
cursor uint32,
|
index common.IndexPosition,
|
||||||
entry *ast.FstabEntry,
|
entry *ast.FstabEntry,
|
||||||
) (*protocol.Hover, error) {
|
) (*protocol.Hover, error) {
|
||||||
targetField := entry.GetFieldAtPosition(cursor)
|
targetField := entry.GetFieldAtPosition(index)
|
||||||
|
|
||||||
switch targetField {
|
switch targetField {
|
||||||
case ast.FstabFieldSpec:
|
case ast.FstabFieldSpec:
|
||||||
@ -27,13 +28,13 @@ func GetHoverInfo(
|
|||||||
fileSystemType := entry.Fields.FilesystemType.Value.Value
|
fileSystemType := entry.Fields.FilesystemType.Value.Value
|
||||||
var optionsField docvalues.DeprecatedValue
|
var optionsField docvalues.DeprecatedValue
|
||||||
|
|
||||||
if foundField, found := fstabdocumentation.MountOptionsMapField[fileSystemType]; found {
|
if foundField, found := fields.MountOptionsMapField[fileSystemType]; found {
|
||||||
optionsField = foundField
|
optionsField = foundField
|
||||||
} else {
|
} else {
|
||||||
optionsField = fstabdocumentation.DefaultMountOptionsField
|
optionsField = fields.DefaultMountOptionsField
|
||||||
}
|
}
|
||||||
|
|
||||||
relativeCursor := cursor - entry.Fields.Options.Start.Character
|
relativeCursor := uint32(index) - entry.Fields.Options.Start.Character
|
||||||
fieldInfo := optionsField.DeprecatedFetchHoverInfo(entry.Fields.Options.Value.Value, relativeCursor)
|
fieldInfo := optionsField.DeprecatedFetchHoverInfo(entry.Fields.Options.Value.Value, relativeCursor)
|
||||||
|
|
||||||
hover := protocol.Hover{
|
hover := protocol.Hover{
|
||||||
|
@ -12,9 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
||||||
c := shared.DocumentParserMap[params.TextDocument.URI]
|
d := shared.DocumentParserMap[params.TextDocument.URI]
|
||||||
|
cursor := common.LSPCharacterAsCursorPosition(params.Position.Character)
|
||||||
|
|
||||||
rawEntry, found := c.Entries.Get(params.Position.Line)
|
rawEntry, found := d.Config.Entries.Get(params.Position.Line)
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
// Empty line, return spec completions
|
// Empty line, return spec completions
|
||||||
@ -26,7 +27,5 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
|||||||
|
|
||||||
entry := rawEntry.(*ast.FstabEntry)
|
entry := rawEntry.(*ast.FstabEntry)
|
||||||
|
|
||||||
cursor := common.CursorToCharacterIndex(params.Position.Character)
|
|
||||||
|
|
||||||
return handlers.GetCompletion(entry, cursor)
|
return handlers.GetCompletion(entry, cursor)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ package lsp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/fstab/analyzer"
|
||||||
"config-lsp/handlers/fstab/shared"
|
"config-lsp/handlers/fstab/shared"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
|
|
||||||
"github.com/tliron/glsp"
|
"github.com/tliron/glsp"
|
||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
@ -15,11 +17,11 @@ func TextDocumentDidChange(
|
|||||||
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
||||||
common.ClearDiagnostics(context, params.TextDocument.URI)
|
common.ClearDiagnostics(context, params.TextDocument.URI)
|
||||||
|
|
||||||
p := shared.DocumentParserMap[params.TextDocument.URI]
|
d := shared.DocumentParserMap[params.TextDocument.URI]
|
||||||
p.Clear()
|
d.Config.Clear()
|
||||||
|
|
||||||
diagnostics := make([]protocol.Diagnostic, 0)
|
diagnostics := make([]protocol.Diagnostic, 0)
|
||||||
errors := p.Parse(content)
|
errors := d.Config.Parse(content)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
diagnostics = append(diagnostics, utils.Map(
|
diagnostics = append(diagnostics, utils.Map(
|
||||||
@ -29,7 +31,7 @@ func TextDocumentDidChange(
|
|||||||
},
|
},
|
||||||
)...)
|
)...)
|
||||||
} else {
|
} else {
|
||||||
// diagnostics = append(diagnostics, p.AnalyzeValues()...)
|
diagnostics = append(diagnostics, analyzer.Analyze(d)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
if len(diagnostics) > 0 {
|
||||||
|
@ -2,6 +2,7 @@ package lsp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"config-lsp/common"
|
"config-lsp/common"
|
||||||
|
"config-lsp/handlers/fstab/analyzer"
|
||||||
"config-lsp/handlers/fstab/ast"
|
"config-lsp/handlers/fstab/ast"
|
||||||
"config-lsp/handlers/fstab/shared"
|
"config-lsp/handlers/fstab/shared"
|
||||||
"config-lsp/utils"
|
"config-lsp/utils"
|
||||||
@ -16,13 +17,16 @@ func TextDocumentDidOpen(
|
|||||||
) error {
|
) error {
|
||||||
common.ClearDiagnostics(context, params.TextDocument.URI)
|
common.ClearDiagnostics(context, params.TextDocument.URI)
|
||||||
|
|
||||||
p := ast.NewFstabConfig()
|
config := ast.NewFstabConfig()
|
||||||
shared.DocumentParserMap[params.TextDocument.URI] = p
|
d := &shared.FstabDocument{
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
shared.DocumentParserMap[params.TextDocument.URI] = d
|
||||||
|
|
||||||
content := params.TextDocument.Text
|
content := params.TextDocument.Text
|
||||||
|
|
||||||
diagnostics := make([]protocol.Diagnostic, 0)
|
diagnostics := make([]protocol.Diagnostic, 0)
|
||||||
errors := p.Parse(content)
|
errors := d.Config.Parse(content)
|
||||||
|
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
diagnostics = append(diagnostics, utils.Map(
|
diagnostics = append(diagnostics, utils.Map(
|
||||||
@ -32,7 +36,7 @@ func TextDocumentDidOpen(
|
|||||||
},
|
},
|
||||||
)...)
|
)...)
|
||||||
} else {
|
} else {
|
||||||
// diagnostics = append(diagnostics, p.AnalyzeValues()...)
|
diagnostics = append(diagnostics, analyzer.Analyze(d)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(diagnostics) > 0 {
|
if len(diagnostics) > 0 {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package lsp
|
package lsp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"config-lsp/common"
|
||||||
"config-lsp/handlers/fstab/ast"
|
"config-lsp/handlers/fstab/ast"
|
||||||
"config-lsp/handlers/fstab/handlers"
|
"config-lsp/handlers/fstab/handlers"
|
||||||
"config-lsp/handlers/fstab/shared"
|
"config-lsp/handlers/fstab/shared"
|
||||||
@ -11,11 +12,11 @@ import (
|
|||||||
|
|
||||||
func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
|
func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
|
||||||
line := params.Position.Line
|
line := params.Position.Line
|
||||||
cursor := params.Position.Character
|
index := common.LSPCharacterAsIndexPosition(params.Position.Character)
|
||||||
|
|
||||||
p := shared.DocumentParserMap[params.TextDocument.URI]
|
d := shared.DocumentParserMap[params.TextDocument.URI]
|
||||||
|
|
||||||
rawEntry, found := p.Entries.Get(params.Position.Line)
|
rawEntry, found := d.Config.Entries.Get(params.Position.Line)
|
||||||
|
|
||||||
// Empty line
|
// Empty line
|
||||||
if !found {
|
if !found {
|
||||||
@ -26,7 +27,7 @@ func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*pr
|
|||||||
|
|
||||||
return handlers.GetHoverInfo(
|
return handlers.GetHoverInfo(
|
||||||
line,
|
line,
|
||||||
cursor,
|
index,
|
||||||
entry,
|
entry,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,385 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"config-lsp/common"
|
|
||||||
docvalues "config-lsp/doc-values"
|
|
||||||
fstabdocumentation "config-lsp/handlers/fstab/fields"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/emirpasic/gods/maps/treemap"
|
|
||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
|
||||||
|
|
||||||
gods "github.com/emirpasic/gods/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
var commentPattern = regexp.MustCompile(`^\s*#`)
|
|
||||||
var ignoreLinePattern = regexp.MustCompile(`^\s*$`)
|
|
||||||
var whitespacePattern = regexp.MustCompile(`\S+`)
|
|
||||||
|
|
||||||
type MalformedLineError struct{}
|
|
||||||
|
|
||||||
func (e MalformedLineError) Error() string {
|
|
||||||
return "Malformed line"
|
|
||||||
}
|
|
||||||
|
|
||||||
type Field struct {
|
|
||||||
Value string
|
|
||||||
Start uint32
|
|
||||||
End uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Field) String() string {
|
|
||||||
return fmt.Sprintf("%v [%v-%v]", f.Value, f.Start, f.End)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) CreateRange(fieldLine uint32) protocol.Range {
|
|
||||||
return protocol.Range{
|
|
||||||
Start: protocol.Position{
|
|
||||||
Line: fieldLine,
|
|
||||||
Character: f.Start,
|
|
||||||
},
|
|
||||||
End: protocol.Position{
|
|
||||||
Line: fieldLine,
|
|
||||||
Character: f.End,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FstabField string
|
|
||||||
|
|
||||||
const (
|
|
||||||
FstabFieldSpec FstabField = "spec"
|
|
||||||
FstabFieldMountPoint FstabField = "mountpoint"
|
|
||||||
FstabFieldFileSystemType FstabField = "filesystemtype"
|
|
||||||
FstabFieldOptions FstabField = "options"
|
|
||||||
FstabFieldFreq FstabField = "freq"
|
|
||||||
FstabFieldPass FstabField = "pass"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FstabFields struct {
|
|
||||||
Spec *Field
|
|
||||||
MountPoint *Field
|
|
||||||
FilesystemType *Field
|
|
||||||
Options *Field
|
|
||||||
Freq *Field
|
|
||||||
Pass *Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FstabFields) String() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"Spec: %s, MountPoint: %s, FilesystemType: %s, Options: %s, Freq: %s, Pass: %s",
|
|
||||||
f.Spec,
|
|
||||||
f.MountPoint,
|
|
||||||
f.FilesystemType,
|
|
||||||
f.Options,
|
|
||||||
f.Freq,
|
|
||||||
f.Pass,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FstabLine struct {
|
|
||||||
Line uint32
|
|
||||||
Fields FstabFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *FstabLine) CheckIsValid() []protocol.Diagnostic {
|
|
||||||
diagnostics := make([]protocol.Diagnostic, 0)
|
|
||||||
|
|
||||||
if e.Fields.Spec != nil {
|
|
||||||
errors := fstabdocumentation.SpecField.DeprecatedCheckIsValid(e.Fields.Spec.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.Spec.Start, errors)...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.MountPoint != nil {
|
|
||||||
errors := fstabdocumentation.MountPointField.DeprecatedCheckIsValid(e.Fields.MountPoint.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.MountPoint.Start, errors)...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileSystemType string = ""
|
|
||||||
|
|
||||||
if e.Fields.FilesystemType != nil {
|
|
||||||
errors := fstabdocumentation.FileSystemTypeField.DeprecatedCheckIsValid(e.Fields.FilesystemType.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.FilesystemType.Start, errors)...,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
fileSystemType = e.Fields.FilesystemType.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.Options != nil && fileSystemType != "" {
|
|
||||||
var optionsField docvalues.DeprecatedValue
|
|
||||||
|
|
||||||
if foundField, found := fstabdocumentation.MountOptionsMapField[fileSystemType]; found {
|
|
||||||
optionsField = foundField
|
|
||||||
} else {
|
|
||||||
optionsField = fstabdocumentation.DefaultMountOptionsField
|
|
||||||
}
|
|
||||||
|
|
||||||
errors := optionsField.DeprecatedCheckIsValid(e.Fields.Options.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.Options.Start, errors)...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.Freq != nil {
|
|
||||||
errors := fstabdocumentation.FreqField.DeprecatedCheckIsValid(e.Fields.Freq.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.Freq.Start, errors)...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.Pass != nil {
|
|
||||||
errors := fstabdocumentation.PassField.DeprecatedCheckIsValid(e.Fields.Pass.Value)
|
|
||||||
|
|
||||||
if len(errors) > 0 {
|
|
||||||
diagnostics = append(
|
|
||||||
diagnostics,
|
|
||||||
docvalues.InvalidValuesToErrorDiagnostics(e.Line, e.Fields.Pass.Start, errors)...,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return diagnostics
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e FstabLine) GetFieldAtPosition(cursor uint32) FstabField {
|
|
||||||
if e.Fields.Spec == nil || (cursor >= e.Fields.Spec.Start && cursor <= e.Fields.Spec.End) {
|
|
||||||
return FstabFieldSpec
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.MountPoint == nil || (cursor >= e.Fields.MountPoint.Start && cursor <= e.Fields.MountPoint.End) {
|
|
||||||
return FstabFieldMountPoint
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.FilesystemType == nil || (cursor >= e.Fields.FilesystemType.Start && cursor <= e.Fields.FilesystemType.End) {
|
|
||||||
return FstabFieldFileSystemType
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.Options == nil || (cursor >= e.Fields.Options.Start && cursor <= e.Fields.Options.End) {
|
|
||||||
return FstabFieldOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Fields.Freq == nil || (cursor >= e.Fields.Freq.Start && cursor <= e.Fields.Freq.End) {
|
|
||||||
return FstabFieldFreq
|
|
||||||
}
|
|
||||||
|
|
||||||
return FstabFieldPass
|
|
||||||
}
|
|
||||||
|
|
||||||
type FstabEntryType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
FstabEntryTypeLine FstabEntryType = "line"
|
|
||||||
FstabEntryTypeComment FstabEntryType = "comment"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FstabEntry struct {
|
|
||||||
Type FstabEntryType
|
|
||||||
Line FstabLine
|
|
||||||
}
|
|
||||||
|
|
||||||
type FstabParser struct {
|
|
||||||
// [uint32]FstabEntry - line number to entry mapping
|
|
||||||
Entries *treemap.Map
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) AddLine(line string, lineNumber int) error {
|
|
||||||
fields := whitespacePattern.FindAllStringIndex(line, -1)
|
|
||||||
|
|
||||||
if len(fields) == 0 {
|
|
||||||
return MalformedLineError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var spec *Field
|
|
||||||
var mountPoint *Field
|
|
||||||
var filesystemType *Field
|
|
||||||
var options *Field
|
|
||||||
var freq *Field
|
|
||||||
var pass *Field
|
|
||||||
|
|
||||||
switch len(fields) {
|
|
||||||
case 6:
|
|
||||||
field := fields[5]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
pass = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case 5:
|
|
||||||
field := fields[4]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
freq = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case 4:
|
|
||||||
field := fields[3]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
options = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case 3:
|
|
||||||
field := fields[2]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
filesystemType = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case 2:
|
|
||||||
field := fields[1]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
mountPoint = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case 1:
|
|
||||||
field := fields[0]
|
|
||||||
start := uint32(field[0])
|
|
||||||
end := uint32(field[1])
|
|
||||||
|
|
||||||
spec = &Field{
|
|
||||||
Value: line[start:end],
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry := FstabEntry{
|
|
||||||
Type: FstabEntryTypeLine,
|
|
||||||
Line: FstabLine{
|
|
||||||
Line: uint32(lineNumber),
|
|
||||||
Fields: FstabFields{
|
|
||||||
Spec: spec,
|
|
||||||
MountPoint: mountPoint,
|
|
||||||
FilesystemType: filesystemType,
|
|
||||||
Options: options,
|
|
||||||
Freq: freq,
|
|
||||||
Pass: pass,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
p.Entries.Put(entry.Line.Line, entry)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) AddCommentLine(line string, lineNumber int) {
|
|
||||||
entry := FstabLine{
|
|
||||||
Line: uint32(lineNumber),
|
|
||||||
}
|
|
||||||
p.Entries.Put(entry.Line, FstabEntry{
|
|
||||||
Type: FstabEntryTypeComment,
|
|
||||||
Line: entry,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) ParseFromContent(content string) []common.ParseError {
|
|
||||||
errors := []common.ParseError{}
|
|
||||||
lines := strings.Split(content, "\n")
|
|
||||||
|
|
||||||
for index, line := range lines {
|
|
||||||
if ignoreLinePattern.MatchString(line) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if commentPattern.MatchString(line) {
|
|
||||||
p.AddCommentLine(line, index)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := p.AddLine(line, index)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
errors = append(errors, common.ParseError{
|
|
||||||
Line: uint32(index),
|
|
||||||
Err: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) GetEntry(line uint32) (*FstabEntry, bool) {
|
|
||||||
rawEntry, found := p.Entries.Get(line)
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
entry := rawEntry.(FstabEntry)
|
|
||||||
|
|
||||||
return &entry, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) Clear() {
|
|
||||||
p.Entries = treemap.NewWith(gods.UInt32Comparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *FstabParser) AnalyzeValues() []protocol.Diagnostic {
|
|
||||||
diagnostics := []protocol.Diagnostic{}
|
|
||||||
|
|
||||||
it := p.Entries.Iterator()
|
|
||||||
|
|
||||||
for it.Next() {
|
|
||||||
entry := it.Value().(FstabEntry)
|
|
||||||
|
|
||||||
switch entry.Type {
|
|
||||||
case FstabEntryTypeLine:
|
|
||||||
newDiagnostics := entry.Line.CheckIsValid()
|
|
||||||
|
|
||||||
if len(newDiagnostics) > 0 {
|
|
||||||
diagnostics = append(diagnostics, newDiagnostics...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return diagnostics
|
|
||||||
}
|
|
@ -6,5 +6,8 @@ import (
|
|||||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DocumentParserMap = map[protocol.DocumentUri]*ast.FstabConfig{}
|
type FstabDocument struct {
|
||||||
|
Config *ast.FstabConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var DocumentParserMap = map[protocol.DocumentUri]*FstabDocument{}
|
||||||
|
25
server/handlers/fstab/test_utils/input.go
Normal file
25
server/handlers/fstab/test_utils/input.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package testutils_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"config-lsp/handlers/fstab/ast"
|
||||||
|
"config-lsp/handlers/fstab/shared"
|
||||||
|
"config-lsp/utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DocumentFromInput(
|
||||||
|
t *testing.T,
|
||||||
|
content string,
|
||||||
|
) *shared.FstabDocument {
|
||||||
|
input := utils.Dedent(content)
|
||||||
|
c := ast.NewFstabConfig()
|
||||||
|
errors := c.Parse(input)
|
||||||
|
|
||||||
|
if len(errors) > 0 {
|
||||||
|
t.Fatalf("Parse error: %v", errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &shared.FstabDocument{
|
||||||
|
Config: c,
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user