fix(fstab): Improvements; Use antlr parser now

This commit is contained in:
Myzel394 2024-10-09 21:44:32 +02:00
parent 5a13487db8
commit 3ca0ea8c35
No known key found for this signature in database
GPG Key ID: ED20A1D1D423AF3F
20 changed files with 2036 additions and 84 deletions

View File

@ -0,0 +1,76 @@
grammar Fstab;
entry
:
WHITESPACE? spec?
WHITESPACE? mountPoint?
WHITESPACE? fileSystem?
WHITESPACE? mountOptions?
WHITESPACE? freq?
WHITESPACE? pass? WHITESPACE?
EOF
;
spec
: QUOTED_STRING | STRING
;
mountPoint
: QUOTED_STRING | STRING
;
fileSystem
: ADFS | AFFS | BTRFS | EXFAT
// Still match unknown file systems
| STRING | QUOTED_STRING
;
mountOptions
: QUOTED_STRING | STRING
;
freq
: DIGITS
;
pass
: DIGITS
;
DIGITS
: [0-9]+
;
WHITESPACE
: [ \t]+
;
HASH
: '#'
;
STRING
: ~(' ' | '\t' | '#')+
;
QUOTED_STRING
: '"' WHITESPACE? (STRING WHITESPACE)* STRING? ('"')?
;
// ///// Supported file systems /////
ADFS
: ('A' | 'a') ('D' | 'd') ('F' | 'f') ('S' | 's')
;
AFFS
: ('A' | 'a') ('F' | 'f') ('F' | 'f') ('S' | 's')
;
BTRFS
: ('B' | 'b') ('T' | 't') ('R' | 'r') ('F' | 'f') ('S' | 's')
;
EXFAT
: ('E' | 'e') ('X' | 'x') ('F' | 'f') ('A' | 'a') ('T' | 't')
;

View File

@ -0,0 +1,45 @@
package ast
import (
"config-lsp/common"
"github.com/antlr4-go/antlr/v4"
)
type errorListenerContext struct {
line uint32
}
type errorListener struct {
*antlr.DefaultErrorListener
Errors []common.LSPError
context errorListenerContext
}
func (d *errorListener) SyntaxError(
recognizer antlr.Recognizer,
offendingSymbol interface{},
_ int,
character int,
message string,
error antlr.RecognitionException,
) {
line := d.context.line
d.Errors = append(d.Errors, common.LSPError{
Range: common.CreateSingleCharRange(uint32(line), uint32(character)),
Err: common.SyntaxError{
Message: message,
},
})
}
func createErrorListener(
line uint32,
) errorListener {
return errorListener{
Errors: make([]common.LSPError, 0),
context: errorListenerContext{
line: line,
},
}
}

View File

