fix(fstab): Improve handler

This commit is contained in:
Myzel394 2024-08-05 22:50:47 +02:00
parent 433cd9ee4c
commit f6eb74f638
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
4 changed files with 170 additions and 53 deletions

View File

@ -17,33 +17,14 @@ var SpecField = docvalues.OrValue{
// docvalues.PathValue{ // docvalues.PathValue{
// RequiredType: docvalues.PathTypeFile & docvalues.PathTypeExistenceOptional, // RequiredType: docvalues.PathTypeFile & docvalues.PathTypeExistenceOptional,
// }, // },
docvalues.KeyValueAssignmentValue{ docvalues.KeyEnumAssignmentValue{
Separator: "=", Separator: "=",
ValueIsOptional: false, ValueIsOptional: false,
Key: docvalues.EnumValue{ Values: map[docvalues.EnumString]docvalues.Value{
EnforceValues: true, docvalues.CreateEnumString("UUID"): UuidField,
Values: []docvalues.EnumString{ docvalues.CreateEnumString("PARTUUID"): UuidField,
docvalues.CreateEnumString("UUID"), docvalues.CreateEnumString("LABEL"): LabelField,
docvalues.CreateEnumString("LABEL"), docvalues.CreateEnumString("PARTLABEL"): LabelField,
docvalues.CreateEnumString("PARTUUID"),
docvalues.CreateEnumString("PARTLABEL"),
},
},
Value: docvalues.CustomValue{
FetchValue: func(rawContext docvalues.CustomValueContext) docvalues.Value {
context := rawContext.(docvalues.KeyValueAssignmentContext)
switch context.SelectedKey {
case "UUID":
case "PARTUUID":
return UuidField
case "LABEL":
case "PARTLABEL":
return LabelField
}
return docvalues.StringValue{}
},
}, },
}, },
}, },

View File