@ -33,7 +33,7 @@ type FstabFields struct {
}
type FstabEntry struct {
Fields FstabFields
Fields *FstabFields
}
type FstabConfig struct {

View File

@ -17,30 +17,118 @@ import (
// return entry.(*FstabEntry)
// }
// LABEL=test ext4 defaults 0 0
func (e FstabEntry) GetFieldAtPosition(position common.Position) FstabFieldName {
if e.Fields.Spec == nil || (e.Fields.Spec.ContainsPosition(position)) {
// No fields defined, empty line
if e.Fields.Spec == nil && e.Fields.MountPoint == nil && e.Fields.FilesystemType == nil && e.Fields.Options == nil && e.Fields.Freq == nil && e.Fields.Pass == nil {
return FstabFieldSpec
}
if e.Fields.MountPoint == nil || (e.Fields.MountPoint.ContainsPosition(position)) {
// First, try if out of the existing fields the user wants to edit one of them
if e.Fields.Spec != nil && e.Fields.Spec.ContainsPosition(position) {
return FstabFieldSpec
}
if e.Fields.MountPoint != nil && e.Fields.MountPoint.ContainsPosition(position) {
return FstabFieldMountPoint
}
if e.Fields.FilesystemType != nil && e.Fields.FilesystemType.ContainsPosition(position) {
return FstabFieldFileSystemType
}
if e.Fields.Options != nil && e.Fields.Options.ContainsPosition(position) {
return FstabFieldOptions
}
if e.Fields.Freq != nil && e.Fields.Freq.ContainsPosition(position) {
return FstabFieldFreq
}
if e.Fields.Pass != nil && e.Fields.Pass.ContainsPosition(position) {
return FstabFieldPass
}
// Okay let's try to fetch the field by assuming the user is typing from left to right normally
if e.Fields.Spec != nil && e.Fields.Spec.IsPositionAfterEnd(position) && (e.Fields.MountPoint == nil || e.Fields.MountPoint.IsPositionBeforeEnd(position)) {
return FstabFieldMountPoint
}
if e.Fields.FilesystemType == nil || (e.Fields.FilesystemType.ContainsPosition(position)) {
if e.Fields.MountPoint != nil && e.Fields.MountPoint.IsPositionAfterEnd(position) && (e.Fields.FilesystemType == nil || e.Fields.FilesystemType.IsPositionBeforeEnd(position)) {
return FstabFieldFileSystemType
}
if e.Fields.Options == nil || (e.Fields.Options.ContainsPosition(position)) {
if e.Fields.FilesystemType != nil && e.Fields.FilesystemType.IsPositionAfterEnd(position) && (e.Fields.Options == nil || e.Fields.Options.IsPositionBeforeEnd(position)) {
return FstabFieldOptions
}
if e.Fields.Freq == nil || (e.Fields.Freq.ContainsPosition(position)) {
if e.Fields.Options != nil && e.Fields.Options.IsPositionAfterEnd(position) && (e.Fields.Freq == nil || e.Fields.Freq.IsPositionBeforeEnd(position)) {
return FstabFieldFreq
}
if e.Fields.Freq != nil && e.Fields.Freq.IsPositionAfterEnd(position) && (e.Fields.Pass == nil || e.Fields.Pass.IsPositionBeforeEnd(position)) {
return FstabFieldPass
}
// Okay shit no idea, let's just give whatever is missing
if e.Fields.Spec == nil {
return FstabFieldSpec
}
if e.Fields.MountPoint == nil {
return FstabFieldMountPoint
}
if e.Fields.FilesystemType == nil {
return FstabFieldFileSystemType
}
if e.Fields.Options == nil {
return FstabFieldOptions
}
if e.Fields.Freq == nil {
return FstabFieldFreq
}
return FstabFieldPass
}
// LABEL=test /mnt/test btrfs subvol=backup,fat=32 [0] [0]
func (e FstabEntry) getCursorIndex() uint8 {
definedAmount := e.getDefinedFieldsAmount()
switch definedAmount {
case 5:
}
return 0
}
func (e FstabEntry) getDefinedFieldsAmount() uint8 {
var definedAmount uint8 = 0
if e.Fields.Spec != nil {
definedAmount++
}
if e.Fields.MountPoint != nil {
definedAmount++
}
if e.Fields.FilesystemType != nil {
definedAmount++
}
if e.Fields.Options != nil {
definedAmount++
}
if e.Fields.Freq != nil {
definedAmount++
}
if e.Fields.Pass != nil {
definedAmount++
}
return definedAmount
}
// Create a mount options field for the entry
func (e FstabEntry) FetchMountOptionsField(includeDefaults bool) docvalues.DeprecatedValue {
if e.Fields.FilesystemType == nil {

View File

@ -0,0 +1,135 @@
package ast
import (
"config-lsp/common"
"config-lsp/handlers/fstab/ast/parser"
commonparser "config-lsp/common/parser"
)
type fstabListenerContext struct {
line uint32
currentEntry *FstabEntry
}
func createListenerContext() *fstabListenerContext {
context := new(fstabListenerContext)
return context
}
type fstabParserListener struct {
*parser.BaseFstabListener
Config *FstabConfig
Errors []common.LSPError
fstabContext *fstabListenerContext
}
func createListener(
config *FstabConfig,
context *fstabListenerContext,
) fstabParserListener {
return fstabParserListener{
Config: config,
Errors: make([]common.LSPError, 0),
fstabContext: context,
}
}
func (s *fstabParserListener) EnterEntry(ctx *parser.EntryContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
s.fstabContext.currentEntry = &FstabEntry{
Fields: &FstabFields{
LocationRange: location,
},
}
s.Config.Entries.Put(
s.fstabContext.line,
s.fstabContext.currentEntry,
)
}
func (s *fstabParserListener) ExitEntry(ctx *parser.EntryContext) {
s.fstabContext.currentEntry = nil
}
func (s *fstabParserListener) EnterSpec(ctx *parser.SpecContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.Spec = &FstabField{
Value: value,
LocationRange: location,
}
}
func (s *fstabParserListener) EnterMountPoint(ctx *parser.MountPointContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.MountPoint = &FstabField{
LocationRange: location,
Value: value,
}
}
func (s *fstabParserListener) EnterFileSystem(ctx *parser.FileSystemContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.FilesystemType = &FstabField{
LocationRange: location,
Value: value,
}
}
func (s *fstabParserListener) EnterMountOptions(ctx *parser.MountOptionsContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.Options = &FstabField{
LocationRange: location,
Value: value,
}
}
func (s *fstabParserListener) EnterFreq(ctx *parser.FreqContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.Freq = &FstabField{
LocationRange: location,
Value: value,
}
}
func (s *fstabParserListener) EnterPass(ctx *parser.PassContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.fstabContext.line)
text := ctx.GetText()
value := commonparser.ParseRawString(text, commonparser.FullFeatures)
s.fstabContext.currentEntry.Fields.Pass = &FstabField{
LocationRange: location,
Value: value,
}
}

View File

@ -3,9 +3,11 @@ package ast
import (
"config-lsp/common"
commonparser "config-lsp/common/parser"
"config-lsp/handlers/fstab/ast/parser"
"config-lsp/utils"
"regexp"
"github.com/antlr4-go/antlr/v4"
"github.com/emirpasic/gods/maps/treemap"
gods "github.com/emirpasic/gods/utils"
@ -25,14 +27,15 @@ func (c *FstabConfig) Clear() {
var commentPattern = regexp.MustCompile(`^\s*#`)
var emptyPattern = regexp.MustCompile(`^\s*$`)
var whitespacePattern = regexp.MustCompile(`\S+`)
func (c *FstabConfig) Parse(input string) []common.LSPError {
errors := make([]common.LSPError, 0)
lines := utils.SplitIntoLines(input)
context := createListenerContext()
for rawLineNumber, line := range lines {
lineNumber := uint32(rawLineNumber)
context.line = lineNumber
if emptyPattern.MatchString(line) {
continue
@ -45,88 +48,120 @@ func (c *FstabConfig) Parse(input string) []common.LSPError {
errors = append(
errors,
c.parseStatement(lineNumber, line)...,
c.parseStatement(context, line)...,
)
}
return errors
}
// TODO: Handle leading comments
func (c *FstabConfig) parseStatement(
line uint32,
context *fstabListenerContext,
input string,
) []common.LSPError {
fields := whitespacePattern.FindAllStringIndex(input, -1)
stream := antlr.NewInputStream(input)
if len(fields) == 0 {
return []common.LSPError{
{
Range: common.LocationRange{
Start: common.Location{
Line: line,
Character: 0,
},
End: common.Location{
Line: line,
Character: 0,
},
},
},
}
lexerErrorListener := createErrorListener(context.line)
lexer := parser.NewFstabLexer(stream)
lexer.RemoveErrorListeners()
lexer.AddErrorListener(&lexerErrorListener)
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
parserErrorListener := createErrorListener(context.line)
antlrParser := parser.NewFstabParser(tokenStream)
antlrParser.RemoveErrorListeners()
antlrParser.AddErrorListener(&parserErrorListener)
listener := createListener(c, context)
antlr.ParseTreeWalkerDefault.Walk(
&listener,
antlrParser.Entry(),
)
errors := lexerErrorListener.Errors
errors = append(errors, parserErrorListener.Errors...)
errors = append(errors, listener.Errors...)
return errors
}
var spec *FstabField
var mountPoint *FstabField
var filesystemType *FstabField
var options *FstabField
var freq *FstabField
var pass *FstabField
switch len(fields) {
case 6:
pass = parseField(line, input, fields[5])
fallthrough
case 5:
freq = parseField(line, input, fields[4])
fallthrough
case 4:
options = parseField(line, input, fields[3])
fallthrough
case 3:
filesystemType = parseField(line, input, fields[2])
fallthrough
case 2:
mountPoint = parseField(line, input, fields[1])
fallthrough
case 1:
spec = parseField(line, input, fields[0])
}
fstabLine := &FstabEntry{
Fields: FstabFields{
LocationRange: common.LocationRange{
Start: common.Location{
Line: line,
Character: 0,
},
End: common.Location{
Line: line,
Character: uint32(len(input)),
},
},
Spec: spec,
MountPoint: mountPoint,
FilesystemType: filesystemType,
Options: options,
Freq: freq,
Pass: pass,
},
}
c.Entries.Put(line, fstabLine)
return nil
}
// func (c *FstabConfig) parseStatement(
// line uint32,
// input string,
// ) []common.LSPError {
// fields := whitespacePattern.FindAllStringIndex(input, -1)
//
// if len(fields) == 0 {
// return []common.LSPError{
// {
// Range: common.LocationRange{
// Start: common.Location{
// Line: line,
// Character: 0,
// },
// End: common.Location{
// Line: line,
// Character: 0,
// },
// },
// },
// }
// }
//
// var spec *FstabField
// var mountPoint *FstabField
// var filesystemType *FstabField
// var options *FstabField
// var freq *FstabField
// var pass *FstabField
//
// switch len(fields) {
// case 6:
// pass = parseField(line, input, fields[5])
// fallthrough
// case 5:
// freq = parseField(line, input, fields[4])
// fallthrough
// case 4:
// options = parseField(line, input, fields[3])
// fallthrough
// case 3:
// filesystemType = parseField(line, input, fields[2])
// fallthrough
// case 2:
// mountPoint = parseField(line, input, fields[1])
// fallthrough
// case 1:
// spec = parseField(line, input, fields[0])
// }
//
// fstabLine := &FstabEntry{
// Fields: FstabFields{
// LocationRange: common.LocationRange{
// Start: common.Location{
// Line: line,
// Character: 0,
// },
// End: common.Location{
// Line: line,
// Character: uint32(len(input)),
// },
// },
// Spec: spec,
// MountPoint: mountPoint,
// FilesystemType: filesystemType,
// Options: options,
// Freq: freq,
// Pass: pass,
// },
// }
//
// c.Entries.Put(line, fstabLine)
//
// return nil
// }
func parseField(
line uint32,

View File

@ -0,0 +1,36 @@
token literal names:
null
null
null
'#'
null
null
null
null
null
null
token symbolic names:
null
DIGITS
WHITESPACE
HASH
STRING
QUOTED_STRING
ADFS
AFFS
BTRFS
EXFAT
rule names:
entry
spec
mountPoint
fileSystem
mountOptions
freq
pass
atn:
[4, 1, 9, 68, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 1, 0, 3, 0, 16, 8, 0, 1, 0, 3, 0, 19, 8, 0, 1, 0, 3, 0, 22, 8, 0, 1, 0, 3, 0, 25, 8, 0, 1, 0, 3, 0, 28, 8, 0, 1, 0, 3, 0, 31, 8, 0, 1, 0, 3, 0, 34, 8, 0, 1, 0, 3, 0, 37, 8, 0, 1, 0, 3, 0, 40, 8, 0, 1, 0, 3, 0, 43, 8, 0, 1, 0, 3, 0, 46, 8, 0, 1, 0, 3, 0, 49, 8, 0, 1, 0, 3, 0, 52, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 0, 0, 7, 0, 2, 4, 6, 8, 10, 12, 0, 2, 1, 0, 4, 5, 1, 0, 4, 9, 73, 0, 15, 1, 0, 0, 0, 2, 55, 1, 0, 0, 0, 4, 57, 1, 0, 0, 0, 6, 59, 1, 0, 0, 0, 8, 61, 1, 0, 0, 0, 10, 63, 1, 0, 0, 0, 12, 65, 1, 0, 0, 0, 14, 16, 5, 2, 0, 0, 15, 14, 1, 0, 0, 0, 15, 16, 1, 0, 0, 0, 16, 18, 1, 0, 0, 0, 17, 19, 3, 2, 1, 0, 18, 17, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19, 21, 1, 0, 0, 0, 20, 22, 5, 2, 0, 0, 21, 20, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 24, 1, 0, 0, 0, 23, 25, 3, 4, 2, 0, 24, 23, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 27, 1, 0, 0, 0, 26, 28, 5, 2, 0, 0, 27, 26, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 30, 1, 0, 0, 0, 29, 31, 3, 6, 3, 0, 30, 29, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 33, 1, 0, 0, 0, 32, 34, 5, 2, 0, 0, 33, 32, 1, 0, 0, 0, 33, 34, 1, 0, 0, 0, 34, 36, 1, 0, 0, 0, 35, 37, 3, 8, 4, 0, 36, 35, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 39, 1, 0, 0, 0, 38, 40, 5, 2, 0, 0, 39, 38, 1, 0, 0, 0, 39, 40, 1, 0, 0, 0, 40, 42, 1, 0, 0, 0, 41, 43, 3, 10, 5, 0, 42, 41, 1, 0, 0, 0, 42, 43, 1, 0, 0, 0, 43, 45, 1, 0, 0, 0, 44, 46, 5, 2, 0, 0, 45, 44, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 48, 1, 0, 0, 0, 47, 49, 3, 12, 6, 0, 48, 47, 1, 0, 0, 0, 48, 49, 1, 0, 0, 0, 49, 51, 1, 0, 0, 0, 50, 52, 5, 2, 0, 0, 51, 50, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 54, 5, 0, 0, 1, 54, 1, 1, 0, 0, 0, 55, 56, 7, 0, 0, 0, 56, 3, 1, 0, 0, 0, 57, 58, 7, 0, 0, 0, 58, 5, 1, 0, 0, 0, 59, 60, 7, 1, 0, 0, 60, 7, 1, 0, 0, 0, 61, 62, 7, 0, 0, 0, 62, 9, 1, 0, 0, 0, 63, 64, 5, 1, 0, 0, 64, 11, 1, 0, 0, 0, 65, 66, 5, 1, 0, 0, 66, 13, 1, 0, 0, 0, 13, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51]

View File

@ -0,0 +1,10 @@
DIGITS=1
WHITESPACE=2
HASH=3
STRING=4
QUOTED_STRING=5
ADFS=6
AFFS=7
BTRFS=8
EXFAT=9
'#'=3

View File

@ -0,0 +1,44 @@
token literal names:
null
null
null
'#'
null
null
null
null
null
null
token symbolic names:
null
DIGITS
WHITESPACE
HASH
STRING
QUOTED_STRING
ADFS
AFFS
BTRFS
EXFAT
rule names:
DIGITS
WHITESPACE
HASH
STRING
QUOTED_STRING
ADFS
AFFS
BTRFS
EXFAT
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
mode names:
DEFAULT_MODE
atn:
[4, 0, 9, 76, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 1, 0, 4, 0, 21, 8, 0, 11, 0, 12, 0, 22, 1, 1, 4, 1, 26, 8, 1, 11, 1, 12, 1, 27, 1, 2, 1, 2, 1, 3, 4, 3, 33, 8, 3, 11, 3, 12, 3, 34, 1, 4, 1, 4, 3, 4, 39, 8, 4, 1, 4, 1, 4, 1, 4, 5, 4, 44, 8, 4, 10, 4, 12, 4, 47, 9, 4, 1, 4, 3, 4, 50, 8, 4, 1, 4, 3, 4, 53, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 0, 0, 9, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 1, 0, 12, 1, 0, 48, 57, 2, 0, 9, 9, 32, 32, 3, 0, 9, 9, 32, 32, 35, 35, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, 100, 2, 0, 70, 70, 102, 102, 2, 0, 83, 83, 115, 115, 2, 0, 66, 66, 98, 98, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 69, 69, 101, 101, 2, 0, 88, 88, 120, 120, 82, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 1, 20, 1, 0, 0, 0, 3, 25, 1, 0, 0, 0, 5, 29, 1, 0, 0, 0, 7, 32, 1, 0, 0, 0, 9, 36, 1, 0, 0, 0, 11, 54, 1, 0, 0, 0, 13, 59, 1, 0, 0, 0, 15, 64, 1, 0, 0, 0, 17, 70, 1, 0, 0, 0, 19, 21, 7, 0, 0, 0, 20, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 2, 1, 0, 0, 0, 24, 26, 7, 1, 0, 0, 25, 24, 1, 0, 0, 0, 26, 27, 1, 0, 0, 0, 27, 25, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 4, 1, 0, 0, 0, 29, 30, 5, 35, 0, 0, 30, 6, 1, 0, 0, 0, 31, 33, 8, 2, 0, 0, 32, 31, 1, 0, 0, 0, 33, 34, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0, 35, 8, 1, 0, 0, 0, 36, 38, 5, 34, 0, 0, 37, 39, 3, 3, 1, 0, 38, 37, 1, 0, 0, 0, 38, 39, 1, 0, 0, 0, 39, 45, 1, 0, 0, 0, 40, 41, 3, 7, 3, 0, 41, 42, 3, 3, 1, 0, 42, 44, 1, 0, 0, 0, 43, 40, 1, 0, 0, 0, 44, 47, 1, 0, 0, 0, 45, 43, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 49, 1, 0, 0, 0, 47, 45, 1, 0, 0, 0, 48, 50, 3, 7, 3, 0, 49, 48, 1, 0, 0, 0, 49, 50, 1, 0, 0, 0, 50, 52, 1, 0, 0, 0, 51, 53, 5, 34, 0, 0, 52, 51, 1, 0, 0, 0, 52, 53, 1, 0, 0, 0, 53, 10, 1, 0, 0, 0, 54, 55, 7, 3, 0, 0, 55, 56, 7, 4, 0, 0, 56, 57, 7, 5, 0, 0, 57, 58, 7, 6, 0, 0, 58, 12, 1, 0, 0, 0, 59, 60, 7, 3, 0, 0, 60, 61, 7, 5, 0, 0, 61, 62, 7, 5, 0, 0, 62, 63, 7, 6, 0, 0, 63, 14, 1, 0, 0, 0, 64, 65, 7, 7, 0, 0, 65, 66, 7, 8, 0, 0, 66, 67, 7, 9, 0, 0, 67, 68, 7, 5, 0, 0, 68, 69, 7, 6, 0, 0, 69, 16, 1, 0, 0, 0, 70, 71, 7, 10, 0, 0, 71, 72, 7, 11, 0, 0, 72, 73, 7, 5, 0, 0, 73, 74, 7, 3, 0, 0, 74, 75, 7, 8, 0, 0, 75, 18, 1, 0, 0, 0, 8, 0, 22, 27, 34, 38, 45, 49, 52, 0]

View File

@ -0,0 +1,10 @@
DIGITS=1
WHITESPACE=2
HASH=3
STRING=4
QUOTED_STRING=5
ADFS=6
AFFS=7
BTRFS=8
EXFAT=9
'#'=3

View File

@ -0,0 +1,64 @@
// Code generated from Fstab.g4 by ANTLR 4.13.0. DO NOT EDIT.
package parser // Fstab
import "github.com/antlr4-go/antlr/v4"
// BaseFstabListener is a complete listener for a parse tree produced by FstabParser.
type BaseFstabListener struct{}
var _ FstabListener = &BaseFstabListener{}
// VisitTerminal is called when a terminal node is visited.
func (s *BaseFstabListener) VisitTerminal(node antlr.TerminalNode) {}
// VisitErrorNode is called when an error node is visited.
func (s *BaseFstabListener) VisitErrorNode(node antlr.ErrorNode) {}
// EnterEveryRule is called when any rule is entered.
func (s *BaseFstabListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
// ExitEveryRule is called when any rule is exited.
func (s *BaseFstabListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
// EnterEntry is called when production entry is entered.
func (s *BaseFstabListener) EnterEntry(ctx *EntryContext) {}
// ExitEntry is called when production entry is exited.
func (s *BaseFstabListener) ExitEntry(ctx *EntryContext) {}
// EnterSpec is called when production spec is entered.
func (s *BaseFstabListener) EnterSpec(ctx *SpecContext) {}
// ExitSpec is called when production spec is exited.
func (s *BaseFstabListener) ExitSpec(ctx *SpecContext) {}
// EnterMountPoint is called when production mountPoint is entered.
func (s *BaseFstabListener) EnterMountPoint(ctx *MountPointContext) {}
// ExitMountPoint is called when production mountPoint is exited.
func (s *BaseFstabListener) ExitMountPoint(ctx *MountPointContext) {}
// EnterFileSystem is called when production fileSystem is entered.
func (s *BaseFstabListener) EnterFileSystem(ctx *FileSystemContext) {}
// ExitFileSystem is called when production fileSystem is exited.
func (s *BaseFstabListener) ExitFileSystem(ctx *FileSystemContext) {}
// EnterMountOptions is called when production mountOptions is entered.
func (s *BaseFstabListener) EnterMountOptions(ctx *MountOptionsContext) {}
// ExitMountOptions is called when production mountOptions is exited.
func (s *BaseFstabListener) ExitMountOptions(ctx *MountOptionsContext) {}
// EnterFreq is called when production freq is entered.
func (s *BaseFstabListener) EnterFreq(ctx *FreqContext) {}
// ExitFreq is called when production freq is exited.
func (s *BaseFstabListener) ExitFreq(ctx *FreqContext) {}
// EnterPass is called when production pass is entered.
func (s *BaseFstabListener) EnterPass(ctx *PassContext) {}
// ExitPass is called when production pass is exited.
func (s *BaseFstabListener) ExitPass(ctx *PassContext) {}

View File

@ -0,0 +1,143 @@
// Code generated from Fstab.g4 by ANTLR 4.13.0. DO NOT EDIT.
package parser
import (
"fmt"
"github.com/antlr4-go/antlr/v4"
"sync"
"unicode"
)
// Suppress unused import error
var _ = fmt.Printf
var _ = sync.Once{}
var _ = unicode.IsLetter
type FstabLexer struct {
*antlr.BaseLexer
channelNames []string
modeNames []string
// TODO: EOF string
}
var FstabLexerLexerStaticData struct {
once sync.Once
serializedATN []int32
ChannelNames []string
ModeNames []string
LiteralNames []string
SymbolicNames []string
RuleNames []string
PredictionContextCache *antlr.PredictionContextCache
atn *antlr.ATN
decisionToDFA []*antlr.DFA
}
func fstablexerLexerInit() {
staticData := &FstabLexerLexerStaticData
staticData.ChannelNames = []string{
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
}
staticData.ModeNames = []string{
"DEFAULT_MODE",
}
staticData.LiteralNames = []string{
"", "", "", "'#'",
}
staticData.SymbolicNames = []string{
"", "DIGITS", "WHITESPACE", "HASH", "STRING", "QUOTED_STRING", "ADFS",
"AFFS", "BTRFS", "EXFAT",
}
staticData.RuleNames = []string{
"DIGITS", "WHITESPACE", "HASH", "STRING", "QUOTED_STRING", "ADFS", "AFFS",
"BTRFS", "EXFAT",
}
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
staticData.serializedATN = []int32{
4, 0, 9, 76, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 1, 0, 4, 0, 21,
8, 0, 11, 0, 12, 0, 22, 1, 1, 4, 1, 26, 8, 1, 11, 1, 12, 1, 27, 1, 2, 1,
2, 1, 3, 4, 3, 33, 8, 3, 11, 3, 12, 3, 34, 1, 4, 1, 4, 3, 4, 39, 8, 4,
1, 4, 1, 4, 1, 4, 5, 4, 44, 8, 4, 10, 4, 12, 4, 47, 9, 4, 1, 4, 3, 4, 50,
8, 4, 1, 4, 3, 4, 53, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1,
6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1,
8, 1, 8, 1, 8, 0, 0, 9, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15,
8, 17, 9, 1, 0, 12, 1, 0, 48, 57, 2, 0, 9, 9, 32, 32, 3, 0, 9, 9, 32, 32,
35, 35, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, 100, 2, 0, 70, 70, 102,
102, 2, 0, 83, 83, 115, 115, 2, 0, 66, 66, 98, 98, 2, 0, 84, 84, 116, 116,
2, 0, 82, 82, 114, 114, 2, 0, 69, 69, 101, 101, 2, 0, 88, 88, 120, 120,
82, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0,
0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0,
0, 0, 0, 17, 1, 0, 0, 0, 1, 20, 1, 0, 0, 0, 3, 25, 1, 0, 0, 0, 5, 29, 1,
0, 0, 0, 7, 32, 1, 0, 0, 0, 9, 36, 1, 0, 0, 0, 11, 54, 1, 0, 0, 0, 13,
59, 1, 0, 0, 0, 15, 64, 1, 0, 0, 0, 17, 70, 1, 0, 0, 0, 19, 21, 7, 0, 0,
0, 20, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23,
1, 0, 0, 0, 23, 2, 1, 0, 0, 0, 24, 26, 7, 1, 0, 0, 25, 24, 1, 0, 0, 0,
26, 27, 1, 0, 0, 0, 27, 25, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 4, 1, 0,
0, 0, 29, 30, 5, 35, 0, 0, 30, 6, 1, 0, 0, 0, 31, 33, 8, 2, 0, 0, 32, 31,
1, 0, 0, 0, 33, 34, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0,
35, 8, 1, 0, 0, 0, 36, 38, 5, 34, 0, 0, 37, 39, 3, 3, 1, 0, 38, 37, 1,
0, 0, 0, 38, 39, 1, 0, 0, 0, 39, 45, 1, 0, 0, 0, 40, 41, 3, 7, 3, 0, 41,
42, 3, 3, 1, 0, 42, 44, 1, 0, 0, 0, 43, 40, 1, 0, 0, 0, 44, 47, 1, 0, 0,
0, 45, 43, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 49, 1, 0, 0, 0, 47, 45,
1, 0, 0, 0, 48, 50, 3, 7, 3, 0, 49, 48, 1, 0, 0, 0, 49, 50, 1, 0, 0, 0,
50, 52, 1, 0, 0, 0, 51, 53, 5, 34, 0, 0, 52, 51, 1, 0, 0, 0, 52, 53, 1,
0, 0, 0, 53, 10, 1, 0, 0, 0, 54, 55, 7, 3, 0, 0, 55, 56, 7, 4, 0, 0, 56,
57, 7, 5, 0, 0, 57, 58, 7, 6, 0, 0, 58, 12, 1, 0, 0, 0, 59, 60, 7, 3, 0,
0, 60, 61, 7, 5, 0, 0, 61, 62, 7, 5, 0, 0, 62, 63, 7, 6, 0, 0, 63, 14,
1, 0, 0, 0, 64, 65, 7, 7, 0, 0, 65, 66, 7, 8, 0, 0, 66, 67, 7, 9, 0, 0,
67, 68, 7, 5, 0, 0, 68, 69, 7, 6, 0, 0, 69, 16, 1, 0, 0, 0, 70, 71, 7,
10, 0, 0, 71, 72, 7, 11, 0, 0, 72, 73, 7, 5, 0, 0, 73, 74, 7, 3, 0, 0,
74, 75, 7, 8, 0, 0, 75, 18, 1, 0, 0, 0, 8, 0, 22, 27, 34, 38, 45, 49, 52,
0,
}
deserializer := antlr.NewATNDeserializer(nil)
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
atn := staticData.atn
staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))
decisionToDFA := staticData.decisionToDFA
for index, state := range atn.DecisionToState {
decisionToDFA[index] = antlr.NewDFA(state, index)
}
}
// FstabLexerInit initializes any static state used to implement FstabLexer. By default the
// static state used to implement the lexer is lazily initialized during the first call to
// NewFstabLexer(). You can call this function if you wish to initialize the static state ahead
// of time.
func FstabLexerInit() {
staticData := &FstabLexerLexerStaticData
staticData.once.Do(fstablexerLexerInit)
}
// NewFstabLexer produces a new lexer instance for the optional input antlr.CharStream.
func NewFstabLexer(input antlr.CharStream) *FstabLexer {
FstabLexerInit()
l := new(FstabLexer)
l.BaseLexer = antlr.NewBaseLexer(input)
staticData := &FstabLexerLexerStaticData
l.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)
l.channelNames = staticData.ChannelNames
l.modeNames = staticData.ModeNames
l.RuleNames = staticData.RuleNames
l.LiteralNames = staticData.LiteralNames
l.SymbolicNames = staticData.SymbolicNames
l.GrammarFileName = "Fstab.g4"
// TODO: l.EOF = antlr.TokenEOF
return l
}
// FstabLexer tokens.
const (
FstabLexerDIGITS = 1
FstabLexerWHITESPACE = 2
FstabLexerHASH = 3
FstabLexerSTRING = 4
FstabLexerQUOTED_STRING = 5
FstabLexerADFS = 6
FstabLexerAFFS = 7
FstabLexerBTRFS = 8
FstabLexerEXFAT = 9
)

View File

@ -0,0 +1,52 @@
// Code generated from Fstab.g4 by ANTLR 4.13.0. DO NOT EDIT.
package parser // Fstab
import "github.com/antlr4-go/antlr/v4"
// FstabListener is a complete listener for a parse tree produced by FstabParser.
type FstabListener interface {
antlr.ParseTreeListener
// EnterEntry is called when entering the entry production.
EnterEntry(c *EntryContext)
// EnterSpec is called when entering the spec production.
EnterSpec(c *SpecContext)
// EnterMountPoint is called when entering the mountPoint production.
EnterMountPoint(c *MountPointContext)
// EnterFileSystem is called when entering the fileSystem production.
EnterFileSystem(c *FileSystemContext)
// EnterMountOptions is called when entering the mountOptions production.
EnterMountOptions(c *MountOptionsContext)
// EnterFreq is called when entering the freq production.
EnterFreq(c *FreqContext)
// EnterPass is called when entering the pass production.
EnterPass(c *PassContext)
// ExitEntry is called when exiting the entry production.
ExitEntry(c *EntryContext)
// ExitSpec is called when exiting the spec production.
ExitSpec(c *SpecContext)
// ExitMountPoint is called when exiting the mountPoint production.
ExitMountPoint(c *MountPointContext)
// ExitFileSystem is called when exiting the fileSystem production.
ExitFileSystem(c *FileSystemContext)
// ExitMountOptions is called when exiting the mountOptions production.
ExitMountOptions(c *MountOptionsContext)
// ExitFreq is called when exiting the freq production.
ExitFreq(c *FreqContext)
// ExitPass is called when exiting the pass production.
ExitPass(c *PassContext)
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ func TestExample1(
) {
input := utils.Dedent(`
LABEL=test /mnt/test ext4 defaults 0 0
LABEL=example /mnt/example fat32 defaults 0 2
`)
c := NewFstabConfig()
@ -20,8 +21,8 @@ LABEL=test /mnt/test ext4 defaults 0 0
t.Fatalf("Expected no errors, got %v", errors)
}
if c.Entries.Size() != 1 {
t.Fatalf("Expected 1 entry, got %d", c.Entries.Size())
if c.Entries.Size() != 2 {
t.Fatalf("Expected 2 entry, got %d", c.Entries.Size())
}
rawFirstEntry, _ := c.Entries.Get(uint32(0))
@ -93,6 +94,12 @@ LABEL=test /mnt/test ext4 defaults 0 0
if !(field == FstabFieldFreq) {
t.Errorf("Expected field to be freq, got %v", field)
}
rawSecondEntry, _ := c.Entries.Get(uint32(1))
secondEntry := rawSecondEntry.(*FstabEntry)
if !(secondEntry.Fields.Start.Line == 1) {
t.Errorf("Expected start line to be 1, got %d", secondEntry.Fields.Start.Line)
}
}
func TestIncompleteExample(

View File

@ -15,7 +15,7 @@ var LabelField = docvalues.RegexValue{
var SpecField = docvalues.OrValue{
Values: []docvalues.DeprecatedValue{
docvalues.PathValue{
RequiredType: docvalues.PathTypeFile,
RequiredType: docvalues.PathTypeExistenceOptional,
},
docvalues.KeyEnumAssignmentValue{
Separator: "=",

View File

@ -101,6 +101,36 @@ LABEL=test /mnt/test btrfs subvol=backup,fat=32 0 0
}
}
func TestIncompleteExample(t *testing.T) {
input := utils.Dedent(`
LABEL=test /mnt/test defaults 0 0
`)
p := ast.NewFstabConfig()
errors := p.Parse(input)
if len(errors) > 0 {
t.Fatal("ParseFromContent returned error", errors)
}
rawFirstEntry, _ := p.Entries.Get(uint32(0))
firstEntry := rawFirstEntry.(*ast.FstabEntry)
name := firstEntry.GetFieldAtPosition(common.CursorPosition(0))
if !(name == ast.FstabFieldSpec) {
t.Errorf("GetFieldAtPosition failed to return correct field name. Got: %v but expected: %v", name, ast.FstabFieldSpec)
}
name = firstEntry.GetFieldAtPosition(common.CursorPosition(9))
if !(name == ast.FstabFieldSpec) {
t.Errorf("GetFieldAtPosition failed to return correct field name. Got: %v but expected: %v", name, ast.FstabFieldSpec)
}
name = firstEntry.GetFieldAtPosition(common.CursorPosition(21))
if !(name == ast.FstabFieldFileSystemType) {
t.Errorf("GetFieldAtPosition failed to return correct field name. Got: %v but expected: %v", name, ast.FstabFieldFileSystemType)
}
}
// func TestExample1(t *testing.T) {
// input := utils.Dedent(`
// /dev/disk/by-uuid/19ae4e13-1d6d-4833-965b-a20197aebf27 /mnt/RetroGames auto nosuid,nodev,nofail,x-gvfs-show 0 0

View File

@ -42,7 +42,6 @@ func GetCompletion(
fileSystemType := entry.Fields.FilesystemType.Value.Value
completions := make([]protocol.CompletionItem, 0, 50)
println("fetching field options now", line, cursor)
for _, completion := range fields.DefaultMountOptionsField.DeprecatedFetchCompletions(line, cursor) {
var documentation string
@ -108,5 +107,9 @@ func getFieldSafely(field *ast.FstabField, cursor common.CursorPosition) (string
return "", 0
}
if uint32(cursor) < field.Start.Character {
return "", 0
}
return field.Value.Raw, common.CursorToCharacterIndex(uint32(cursor) - field.Start.Character)
}

View File

@ -26,6 +26,13 @@ func createListenerContext() *sshListenerContext {
return context
}
type sshParserListener struct {
*parser.BaseConfigListener
Config *SSHConfig
Errors []common.LSPError
sshContext *sshListenerContext
}
func createListener(
config *SSHConfig,
context *sshListenerContext,
@ -37,13 +44,6 @@ func createListener(
}
}
type sshParserListener struct {
*parser.BaseConfigListener
Config *SSHConfig
Errors []common.LSPError
sshContext *sshListenerContext
}
func (s *sshParserListener) EnterEntry(ctx *parser.EntryContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.sshContext.line)

View File

@ -5,6 +5,9 @@ ROOT=$(git rev-parse --show-toplevel)/server
# aliases
cd $ROOT/handlers/aliases && antlr4 -Dlanguage=Go -o ast/parser Aliases.g4
# fstab
cd $ROOT/hanlders/fstab && antlr4 -Dlanguage=Go -o ast/parser Fstab.g4
# sshd_config
cd $ROOT/handlers/sshd_config && antlr4 -Dlanguage=Go -o ast/parser Config.g4
cd $ROOT/handlers/sshd_config/match-parser && antlr4 -Dlanguage=Go -o parser Match.g4