@ -44,6 +44,17 @@ func (f *Field) CreateRange(fieldLine uint32) protocol.Range {
} }
} }
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 { type FstabFields struct {
Spec *Field Spec *Field
MountPoint *Field MountPoint *Field
@ -146,6 +157,30 @@ func (e *FstabEntry) CheckIsValid() []protocol.Diagnostic {
return diagnostics return diagnostics
} }
func (e FstabEntry) 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 FstabParser struct { type FstabParser struct {
entries []FstabEntry entries []FstabEntry
} }
@ -157,83 +192,83 @@ func (p *FstabParser) AddLine(line string, lineNumber int) error {
return MalformedLineError{} return MalformedLineError{}
} }
var spec Field var spec *Field
var mountPoint Field var mountPoint *Field
var filesystemType Field var filesystemType *Field
var options Field var options *Field
var freq Field var freq *Field
var pass Field var pass *Field
switch len(fields) { switch len(fields) {
case 6: case 6:
value := fields[5] value := fields[5]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
pass = Field{ pass = &Field{
Value: fields[5], Value: fields[5],
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
fallthrough fallthrough
case 5: case 5:
value := fields[4] value := fields[4]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
freq = Field{ freq = &Field{
Value: value, Value: value,
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
fallthrough fallthrough
case 4: case 4:
value := fields[3] value := fields[3]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
options = Field{ options = &Field{
Value: value, Value: value,
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
fallthrough fallthrough
case 3: case 3:
value := fields[2] value := fields[2]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
filesystemType = Field{ filesystemType = &Field{
Value: value, Value: value,
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
fallthrough fallthrough
case 2: case 2:
value := fields[1] value := fields[1]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
mountPoint = Field{ mountPoint = &Field{
Value: value, Value: value,
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
fallthrough fallthrough
case 1: case 1:
value := fields[0] value := fields[0]
start := uint32(strings.Index(line, value)) start := uint32(strings.Index(line, value))
spec = Field{ spec = &Field{
Value: value, Value: value,
Start: start, Start: start,
End: start + uint32(len(value)), End: start + uint32(len(value)) - 1,
} }
} }
entry := FstabEntry{ entry := FstabEntry{
Line: uint32(lineNumber), Line: uint32(lineNumber),
Fields: FstabFields{ Fields: FstabFields{
Spec: &spec, Spec: spec,
MountPoint: &mountPoint, MountPoint: mountPoint,
FilesystemType: &filesystemType, FilesystemType: filesystemType,
Options: &options, Options: options,
Freq: &freq, Freq: freq,
Pass: &pass, Pass: pass,
}, },
} }
p.entries = append(p.entries, entry) p.entries = append(p.entries, entry)
@ -263,7 +298,7 @@ func (p *FstabParser) ParseFromContent(content string) []common.ParseError {
return errors return errors
} }
func (p *FstabParser) GetEntry(line uint32) (FstabEntry, bool) { func (p *FstabParser) GetEntry(line uint32) (*FstabEntry, bool) {
index, found := slices.BinarySearchFunc(p.entries, line, func(entry FstabEntry, line uint32) int { index, found := slices.BinarySearchFunc(p.entries, line, func(entry FstabEntry, line uint32) int {
if entry.Line < line { if entry.Line < line {
return -1 return -1
@ -277,10 +312,10 @@ func (p *FstabParser) GetEntry(line uint32) (FstabEntry, bool) {
}) })
if !found { if !found {
return FstabEntry{}, false return nil, false
} }
return p.entries[index], true return &p.entries[index], true
} }
func (p *FstabParser) Clear() { func (p *FstabParser) Clear() {

View File

@ -0,0 +1,102 @@
package fstab
import (
docvalues "config-lsp/doc-values"
fstabdocumentation "config-lsp/handlers/fstab/documentation"
"fmt"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
parser := documentParserMap[params.TextDocument.URI]
entry, found := parser.GetEntry(params.Position.Line)
if !found {
// Empty line, return spec completions
return fstabdocumentation.SpecField.FetchCompletions(
"",
params.Position.Character,
), nil
}
cursor := params.Position.Character
targetField := entry.GetFieldAtPosition(cursor - 1)
println("cursor at", cursor, "target field", targetField)
switch targetField {
case FstabFieldSpec:
value, cursor := GetFieldSafely(entry.Fields.Spec, cursor)
return fstabdocumentation.SpecField.FetchCompletions(
value,
cursor,
), nil
case FstabFieldMountPoint:
value, cursor := GetFieldSafely(entry.Fields.MountPoint, cursor)
return fstabdocumentation.MountPointField.FetchCompletions(
value,
cursor,
), nil
case FstabFieldFileSystemType:
println(fmt.Sprintf("file system type: %s", entry.Fields.FilesystemType))
value, cursor := GetFieldSafely(entry.Fields.FilesystemType, cursor)
println("CURSOR", cursor)
return fstabdocumentation.FileSystemTypeField.FetchCompletions(
value,
cursor,
), nil
case FstabFieldOptions:
fileSystemType := entry.Fields.FilesystemType.Value
var optionsField docvalues.Value
if foundField, found := fstabdocumentation.MountOptionsMapField[fileSystemType]; found {
optionsField = foundField
} else {
optionsField = fstabdocumentation.DefaultMountOptionsField
}
value, cursor := GetFieldSafely(entry.Fields.Options, cursor)
return optionsField.FetchCompletions(
value,
cursor,
), nil
case FstabFieldFreq:
value, cursor := GetFieldSafely(entry.Fields.Freq, cursor)
return fstabdocumentation.FreqField.FetchCompletions(
value,
cursor,
), nil
case FstabFieldPass:
value, cursor := GetFieldSafely(entry.Fields.Pass, cursor)
return fstabdocumentation.PassField.FetchCompletions(
value,
cursor,
), nil
}
return nil, nil
}
// Safely get value and new cursor position
// If field is nil, return empty string and 0
func GetFieldSafely(field *Field, character uint32) (string, uint32) {
if field == nil {
return "", 0
}
if field.Value == "" {
return "", 0
}
return field.Value, character - field.Start
}

View File

@ -15,7 +15,6 @@ func TextDocumentDidOpen(
common.ClearDiagnostics(context, params.TextDocument.URI) common.ClearDiagnostics(context, params.TextDocument.URI)
parser := FstabParser{} parser := FstabParser{}
documentParserMap[params.TextDocument.URI] = &parser documentParserMap[params.TextDocument.URI] = &parser
errors := parser.ParseFromContent(params.TextDocument.Text) errors := parser.ParseFromContent(params.TextDocument.Text)