mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-19 07:25:27 +02:00
feat(sshd_config): Add match completions; Bugfixes
This commit is contained in:
parent
6911511b51
commit
9b1a5af2d0
@ -1,7 +1,7 @@
|
||||
grammar Config;
|
||||
|
||||
lineStatement
|
||||
: (entry | (WHITESPACE? leadingComment) | WHITESPACE?) EOF
|
||||
: (entry | (leadingComment) | WHITESPACE?) EOF
|
||||
;
|
||||
|
||||
entry
|
||||
@ -17,7 +17,7 @@ key
|
||||
;
|
||||
|
||||
value
|
||||
: (STRING WHITESPACE)? STRING WHITESPACE?
|
||||
: (STRING WHITESPACE)* STRING? WHITESPACE?
|
||||
;
|
||||
|
||||
leadingComment
|
||||
|
@ -95,31 +95,41 @@ func (s *sshParserListener) ExitEntry(ctx *parser.EntryContext) {
|
||||
|
||||
if s.sshContext.isKeyAMatchBlock {
|
||||
// Add new match block
|
||||
match := match_parser.NewMatch()
|
||||
errors := match.Parse(s.sshContext.currentOption.OptionValue.Value, location.Start.Line)
|
||||
var match *match_parser.Match
|
||||
|
||||
if len(errors) > 0 {
|
||||
for _, err := range errors {
|
||||
s.Errors = append(s.Errors, common.LSPError{
|
||||
Range: err.Range.ShiftHorizontal(s.sshContext.currentOption.Start.Character),
|
||||
Err: err.Err,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
matchBlock := &SSHMatchBlock{
|
||||
LocationRange: location,
|
||||
MatchEntry: s.sshContext.currentOption,
|
||||
MatchValue: match,
|
||||
Options: treemap.NewWith(gods.UInt32Comparator),
|
||||
}
|
||||
s.Config.Options.Put(
|
||||
if s.sshContext.currentOption.OptionValue != nil {
|
||||
matchParser := match_parser.NewMatch()
|
||||
errors := matchParser.Parse(
|
||||
s.sshContext.currentOption.OptionValue.Value,
|
||||
location.Start.Line,
|
||||
matchBlock,
|
||||
s.sshContext.currentOption.OptionValue.Start.Character,
|
||||
)
|
||||
|
||||
s.sshContext.currentMatchBlock = matchBlock
|
||||
if len(errors) > 0 {
|
||||
for _, err := range errors {
|
||||
s.Errors = append(s.Errors, common.LSPError{
|
||||
Range: err.Range.ShiftHorizontal(s.sshContext.currentOption.Start.Character),
|
||||
Err: err.Err,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
match = matchParser
|
||||
}
|
||||
}
|
||||
|
||||
matchBlock := &SSHMatchBlock{
|
||||
LocationRange: location,
|
||||
MatchEntry: s.sshContext.currentOption,
|
||||
MatchValue: match,
|
||||
Options: treemap.NewWith(gods.UInt32Comparator),
|
||||
}
|
||||
s.Config.Options.Put(
|
||||
location.Start.Line,
|
||||
matchBlock,
|
||||
)
|
||||
|
||||
s.sshContext.currentMatchBlock = matchBlock
|
||||
|
||||
s.sshContext.isKeyAMatchBlock = false
|
||||
} else if s.sshContext.currentMatchBlock != nil {
|
||||
s.sshContext.currentMatchBlock.Options.Put(
|
||||
|
@ -22,4 +22,4 @@ leadingComment
|
||||
|
||||
|
||||
atn:
|
||||
[4, 1, 4, 64, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 1, 0, 1, 0, 3, 0, 15, 8, 0, 1, 0, 1, 0, 3, 0, 19, 8, 0, 3, 0, 21, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 26, 8, 1, 1, 1, 3, 1, 29, 8, 1, 1, 1, 3, 1, 32, 8, 1, 1, 1, 3, 1, 35, 8, 1, 1, 1, 3, 1, 38, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 46, 8, 4, 1, 4, 1, 4, 3, 4, 50, 8, 4, 1, 5, 1, 5, 3, 5, 54, 8, 5, 1, 5, 1, 5, 3, 5, 58, 8, 5, 4, 5, 60, 8, 5, 11, 5, 12, 5, 61, 1, 5, 0, 0, 6, 0, 2, 4, 6, 8, 10, 0, 0, 71, 0, 20, 1, 0, 0, 0, 2, 25, 1, 0, 0, 0, 4, 39, 1, 0, 0, 0, 6, 41, 1, 0, 0, 0, 8, 45, 1, 0, 0, 0, 10, 51, 1, 0, 0, 0, 12, 21, 3, 2, 1, 0, 13, 15, 5, 2, 0, 0, 14, 13, 1, 0, 0, 0, 14, 15, 1, 0, 0, 0, 15, 16, 1, 0, 0, 0, 16, 21, 3, 10, 5, 0, 17, 19, 5, 2, 0, 0, 18, 17, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19, 21, 1, 0, 0, 0, 20, 12, 1, 0, 0, 0, 20, 14, 1, 0, 0, 0, 20, 18, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 23, 5, 0, 0, 1, 23, 1, 1, 0, 0, 0, 24, 26, 5, 2, 0, 0, 25, 24, 1, 0, 0, 0, 25, 26, 1, 0, 0, 0, 26, 28, 1, 0, 0, 0, 27, 29, 3, 6, 3, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1, 0, 0, 0, 29, 31, 1, 0, 0, 0, 30, 32, 3, 4, 2, 0, 31, 30, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 34, 1, 0, 0, 0, 33, 35, 3, 8, 4, 0, 34, 33, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0, 35, 37, 1, 0, 0, 0, 36, 38, 3, 10, 5, 0, 37, 36, 1, 0, 0, 0, 37, 38, 1, 0, 0, 0, 38, 3, 1, 0, 0, 0, 39, 40, 5, 2, 0, 0, 40, 5, 1, 0, 0, 0, 41, 42, 5, 3, 0, 0, 42, 7, 1, 0, 0, 0, 43, 44, 5, 3, 0, 0, 44, 46, 5, 2, 0, 0, 45, 43, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 47, 1, 0, 0, 0, 47, 49, 5, 3, 0, 0, 48, 50, 5, 2, 0, 0, 49, 48, 1, 0, 0, 0, 49, 50, 1, 0, 0, 0, 50, 9, 1, 0, 0, 0, 51, 53, 5, 1, 0, 0, 52, 54, 5, 2, 0, 0, 53, 52, 1, 0, 0, 0, 53, 54, 1, 0, 0, 0, 54, 59, 1, 0, 0, 0, 55, 57, 5, 3, 0, 0, 56, 58, 5, 2, 0, 0, 57, 56, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 60, 1, 0, 0, 0, 59, 55, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 11, 1, 0, 0, 0, 13, 14, 18, 20, 25, 28, 31, 34, 37, 45, 49, 53, 57, 61]
|
||||
[4, 1, 4, 66, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 1, 0, 1, 0, 1, 0, 3, 0, 16, 8, 0, 3, 0, 18, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 23, 8, 1, 1, 1, 3, 1, 26, 8, 1, 1, 1, 3, 1, 29, 8, 1, 1, 1, 3, 1, 32, 8, 1, 1, 1, 3, 1, 35, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 5, 4, 43, 8, 4, 10, 4, 12, 4, 46, 9, 4, 1, 4, 3, 4, 49, 8, 4, 1, 4, 3, 4, 52, 8, 4, 1, 5, 1, 5, 3, 5, 56, 8, 5, 1, 5, 1, 5, 3, 5, 60, 8, 5, 4, 5, 62, 8, 5, 11, 5, 12, 5, 63, 1, 5, 0, 0, 6, 0, 2, 4, 6, 8, 10, 0, 0, 73, 0, 17, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 36, 1, 0, 0, 0, 6, 38, 1, 0, 0, 0, 8, 44, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 18, 3, 2, 1, 0, 13, 18, 3, 10, 5, 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, 12, 1, 0, 0, 0, 17, 13, 1, 0, 0, 0, 17, 15, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19, 20, 5, 0, 0, 1, 20, 1, 1, 0, 0, 0, 21, 23, 5, 2, 0, 0, 22, 21, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 25, 1, 0, 0, 0, 24, 26, 3, 6, 3, 0, 25, 24, 1, 0, 0, 0, 25, 26, 1, 0, 0, 0, 26, 28, 1, 0, 0, 0, 27, 29, 3, 4, 2, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1, 0, 0, 0, 29, 31, 1, 0, 0, 0, 30, 32, 3, 8, 4, 0, 31, 30, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 34, 1, 0, 0, 0, 33, 35, 3, 10, 5, 0, 34, 33, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0, 35, 3, 1, 0, 0, 0, 36, 37, 5, 2, 0, 0, 37, 5, 1, 0, 0, 0, 38, 39, 5, 3, 0, 0, 39, 7, 1, 0, 0, 0, 40, 41, 5, 3, 0, 0, 41, 43, 5, 2, 0, 0, 42, 40, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 48, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 49, 5, 3, 0, 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, 9, 1, 0, 0, 0, 53, 55, 5, 1, 0, 0, 54, 56, 5, 2, 0, 0, 55, 54, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 61, 1, 0, 0, 0, 57, 59, 5, 3, 0, 0, 58, 60, 5, 2, 0, 0, 59, 58, 1, 0, 0, 0, 59, 60, 1, 0, 0, 0, 60, 62, 1, 0, 0, 0, 61, 57, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 61, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0, 64, 11, 1, 0, 0, 0, 13, 15, 17, 22, 25, 28, 31, 34, 44, 48, 51, 55, 59, 63]
|
@ -43,34 +43,35 @@ func configParserInit() {
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 1, 4, 64, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4,
|
||||
2, 5, 7, 5, 1, 0, 1, 0, 3, 0, 15, 8, 0, 1, 0, 1, 0, 3, 0, 19, 8, 0, 3,
|
||||
0, 21, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 26, 8, 1, 1, 1, 3, 1, 29, 8, 1, 1,
|
||||
1, 3, 1, 32, 8, 1, 1, 1, 3, 1, 35, 8, 1, 1, 1, 3, 1, 38, 8, 1, 1, 2, 1,
|
||||
2, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 46, 8, 4, 1, 4, 1, 4, 3, 4, 50, 8, 4,
|
||||
1, 5, 1, 5, 3, 5, 54, 8, 5, 1, 5, 1, 5, 3, 5, 58, 8, 5, 4, 5, 60, 8, 5,
|
||||
11, 5, 12, 5, 61, 1, 5, 0, 0, 6, 0, 2, 4, 6, 8, 10, 0, 0, 71, 0, 20, 1,
|
||||
0, 0, 0, 2, 25, 1, 0, 0, 0, 4, 39, 1, 0, 0, 0, 6, 41, 1, 0, 0, 0, 8, 45,
|
||||
1, 0, 0, 0, 10, 51, 1, 0, 0, 0, 12, 21, 3, 2, 1, 0, 13, 15, 5, 2, 0, 0,
|
||||
14, 13, 1, 0, 0, 0, 14, 15, 1, 0, 0, 0, 15, 16, 1, 0, 0, 0, 16, 21, 3,
|
||||
10, 5, 0, 17, 19, 5, 2, 0, 0, 18, 17, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19,
|
||||
21, 1, 0, 0, 0, 20, 12, 1, 0, 0, 0, 20, 14, 1, 0, 0, 0, 20, 18, 1, 0, 0,
|
||||
0, 21, 22, 1, 0, 0, 0, 22, 23, 5, 0, 0, 1, 23, 1, 1, 0, 0, 0, 24, 26, 5,
|
||||
2, 0, 0, 25, 24, 1, 0, 0, 0, 25, 26, 1, 0, 0, 0, 26, 28, 1, 0, 0, 0, 27,
|
||||
29, 3, 6, 3, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1, 0, 0, 0, 29, 31, 1, 0, 0,
|
||||
0, 30, 32, 3, 4, 2, 0, 31, 30, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 34,
|
||||
1, 0, 0, 0, 33, 35, 3, 8, 4, 0, 34, 33, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0,
|
||||
35, 37, 1, 0, 0, 0, 36, 38, 3, 10, 5, 0, 37, 36, 1, 0, 0, 0, 37, 38, 1,
|
||||
0, 0, 0, 38, 3, 1, 0, 0, 0, 39, 40, 5, 2, 0, 0, 40, 5, 1, 0, 0, 0, 41,
|
||||
42, 5, 3, 0, 0, 42, 7, 1, 0, 0, 0, 43, 44, 5, 3, 0, 0, 44, 46, 5, 2, 0,
|
||||
0, 45, 43, 1, 0, 0, 0, 45, 46, 1, 0, 0, 0, 46, 47, 1, 0, 0, 0, 47, 49,
|
||||
5, 3, 0, 0, 48, 50, 5, 2, 0, 0, 49, 48, 1, 0, 0, 0, 49, 50, 1, 0, 0, 0,
|
||||
50, 9, 1, 0, 0, 0, 51, 53, 5, 1, 0, 0, 52, 54, 5, 2, 0, 0, 53, 52, 1, 0,
|
||||
0, 0, 53, 54, 1, 0, 0, 0, 54, 59, 1, 0, 0, 0, 55, 57, 5, 3, 0, 0, 56, 58,
|
||||
5, 2, 0, 0, 57, 56, 1, 0, 0, 0, 57, 58, 1, 0, 0, 0, 58, 60, 1, 0, 0, 0,
|
||||
59, 55, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1,
|
||||
0, 0, 0, 62, 11, 1, 0, 0, 0, 13, 14, 18, 20, 25, 28, 31, 34, 37, 45, 49,
|
||||
53, 57, 61,
|
||||
4, 1, 4, 66, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4,
|
||||
2, 5, 7, 5, 1, 0, 1, 0, 1, 0, 3, 0, 16, 8, 0, 3, 0, 18, 8, 0, 1, 0, 1,
|
||||
0, 1, 1, 3, 1, 23, 8, 1, 1, 1, 3, 1, 26, 8, 1, 1, 1, 3, 1, 29, 8, 1, 1,
|
||||
1, 3, 1, 32, 8, 1, 1, 1, 3, 1, 35, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4,
|
||||
1, 4, 5, 4, 43, 8, 4, 10, 4, 12, 4, 46, 9, 4, 1, 4, 3, 4, 49, 8, 4, 1,
|
||||
4, 3, 4, 52, 8, 4, 1, 5, 1, 5, 3, 5, 56, 8, 5, 1, 5, 1, 5, 3, 5, 60, 8,
|
||||
5, 4, 5, 62, 8, 5, 11, 5, 12, 5, 63, 1, 5, 0, 0, 6, 0, 2, 4, 6, 8, 10,
|
||||
0, 0, 73, 0, 17, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 36, 1, 0, 0, 0, 6, 38,
|
||||
1, 0, 0, 0, 8, 44, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 18, 3, 2, 1, 0,
|
||||
13, 18, 3, 10, 5, 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, 12, 1, 0, 0, 0, 17, 13, 1, 0, 0, 0, 17,
|
||||
15, 1, 0, 0, 0, 18, 19, 1, 0, 0, 0, 19, 20, 5, 0, 0, 1, 20, 1, 1, 0, 0,
|
||||
0, 21, 23, 5, 2, 0, 0, 22, 21, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 25,
|
||||
1, 0, 0, 0, 24, 26, 3, 6, 3, 0, 25, 24, 1, 0, 0, 0, 25, 26, 1, 0, 0, 0,
|
||||
26, 28, 1, 0, 0, 0, 27, 29, 3, 4, 2, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1,
|
||||
0, 0, 0, 29, 31, 1, 0, 0, 0, 30, 32, 3, 8, 4, 0, 31, 30, 1, 0, 0, 0, 31,
|
||||
32, 1, 0, 0, 0, 32, 34, 1, 0, 0, 0, 33, 35, 3, 10, 5, 0, 34, 33, 1, 0,
|
||||
0, 0, 34, 35, 1, 0, 0, 0, 35, 3, 1, 0, 0, 0, 36, 37, 5, 2, 0, 0, 37, 5,
|
||||
1, 0, 0, 0, 38, 39, 5, 3, 0, 0, 39, 7, 1, 0, 0, 0, 40, 41, 5, 3, 0, 0,
|
||||
41, 43, 5, 2, 0, 0, 42, 40, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1,
|
||||
0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 48, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47,
|
||||
49, 5, 3, 0, 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, 9, 1,
|
||||
0, 0, 0, 53, 55, 5, 1, 0, 0, 54, 56, 5, 2, 0, 0, 55, 54, 1, 0, 0, 0, 55,
|
||||
56, 1, 0, 0, 0, 56, 61, 1, 0, 0, 0, 57, 59, 5, 3, 0, 0, 58, 60, 5, 2, 0,
|
||||
0, 59, 58, 1, 0, 0, 0, 59, 60, 1, 0, 0, 0, 60, 62, 1, 0, 0, 0, 61, 57,
|
||||
1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 61, 1, 0, 0, 0, 63, 64, 1, 0, 0, 0,
|
||||
64, 11, 1, 0, 0, 0, 13, 15, 17, 22, 25, 28, 31, 34, 44, 48, 51, 55, 59,
|
||||
63,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
@ -240,13 +241,13 @@ func (p *ConfigParser) LineStatement() (localctx ILineStatementContext) {
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(20)
|
||||
p.SetState(17)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
|
||||
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) {
|
||||
switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 1, p.GetParserRuleContext()) {
|
||||
case 1:
|
||||
{
|
||||
p.SetState(12)
|
||||
@ -254,31 +255,13 @@ func (p *ConfigParser) LineStatement() (localctx ILineStatementContext) {
|
||||
}
|
||||
|
||||
case 2:
|
||||
p.SetState(14)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
{
|
||||
p.SetState(13)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
{
|
||||
p.SetState(16)
|
||||
p.SetState(13)
|
||||
p.LeadingComment()
|
||||
}
|
||||
|
||||
case 3:
|
||||
p.SetState(18)
|
||||
p.SetState(15)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -287,7 +270,7 @@ func (p *ConfigParser) LineStatement() (localctx ILineStatementContext) {
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
{
|
||||
p.SetState(17)
|
||||
p.SetState(14)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -301,7 +284,7 @@ func (p *ConfigParser) LineStatement() (localctx ILineStatementContext) {
|
||||
goto errorExit
|
||||
}
|
||||
{
|
||||
p.SetState(22)
|
||||
p.SetState(19)
|
||||
p.Match(ConfigParserEOF)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -466,17 +449,29 @@ func (p *ConfigParser) Entry() (localctx IEntryContext) {
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(22)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(21)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
goto errorExit
|
||||
}
|
||||
p.SetState(25)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(24)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
p.Key()
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
@ -488,7 +483,7 @@ func (p *ConfigParser) Entry() (localctx IEntryContext) {
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(27)
|
||||
p.Key()
|
||||
p.Separator()
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
@ -496,17 +491,15 @@ func (p *ConfigParser) Entry() (localctx IEntryContext) {
|
||||
}
|
||||
p.SetState(31)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 5, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(30)
|
||||
p.Separator()
|
||||
p.Value()
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
goto errorExit
|
||||
}
|
||||
p.SetState(34)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
@ -515,23 +508,9 @@ func (p *ConfigParser) Entry() (localctx IEntryContext) {
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == ConfigParserSTRING {
|
||||
{
|
||||
p.SetState(33)
|
||||
p.Value()
|
||||
}
|
||||
|
||||
}
|
||||
p.SetState(37)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == ConfigParserHASH {
|
||||
{
|
||||
p.SetState(36)
|
||||
p.SetState(33)
|
||||
p.LeadingComment()
|
||||
}
|
||||
|
||||
@ -625,7 +604,7 @@ func (p *ConfigParser) Separator() (localctx ISeparatorContext) {
|
||||
p.EnterRule(localctx, 4, ConfigParserRULE_separator)
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(39)
|
||||
p.SetState(36)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -721,7 +700,7 @@ func (p *ConfigParser) Key() (localctx IKeyContext) {
|
||||
p.EnterRule(localctx, 6, ConfigParserRULE_key)
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(41)
|
||||
p.SetState(38)
|
||||
p.Match(ConfigParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -832,40 +811,67 @@ func (p *ConfigParser) Value() (localctx IValueContext) {
|
||||
p.EnterRule(localctx, 8, ConfigParserRULE_value)
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(45)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
var _alt int
|
||||
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 8, p.GetParserRuleContext()) == 1 {
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(44)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 7, p.GetParserRuleContext())
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
|
||||
if _alt == 1 {
|
||||
{
|
||||
p.SetState(40)
|
||||
p.Match(ConfigParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
{
|
||||
p.SetState(41)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
p.SetState(46)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 7, p.GetParserRuleContext())
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
p.SetState(48)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == ConfigParserSTRING {
|
||||
{
|
||||
p.SetState(43)
|
||||
p.SetState(47)
|
||||
p.Match(ConfigParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
{
|
||||
p.SetState(44)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
goto errorExit
|
||||
}
|
||||
{
|
||||
p.SetState(47)
|
||||
p.Match(ConfigParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
p.SetState(49)
|
||||
p.SetState(51)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -874,7 +880,7 @@ func (p *ConfigParser) Value() (localctx IValueContext) {
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
{
|
||||
p.SetState(48)
|
||||
p.SetState(50)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -994,14 +1000,14 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(51)
|
||||
p.SetState(53)
|
||||
p.Match(ConfigParserHASH)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
p.SetState(53)
|
||||
p.SetState(55)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -1010,7 +1016,7 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
{
|
||||
p.SetState(52)
|
||||
p.SetState(54)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -1019,7 +1025,7 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
}
|
||||
|
||||
}
|
||||
p.SetState(59)
|
||||
p.SetState(61)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -1028,14 +1034,14 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
|
||||
for ok := true; ok; ok = _la == ConfigParserSTRING {
|
||||
{
|
||||
p.SetState(55)
|
||||
p.SetState(57)
|
||||
p.Match(ConfigParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
p.SetState(57)
|
||||
p.SetState(59)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -1044,7 +1050,7 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
|
||||
if _la == ConfigParserWHITESPACE {
|
||||
{
|
||||
p.SetState(56)
|
||||
p.SetState(58)
|
||||
p.Match(ConfigParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -1054,7 +1060,7 @@ func (p *ConfigParser) LeadingComment() (localctx ILeadingCommentContext) {
|
||||
|
||||
}
|
||||
|
||||
p.SetState(61)
|
||||
p.SetState(63)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
|
@ -92,7 +92,7 @@ Match Address 192.168.0.1
|
||||
t.Errorf("Expected second entry to be 'Match Address 192.168.0.1', but got: %v", secondEntry.MatchEntry.Value)
|
||||
}
|
||||
|
||||
if !(secondEntry.MatchValue.Entries[0].Criteria == "Address" && secondEntry.MatchValue.Entries[0].Values[0].Value == "192.168.0.1") {
|
||||
if !(secondEntry.MatchValue.Entries[0].Criteria.Type == "Address" && secondEntry.MatchValue.Entries[0].Values.Values[0].Value == "192.168.0.1" && secondEntry.MatchEntry.OptionValue.Start.Character == 6) {
|
||||
t.Errorf("Expected second entry to be 'Match Address 192.168.0.1', but got: %v", secondEntry.MatchValue)
|
||||
}
|
||||
|
||||
@ -107,6 +107,65 @@ Match Address 192.168.0.1
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleEntriesInMatchBlock(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
Match User lena User root
|
||||
`)
|
||||
p := NewSSHConfig()
|
||||
errors := p.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Fatalf("Expected no errors, got %v", errors)
|
||||
}
|
||||
|
||||
_, matchBlock := p.FindOption(uint32(0))
|
||||
|
||||
if !(matchBlock.MatchEntry.Value == "Match User lena User root") {
|
||||
t.Errorf("Expected match block to be 'Match User lena User root', but got: %v", matchBlock.MatchEntry.Value)
|
||||
}
|
||||
|
||||
if !(len(matchBlock.MatchValue.Entries) == 2) {
|
||||
t.Errorf("Expected 2 entries in match block, but got: %v", matchBlock.MatchValue.Entries)
|
||||
}
|
||||
|
||||
if !(matchBlock.MatchValue.Entries[0].Criteria.Type == "User" && matchBlock.MatchValue.Entries[0].Values.Values[0].Value == "lena") {
|
||||
t.Errorf("Expected first entry to be 'User lena', but got: %v", matchBlock.MatchValue.Entries[0])
|
||||
}
|
||||
|
||||
if !(matchBlock.MatchValue.Entries[1].Criteria.Type == "User" && matchBlock.MatchValue.Entries[1].Values.Values[0].Value == "root") {
|
||||
t.Errorf("Expected second entry to be 'User root', but got: %v", matchBlock.MatchValue.Entries[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncompleteMatchBlock(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := "Match User lena User "
|
||||
|
||||
p := NewSSHConfig()
|
||||
errors := p.Parse(input)
|
||||
|
||||
if !(len(errors) == 0) {
|
||||
t.Errorf("Expected 0 error, got %v", errors)
|
||||
}
|
||||
|
||||
_, matchBlock := p.FindOption(uint32(0))
|
||||
|
||||
if !(matchBlock.MatchEntry.Value == "Match User lena User ") {
|
||||
t.Errorf("Expected match block to be 'Match User lena User ', but got: %v", matchBlock.MatchEntry.Value)
|
||||
}
|
||||
|
||||
if !(matchBlock.MatchValue.Entries[0].Criteria.Type == "User" && matchBlock.MatchValue.Entries[0].Values.Values[0].Value == "lena") {
|
||||
t.Errorf("Expected first entry to be 'User lena', but got: %v", matchBlock.MatchValue.Entries[0])
|
||||
}
|
||||
|
||||
if !(matchBlock.MatchValue.Entries[1].Value == "User " && matchBlock.MatchValue.Entries[1].Criteria.Type == "User" && matchBlock.MatchValue.Entries[1].Values == nil) {
|
||||
t.Errorf("Expected second entry to be 'User ', but got: %v", matchBlock.MatchValue.Entries[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleMatchBlocks(
|
||||
t *testing.T,
|
||||
) {
|
||||
@ -168,12 +227,12 @@ Match Address 192.168.0.2
|
||||
}
|
||||
|
||||
emptyOption, matchBlock := p.FindOption(uint32(5))
|
||||
if !(emptyOption == nil && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values[0].Value == "lena") {
|
||||
if !(emptyOption == nil && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values.Values[0].Value == "lena") {
|
||||
t.Errorf("Expected empty option and match block to be 'Match User lena', but got: %v, %v", emptyOption, matchBlock)
|
||||
}
|
||||
|
||||
matchOption, matchBlock := p.FindOption(uint32(2))
|
||||
if !(matchOption.Value == "Match User lena" && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values[0].Value == "lena") {
|
||||
if !(matchOption.Value == "Match User lena" && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values.Values[0].Value == "lena" && matchBlock.MatchEntry.OptionValue.Start.Character == 6) {
|
||||
t.Errorf("Expected match option to be 'Match User lena', but got: %v, %v", matchOption, matchBlock)
|
||||
}
|
||||
}
|
||||
@ -416,7 +475,7 @@ Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1
|
||||
t.Errorf("Expected fourth entry to be 'Match User anoncvs', but got: %v", fourthEntry.MatchEntry.Value)
|
||||
}
|
||||
|
||||
if !(fourthEntry.MatchValue.Entries[0].Criteria == "User" && fourthEntry.MatchValue.Entries[0].Values[0].Value == "anoncvs") {
|
||||
if !(fourthEntry.MatchValue.Entries[0].Criteria.Type == "User" && fourthEntry.MatchValue.Entries[0].Values.Values[0].Value == "anoncvs") {
|
||||
t.Errorf("Expected fourth entry to be 'Match User anoncvs', but got: %v", fourthEntry.MatchValue)
|
||||
}
|
||||
|
||||
@ -440,7 +499,7 @@ Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1
|
||||
t.Errorf("Expected sixth entry to be 'Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1', but got: %v", sixthEntry.MatchEntry.Value)
|
||||
}
|
||||
|
||||
if !(sixthEntry.MatchValue.Entries[0].Criteria == "Address" && len(sixthEntry.MatchValue.Entries[0].Values) == 3) {
|
||||
if !(sixthEntry.MatchValue.Entries[0].Criteria.Type == "Address" && len(sixthEntry.MatchValue.Entries[0].Values.Values) == 3) {
|
||||
t.Errorf("Expected sixth entry to contain 3 values, but got: %v", sixthEntry.MatchValue)
|
||||
}
|
||||
|
||||
|
@ -42,14 +42,6 @@ type SSHOption struct {
|
||||
OptionValue *SSHValue
|
||||
}
|
||||
|
||||
func (o SSHOption) GetType() SSHEntryType {
|
||||
return SSHEntryTypeOption
|
||||
}
|
||||
|
||||
func (o SSHOption) GetOption() SSHOption {
|
||||
return o
|
||||
}
|
||||
|
||||
type SSHMatchBlock struct {
|
||||
common.LocationRange
|
||||
MatchEntry *SSHOption
|
||||
@ -59,66 +51,9 @@ type SSHMatchBlock struct {
|
||||
Options *treemap.Map
|
||||
}
|
||||
|
||||
func (m SSHMatchBlock) GetType() SSHEntryType {
|
||||
return SSHEntryTypeMatchBlock
|
||||
}
|
||||
|
||||
func (m SSHMatchBlock) GetOption() SSHOption {
|
||||
return *m.MatchEntry
|
||||
}
|
||||
|
||||
type SSHConfig struct {
|
||||
// [uint32]SSHOption -> line number -> *SSHEntry
|
||||
Options *treemap.Map
|
||||
// [uint32]{} -> line number -> {}
|
||||
CommentLines map[uint32]struct{}
|
||||
}
|
||||
|
||||
func (c SSHConfig) FindMatchBlock(line uint32) *SSHMatchBlock {
|
||||
for currentLine := line; currentLine > 0; currentLine-- {
|
||||
rawEntry, found := c.Options.Get(currentLine)
|
||||
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
switch entry := rawEntry.(type) {
|
||||
case *SSHMatchBlock:
|
||||
return entry
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c SSHConfig) FindOption(line uint32) (*SSHOption, *SSHMatchBlock) {
|
||||
matchBlock := c.FindMatchBlock(line)
|
||||
|
||||
if matchBlock != nil {
|
||||
if line == matchBlock.MatchEntry.Start.Line {
|
||||
return matchBlock.MatchEntry, matchBlock
|
||||
}
|
||||
|
||||
rawEntry, found := matchBlock.Options.Get(line)
|
||||
|
||||
if found {
|
||||
return rawEntry.(*SSHOption), matchBlock
|
||||
} else {
|
||||
return nil, matchBlock
|
||||
}
|
||||
}
|
||||
|
||||
rawEntry, found := c.Options.Get(line)
|
||||
|
||||
if found {
|
||||
switch rawEntry.(type) {
|
||||
case *SSHMatchBlock:
|
||||
return rawEntry.(*SSHMatchBlock).MatchEntry, rawEntry.(*SSHMatchBlock)
|
||||
case *SSHOption:
|
||||
return rawEntry.(*SSHOption), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
||||
}
|
||||
|
66
handlers/sshd_config/ast/sshd_config_fields.go
Normal file
66
handlers/sshd_config/ast/sshd_config_fields.go
Normal file
@ -0,0 +1,66 @@
|
||||
package ast
|
||||
|
||||
func (o SSHOption) GetType() SSHEntryType {
|
||||
return SSHEntryTypeOption
|
||||
}
|
||||
|
||||
func (o SSHOption) GetOption() SSHOption {
|
||||
return o
|
||||
}
|
||||
|
||||
func (m SSHMatchBlock) GetType() SSHEntryType {
|
||||
return SSHEntryTypeMatchBlock
|
||||
}
|
||||
|
||||
func (m SSHMatchBlock) GetOption() SSHOption {
|
||||
return *m.MatchEntry
|
||||
}
|
||||
|
||||
func (c SSHConfig) FindMatchBlock(line uint32) *SSHMatchBlock {
|
||||
for currentLine := line; currentLine > 0; currentLine-- {
|
||||
rawEntry, found := c.Options.Get(currentLine)
|
||||
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
switch entry := rawEntry.(type) {
|
||||
case *SSHMatchBlock:
|
||||
return entry
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c SSHConfig) FindOption(line uint32) (*SSHOption, *SSHMatchBlock) {
|
||||
matchBlock := c.FindMatchBlock(line)
|
||||
|
||||
if matchBlock != nil {
|
||||
if line == matchBlock.MatchEntry.Start.Line {
|
||||
return matchBlock.MatchEntry, matchBlock
|
||||
}
|
||||
|
||||
rawEntry, found := matchBlock.Options.Get(line)
|
||||
|
||||
if found {
|
||||
return rawEntry.(*SSHOption), matchBlock
|
||||
} else {
|
||||
return nil, matchBlock
|
||||
}
|
||||
}
|
||||
|
||||
rawEntry, found := c.Options.Get(line)
|
||||
|
||||
if found {
|
||||
switch rawEntry.(type) {
|
||||
case *SSHMatchBlock:
|
||||
return rawEntry.(*SSHMatchBlock).MatchEntry, rawEntry.(*SSHMatchBlock)
|
||||
case *SSHOption:
|
||||
return rawEntry.(*SSHOption), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
||||
}
|
@ -563,27 +563,7 @@ The arguments to Match are one or more criteria-pattern pairs or the single toke
|
||||
The match patterns may consist of single entries or comma-separated lists and may use the wildcard and negation operators described in the “PATTERNS” section of ssh_config(5).
|
||||
The patterns in an Address criteria may additionally contain addresses to match in CIDR address/masklen format, such as 192.0.2.0/24 or 2001:db8::/32. Note that the mask length provided must be consistent with the address - it is an error to specify a mask length that is too long for the address or one with bits set in this host portion of the address. For example, 192.0.2.0/33 and 192.0.2.0/8, respectively.
|
||||
Only a subset of keywords may be used on the lines following a Match keyword. Available keywords are AcceptEnv, AllowAgentForwarding, AllowGroups, AllowStreamLocalForwarding, AllowTcpForwarding, AllowUsers, AuthenticationMethods, AuthorizedKeysCommand, AuthorizedKeysCommandUser, AuthorizedKeysFile, AuthorizedPrincipalsCommand, AuthorizedPrincipalsCommandUser, AuthorizedPrincipalsFile, Banner, CASignatureAlgorithms, ChannelTimeout, ChrootDirectory, ClientAliveCountMax, ClientAliveInterval, DenyGroups, DenyUsers, DisableForwarding, ExposeAuthInfo, ForceCommand, GatewayPorts, GSSAPIAuthentication, HostbasedAcceptedAlgorithms, HostbasedAuthentication, HostbasedUsesNameFromPacketOnly, IgnoreRhosts, Include, IPQoS, KbdInteractiveAuthentication, KerberosAuthentication, LogLevel, MaxAuthTries, MaxSessions, PasswordAuthentication, PermitEmptyPasswords, PermitListen, PermitOpen, PermitRootLogin, PermitTTY, PermitTunnel, PermitUserRC, PubkeyAcceptedAlgorithms, PubkeyAuthentication, PubkeyAuthOptions, RekeyLimit, RevokedKeys, RDomain, SetEnv, StreamLocalBindMask, StreamLocalBindUnlink, TrustedUserCAKeys, UnusedConnectionTimeout, X11DisplayOffset, X11Forwarding and X11UseLocalhost.`,
|
||||
Value: docvalues.OrValue{
|
||||
Values: []docvalues.Value{
|
||||
docvalues.SingleEnumValue("All"),
|
||||
docvalues.ArrayValue{
|
||||
Separator: ",",
|
||||
DuplicatesExtractor: &docvalues.SimpleDuplicatesExtractor,
|
||||
SubValue: docvalues.KeyEnumAssignmentValue{
|
||||
Separator: " ",
|
||||
Values: map[docvalues.EnumString]docvalues.Value{
|
||||
docvalues.CreateEnumString("User"): docvalues.UserValue("", false),
|
||||
docvalues.CreateEnumString("Group"): docvalues.GroupValue("", false),
|
||||
docvalues.CreateEnumString("Host"): docvalues.StringValue{},
|
||||
docvalues.CreateEnumString("LocalAddress"): docvalues.StringValue{},
|
||||
docvalues.CreateEnumString("LocalPort"): docvalues.NumberValue{Min: &ZERO, Max: &MAX_PORT},
|
||||
docvalues.CreateEnumString("RDomain"): docvalues.StringValue{},
|
||||
docvalues.CreateEnumString("Address"): docvalues.StringValue{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Value: docvalues.StringValue{},
|
||||
},
|
||||
"MaxAuthTries": {
|
||||
Documentation: `Specifies the maximum number of authentication attempts permitted per connection. Once the number of failures reaches half this value, additional failures are logged. The default is 6.`,
|
||||
|
@ -1,25 +1,23 @@
|
||||
grammar Match;
|
||||
|
||||
root
|
||||
: matchEntry? (WHITESPACE matchEntry)* EOF
|
||||
: matchEntry? (WHITESPACE matchEntry?)* EOF
|
||||
;
|
||||
|
||||
matchEntry
|
||||
: criteria WHITESPACE? values?
|
||||
: criteria separator? values?
|
||||
;
|
||||
|
||||
separator
|
||||
: WHITESPACE
|
||||
;
|
||||
|
||||
criteria
|
||||
: USER
|
||||
| GROUP
|
||||
| HOST
|
||||
| LOCALADDRESS
|
||||
| LOCALPORT
|
||||
| RDOMAIN
|
||||
| ADDRESS
|
||||
: (USER | GROUP | HOST| LOCALADDRESS | LOCALPORT | RDOMAIN | ADDRESS)
|
||||
;
|
||||
|
||||
values
|
||||
: value? (COMMA value?)*
|
||||
: value (COMMA value?)*
|
||||
;
|
||||
|
||||
value
|
||||
|
@ -11,16 +11,19 @@ import (
|
||||
|
||||
func createMatchListenerContext(
|
||||
line uint32,
|
||||
startCharacter uint32,
|
||||
) *matchListenerContext {
|
||||
return &matchListenerContext{
|
||||
currentEntry: nil,
|
||||
line: line,
|
||||
currentEntry: nil,
|
||||
line: line,
|
||||
startCharacter: startCharacter,
|
||||
}
|
||||
}
|
||||
|
||||
type matchListenerContext struct {
|
||||
currentEntry *MatchEntry
|
||||
line uint32
|
||||
currentEntry *MatchEntry
|
||||
line uint32
|
||||
startCharacter uint32
|
||||
}
|
||||
|
||||
func createListener(
|
||||
@ -42,13 +45,12 @@ type matchParserListener struct {
|
||||
}
|
||||
|
||||
func (s *matchParserListener) EnterMatchEntry(ctx *parser.MatchEntryContext) {
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext).ShiftHorizontal(s.matchContext.startCharacter)
|
||||
location.ChangeBothLines(s.matchContext.line)
|
||||
|
||||
entry := &MatchEntry{
|
||||
LocationRange: location,
|
||||
Value: ctx.GetText(),
|
||||
Values: make([]*MatchValue, 0),
|
||||
}
|
||||
|
||||
s.match.Entries = append(s.match.Entries, entry)
|
||||
@ -70,7 +72,7 @@ var availableCriteria = map[string]MatchCriteriaType{
|
||||
}
|
||||
|
||||
func (s *matchParserListener) EnterCriteria(ctx *parser.CriteriaContext) {
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext).ShiftHorizontal(s.matchContext.startCharacter)
|
||||
location.ChangeBothLines(s.matchContext.line)
|
||||
|
||||
criteria, found := availableCriteria[ctx.GetText()]
|
||||
@ -83,11 +85,33 @@ func (s *matchParserListener) EnterCriteria(ctx *parser.CriteriaContext) {
|
||||
return
|
||||
}
|
||||
|
||||
s.matchContext.currentEntry.Criteria = criteria
|
||||
s.matchContext.currentEntry.Criteria = MatchCriteria{
|
||||
LocationRange: location,
|
||||
Type: criteria,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *matchParserListener) EnterSeparator(ctx *parser.SeparatorContext) {
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext).ShiftHorizontal(s.matchContext.startCharacter)
|
||||
location.ChangeBothLines(s.matchContext.line)
|
||||
|
||||
s.matchContext.currentEntry.Separator = &MatchSeparator{
|
||||
LocationRange: location,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *matchParserListener) EnterValues(ctx *parser.ValuesContext) {
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext).ShiftHorizontal(s.matchContext.startCharacter)
|
||||
location.ChangeBothLines(s.matchContext.line)
|
||||
|
||||
s.matchContext.currentEntry.Values = &MatchValues{
|
||||
LocationRange: location,
|
||||
Values: make([]*MatchValue, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *matchParserListener) EnterValue(ctx *parser.ValueContext) {
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext).ShiftHorizontal(s.matchContext.startCharacter)
|
||||
location.ChangeBothLines(s.matchContext.line)
|
||||
|
||||
value := &MatchValue{
|
||||
@ -95,5 +119,5 @@ func (s *matchParserListener) EnterValue(ctx *parser.ValueContext) {
|
||||
Value: ctx.GetText(),
|
||||
}
|
||||
|
||||
s.matchContext.currentEntry.Values = append(s.matchContext.currentEntry.Values, value)
|
||||
s.matchContext.currentEntry.Values.Values = append(s.matchContext.currentEntry.Values.Values, value)
|
||||
}
|
||||
|
@ -26,12 +26,23 @@ type MatchCriteria struct {
|
||||
Type MatchCriteriaType
|
||||
}
|
||||
|
||||
type MatchSeparator struct {
|
||||
common.LocationRange
|
||||
}
|
||||
|
||||
type MatchValues struct {
|
||||
common.LocationRange
|
||||
|
||||
Values []*MatchValue
|
||||
}
|
||||
|
||||
type MatchEntry struct {
|
||||
common.LocationRange
|
||||
Value string
|
||||
|
||||
Criteria MatchCriteriaType
|
||||
Values []*MatchValue
|
||||
Criteria MatchCriteria
|
||||
Separator *MatchSeparator
|
||||
Values *MatchValues
|
||||
}
|
||||
|
||||
type MatchValue struct {
|
||||
|
67
handlers/sshd_config/fields/match-parser/match_fields.go
Normal file
67
handlers/sshd_config/fields/match-parser/match_fields.go
Normal file
@ -0,0 +1,67 @@
|
||||
package match_parser
|
||||
|
||||
import "slices"
|
||||
|
||||
func (m Match) GetEntryByCursor(cursor uint32) *MatchEntry {
|
||||
index, found := slices.BinarySearchFunc(
|
||||
m.Entries,
|
||||
cursor,
|
||||
func(entry *MatchEntry, cursor uint32) int {
|
||||
if cursor < entry.Start.Character {
|
||||
return 1
|
||||
}
|
||||
|
||||
if cursor > entry.End.Character {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
},
|
||||
)
|
||||
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
entry := m.Entries[index]
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
func (c MatchCriteria) IsCursorBetween(cursor uint32) bool {
|
||||
return cursor >= c.Start.Character && cursor <= c.End.Character
|
||||
}
|
||||
|
||||
func (e MatchEntry) GetValueByCursor(cursor uint32) *MatchValue {
|
||||
if e.Values == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
index, found := slices.BinarySearchFunc(
|
||||
e.Values.Values,
|
||||
cursor,
|
||||
func(value *MatchValue, cursor uint32) int {
|
||||
if cursor < value.Start.Character {
|
||||
return 1
|
||||
}
|
||||
|
||||
if cursor > value.End.Character {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
},
|
||||
)
|
||||
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
value := e.Values.Values[index]
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func (v MatchValues) IsCursorBetween(cursor uint32) bool {
|
||||
return cursor >= v.Start.Character && cursor <= v.End.Character
|
||||
}
|
@ -20,8 +20,9 @@ func (m *Match) Clear() {
|
||||
func (m *Match) Parse(
|
||||
input string,
|
||||
line uint32,
|
||||
startCharacter uint32,
|
||||
) []common.LSPError {
|
||||
context := createMatchListenerContext(line)
|
||||
context := createMatchListenerContext(line, startCharacter)
|
||||
|
||||
stream := antlr.NewInputStream(input)
|
||||
|
||||
|
@ -27,10 +27,11 @@ WHITESPACE
|
||||
rule names:
|
||||
root
|
||||
matchEntry
|
||||
separator
|
||||
criteria
|
||||
values
|
||||
value
|
||||
|
||||
|
||||
atn:
|
||||
[4, 1, 10, 46, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 1, 0, 3, 0, 12, 8, 0, 1, 0, 1, 0, 5, 0, 16, 8, 0, 10, 0, 12, 0, 19, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 25, 8, 1, 1, 1, 3, 1, 28, 8, 1, 1, 2, 1, 2, 1, 3, 3, 3, 33, 8, 3, 1, 3, 1, 3, 3, 3, 37, 8, 3, 5, 3, 39, 8, 3, 10, 3, 12, 3, 42, 9, 3, 1, 4, 1, 4, 1, 4, 0, 0, 5, 0, 2, 4, 6, 8, 0, 1, 1, 0, 1, 7, 47, 0, 11, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 29, 1, 0, 0, 0, 6, 32, 1, 0, 0, 0, 8, 43, 1, 0, 0, 0, 10, 12, 3, 2, 1, 0, 11, 10, 1, 0, 0, 0, 11, 12, 1, 0, 0, 0, 12, 17, 1, 0, 0, 0, 13, 14, 5, 10, 0, 0, 14, 16, 3, 2, 1, 0, 15, 13, 1, 0, 0, 0, 16, 19, 1, 0, 0, 0, 17, 15, 1, 0, 0, 0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 17, 1, 0, 0, 0, 20, 21, 5, 0, 0, 1, 21, 1, 1, 0, 0, 0, 22, 24, 3, 4, 2, 0, 23, 25, 5, 10, 0, 0, 24, 23, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 27, 1, 0, 0, 0, 26, 28, 3, 6, 3, 0, 27, 26, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 3, 1, 0, 0, 0, 29, 30, 7, 0, 0, 0, 30, 5, 1, 0, 0, 0, 31, 33, 3, 8, 4, 0, 32, 31, 1, 0, 0, 0, 32, 33, 1, 0, 0, 0, 33, 40, 1, 0, 0, 0, 34, 36, 5, 8, 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, 34, 1, 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 7, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 44, 5, 9, 0, 0, 44, 9, 1, 0, 0, 0, 7, 11, 17, 24, 27, 32, 36, 40]
|
||||
[4, 1, 10, 50, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 1, 0, 3, 0, 14, 8, 0, 1, 0, 1, 0, 3, 0, 18, 8, 0, 5, 0, 20, 8, 0, 10, 0, 12, 0, 23, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 29, 8, 1, 1, 1, 3, 1, 32, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 3, 4, 41, 8, 4, 5, 4, 43, 8, 4, 10, 4, 12, 4, 46, 9, 4, 1, 5, 1, 5, 1, 5, 0, 0, 6, 0, 2, 4, 6, 8, 10, 0, 1, 1, 0, 1, 7, 50, 0, 13, 1, 0, 0, 0, 2, 26, 1, 0, 0, 0, 4, 33, 1, 0, 0, 0, 6, 35, 1, 0, 0, 0, 8, 37, 1, 0, 0, 0, 10, 47, 1, 0, 0, 0, 12, 14, 3, 2, 1, 0, 13, 12, 1, 0, 0, 0, 13, 14, 1, 0, 0, 0, 14, 21, 1, 0, 0, 0, 15, 17, 5, 10, 0, 0, 16, 18, 3, 2, 1, 0, 17, 16, 1, 0, 0, 0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 15, 1, 0, 0, 0, 20, 23, 1, 0, 0, 0, 21, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 24, 1, 0, 0, 0, 23, 21, 1, 0, 0, 0, 24, 25, 5, 0, 0, 1, 25, 1, 1, 0, 0, 0, 26, 28, 3, 6, 3, 0, 27, 29, 3, 4, 2, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1, 0, 0, 0, 29, 31, 1, 0, 0, 0, 30, 32, 3, 8, 4, 0, 31, 30, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 3, 1, 0, 0, 0, 33, 34, 5, 10, 0, 0, 34, 5, 1, 0, 0, 0, 35, 36, 7, 0, 0, 0, 36, 7, 1, 0, 0, 0, 37, 44, 3, 10, 5, 0, 38, 40, 5, 8, 0, 0, 39, 41, 3, 10, 5, 0, 40, 39, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 43, 1, 0, 0, 0, 42, 38, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 9, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 48, 5, 9, 0, 0, 48, 11, 1, 0, 0, 0, 7, 13, 17, 21, 28, 31, 40, 44]
|
@ -33,6 +33,12 @@ func (s *BaseMatchListener) EnterMatchEntry(ctx *MatchEntryContext) {}
|
||||
// ExitMatchEntry is called when production matchEntry is exited.
|
||||
func (s *BaseMatchListener) ExitMatchEntry(ctx *MatchEntryContext) {}
|
||||
|
||||
// EnterSeparator is called when production separator is entered.
|
||||
func (s *BaseMatchListener) EnterSeparator(ctx *SeparatorContext) {}
|
||||
|
||||
// ExitSeparator is called when production separator is exited.
|
||||
func (s *BaseMatchListener) ExitSeparator(ctx *SeparatorContext) {}
|
||||
|
||||
// EnterCriteria is called when production criteria is entered.
|
||||
func (s *BaseMatchListener) EnterCriteria(ctx *CriteriaContext) {}
|
||||
|
||||
|
@ -14,6 +14,9 @@ type MatchListener interface {
|
||||
// EnterMatchEntry is called when entering the matchEntry production.
|
||||
EnterMatchEntry(c *MatchEntryContext)
|
||||
|
||||
// EnterSeparator is called when entering the separator production.
|
||||
EnterSeparator(c *SeparatorContext)
|
||||
|
||||
// EnterCriteria is called when entering the criteria production.
|
||||
EnterCriteria(c *CriteriaContext)
|
||||
|
||||
@ -29,6 +32,9 @@ type MatchListener interface {
|
||||
// ExitMatchEntry is called when exiting the matchEntry production.
|
||||
ExitMatchEntry(c *MatchEntryContext)
|
||||
|
||||
// ExitSeparator is called when exiting the separator production.
|
||||
ExitSeparator(c *SeparatorContext)
|
||||
|
||||
// ExitCriteria is called when exiting the criteria production.
|
||||
ExitCriteria(c *CriteriaContext)
|
||||
|
||||
|
@ -40,29 +40,30 @@ func matchParserInit() {
|
||||
"ADDRESS", "COMMA", "STRING", "WHITESPACE",
|
||||
}
|
||||
staticData.RuleNames = []string{
|
||||
"root", "matchEntry", "criteria", "values", "value",
|
||||
"root", "matchEntry", "separator", "criteria", "values", "value",
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 1, 10, 46, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7,
|
||||
4, 1, 0, 3, 0, 12, 8, 0, 1, 0, 1, 0, 5, 0, 16, 8, 0, 10, 0, 12, 0, 19,
|
||||
9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 25, 8, 1, 1, 1, 3, 1, 28, 8, 1, 1,
|
||||
2, 1, 2, 1, 3, 3, 3, 33, 8, 3, 1, 3, 1, 3, 3, 3, 37, 8, 3, 5, 3, 39, 8,
|
||||
3, 10, 3, 12, 3, 42, 9, 3, 1, 4, 1, 4, 1, 4, 0, 0, 5, 0, 2, 4, 6, 8, 0,
|
||||
1, 1, 0, 1, 7, 47, 0, 11, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 29, 1, 0, 0,
|
||||
0, 6, 32, 1, 0, 0, 0, 8, 43, 1, 0, 0, 0, 10, 12, 3, 2, 1, 0, 11, 10, 1,
|
||||
0, 0, 0, 11, 12, 1, 0, 0, 0, 12, 17, 1, 0, 0, 0, 13, 14, 5, 10, 0, 0, 14,
|
||||
16, 3, 2, 1, 0, 15, 13, 1, 0, 0, 0, 16, 19, 1, 0, 0, 0, 17, 15, 1, 0, 0,
|
||||
0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 17, 1, 0, 0, 0, 20, 21,
|
||||
5, 0, 0, 1, 21, 1, 1, 0, 0, 0, 22, 24, 3, 4, 2, 0, 23, 25, 5, 10, 0, 0,
|
||||
24, 23, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 27, 1, 0, 0, 0, 26, 28, 3,
|
||||
6, 3, 0, 27, 26, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 3, 1, 0, 0, 0, 29,
|
||||
30, 7, 0, 0, 0, 30, 5, 1, 0, 0, 0, 31, 33, 3, 8, 4, 0, 32, 31, 1, 0, 0,
|
||||
0, 32, 33, 1, 0, 0, 0, 33, 40, 1, 0, 0, 0, 34, 36, 5, 8, 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, 34, 1, 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1,
|
||||
0, 0, 0, 41, 7, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 44, 5, 9, 0, 0, 44,
|
||||
9, 1, 0, 0, 0, 7, 11, 17, 24, 27, 32, 36, 40,
|
||||
4, 1, 10, 50, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7,
|
||||
4, 2, 5, 7, 5, 1, 0, 3, 0, 14, 8, 0, 1, 0, 1, 0, 3, 0, 18, 8, 0, 5, 0,
|
||||
20, 8, 0, 10, 0, 12, 0, 23, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 29, 8,
|
||||
1, 1, 1, 3, 1, 32, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 3, 4,
|
||||
41, 8, 4, 5, 4, 43, 8, 4, 10, 4, 12, 4, 46, 9, 4, 1, 5, 1, 5, 1, 5, 0,
|
||||
0, 6, 0, 2, 4, 6, 8, 10, 0, 1, 1, 0, 1, 7, 50, 0, 13, 1, 0, 0, 0, 2, 26,
|
||||
1, 0, 0, 0, 4, 33, 1, 0, 0, 0, 6, 35, 1, 0, 0, 0, 8, 37, 1, 0, 0, 0, 10,
|
||||
47, 1, 0, 0, 0, 12, 14, 3, 2, 1, 0, 13, 12, 1, 0, 0, 0, 13, 14, 1, 0, 0,
|
||||
0, 14, 21, 1, 0, 0, 0, 15, 17, 5, 10, 0, 0, 16, 18, 3, 2, 1, 0, 17, 16,
|
||||
1, 0, 0, 0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 15, 1, 0, 0, 0,
|
||||
20, 23, 1, 0, 0, 0, 21, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 24, 1,
|
||||
0, 0, 0, 23, 21, 1, 0, 0, 0, 24, 25, 5, 0, 0, 1, 25, 1, 1, 0, 0, 0, 26,
|
||||
28, 3, 6, 3, 0, 27, 29, 3, 4, 2, 0, 28, 27, 1, 0, 0, 0, 28, 29, 1, 0, 0,
|
||||
0, 29, 31, 1, 0, 0, 0, 30, 32, 3, 8, 4, 0, 31, 30, 1, 0, 0, 0, 31, 32,
|
||||
1, 0, 0, 0, 32, 3, 1, 0, 0, 0, 33, 34, 5, 10, 0, 0, 34, 5, 1, 0, 0, 0,
|
||||
35, 36, 7, 0, 0, 0, 36, 7, 1, 0, 0, 0, 37, 44, 3, 10, 5, 0, 38, 40, 5,
|
||||
8, 0, 0, 39, 41, 3, 10, 5, 0, 40, 39, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41,
|
||||
43, 1, 0, 0, 0, 42, 38, 1, 0, 0, 0, 43, 46, 1, 0, 0, 0, 44, 42, 1, 0, 0,
|
||||
0, 44, 45, 1, 0, 0, 0, 45, 9, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 48, 5,
|
||||
9, 0, 0, 48, 11, 1, 0, 0, 0, 7, 13, 17, 21, 28, 31, 40, 44,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
@ -117,9 +118,10 @@ const (
|
||||
const (
|
||||
MatchParserRULE_root = 0
|
||||
MatchParserRULE_matchEntry = 1
|
||||
MatchParserRULE_criteria = 2
|
||||
MatchParserRULE_values = 3
|
||||
MatchParserRULE_value = 4
|
||||
MatchParserRULE_separator = 2
|
||||
MatchParserRULE_criteria = 3
|
||||
MatchParserRULE_values = 4
|
||||
MatchParserRULE_value = 5
|
||||
)
|
||||
|
||||
// IRootContext is an interface to support dynamic dispatch.
|
||||
@ -251,7 +253,7 @@ func (p *MatchParser) Root() (localctx IRootContext) {
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(11)
|
||||
p.SetState(13)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -260,12 +262,12 @@ func (p *MatchParser) Root() (localctx IRootContext) {
|
||||
|
||||
if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&254) != 0 {
|
||||
{
|
||||
p.SetState(10)
|
||||
p.SetState(12)
|
||||
p.MatchEntry()
|
||||
}
|
||||
|
||||
}
|
||||
p.SetState(17)
|
||||
p.SetState(21)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -274,19 +276,29 @@ func (p *MatchParser) Root() (localctx IRootContext) {
|
||||
|
||||
for _la == MatchParserWHITESPACE {
|
||||
{
|
||||
p.SetState(13)
|
||||
p.SetState(15)
|
||||
p.Match(MatchParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
{
|
||||
p.SetState(14)
|
||||
p.MatchEntry()
|
||||
p.SetState(17)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&254) != 0 {
|
||||
{
|
||||
p.SetState(16)
|
||||
p.MatchEntry()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p.SetState(19)
|
||||
p.SetState(23)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -294,7 +306,7 @@ func (p *MatchParser) Root() (localctx IRootContext) {
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
}
|
||||
{
|
||||
p.SetState(20)
|
||||
p.SetState(24)
|
||||
p.Match(MatchParserEOF)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
@ -324,7 +336,7 @@ type IMatchEntryContext interface {
|
||||
|
||||
// Getter signatures
|
||||
Criteria() ICriteriaContext
|
||||
WHITESPACE() antlr.TerminalNode
|
||||
Separator() ISeparatorContext
|
||||
Values() IValuesContext
|
||||
|
||||
// IsMatchEntryContext differentiates from other interfaces.
|
||||
@ -379,8 +391,20 @@ func (s *MatchEntryContext) Criteria() ICriteriaContext {
|
||||
return t.(ICriteriaContext)
|
||||
}
|
||||
|
||||
func (s *MatchEntryContext) WHITESPACE() antlr.TerminalNode {
|
||||
return s.GetToken(MatchParserWHITESPACE, 0)
|
||||
func (s *MatchEntryContext) Separator() ISeparatorContext {
|
||||
var t antlr.RuleContext
|
||||
for _, ctx := range s.GetChildren() {
|
||||
if _, ok := ctx.(ISeparatorContext); ok {
|
||||
t = ctx.(antlr.RuleContext)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.(ISeparatorContext)
|
||||
}
|
||||
|
||||
func (s *MatchEntryContext) Values() IValuesContext {
|
||||
@ -422,39 +446,135 @@ func (s *MatchEntryContext) ExitRule(listener antlr.ParseTreeListener) {
|
||||
func (p *MatchParser) MatchEntry() (localctx IMatchEntryContext) {
|
||||
localctx = NewMatchEntryContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 2, MatchParserRULE_matchEntry)
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(22)
|
||||
p.SetState(26)
|
||||
p.Criteria()
|
||||
}
|
||||
p.SetState(24)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(23)
|
||||
p.Match(MatchParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
goto errorExit
|
||||
}
|
||||
p.SetState(27)
|
||||
p.SetState(28)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
|
||||
if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext()) == 1 {
|
||||
{
|
||||
p.SetState(26)
|
||||
p.Values()
|
||||
p.SetState(27)
|
||||
p.Separator()
|
||||
}
|
||||
|
||||
} else if p.HasError() { // JIM
|
||||
goto errorExit
|
||||
}
|
||||
p.SetState(31)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == MatchParserSTRING {
|
||||
{
|
||||
p.SetState(30)
|
||||
p.Values()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
errorExit:
|
||||
if p.HasError() {
|
||||
v := p.GetError()
|
||||
localctx.SetException(v)
|
||||
p.GetErrorHandler().ReportError(p, v)
|
||||
p.GetErrorHandler().Recover(p, v)
|
||||
p.SetError(nil)
|
||||
}
|
||||
p.ExitRule()
|
||||
return localctx
|
||||
goto errorExit // Trick to prevent compiler error if the label is not used
|
||||
}
|
||||
|
||||
// ISeparatorContext is an interface to support dynamic dispatch.
|
||||
type ISeparatorContext interface {
|
||||
antlr.ParserRuleContext
|
||||
|
||||
// GetParser returns the parser.
|
||||
GetParser() antlr.Parser
|
||||
|
||||
// Getter signatures
|
||||
WHITESPACE() antlr.TerminalNode
|
||||
|
||||
// IsSeparatorContext differentiates from other interfaces.
|
||||
IsSeparatorContext()
|
||||
}
|
||||
|
||||
type SeparatorContext struct {
|
||||
antlr.BaseParserRuleContext
|
||||
parser antlr.Parser
|
||||
}
|
||||
|
||||
func NewEmptySeparatorContext() *SeparatorContext {
|
||||
var p = new(SeparatorContext)
|
||||
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
|
||||
p.RuleIndex = MatchParserRULE_separator
|
||||
return p
|
||||
}
|
||||
|
||||
func InitEmptySeparatorContext(p *SeparatorContext) {
|
||||
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)
|
||||
p.RuleIndex = MatchParserRULE_separator
|
||||
}
|
||||
|
||||
func (*SeparatorContext) IsSeparatorContext() {}
|
||||
|
||||
func NewSeparatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *SeparatorContext {
|
||||
var p = new(SeparatorContext)
|
||||
|
||||
antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)
|
||||
|
||||
p.parser = parser
|
||||
p.RuleIndex = MatchParserRULE_separator
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *SeparatorContext) GetParser() antlr.Parser { return s.parser }
|
||||
|
||||
func (s *SeparatorContext) WHITESPACE() antlr.TerminalNode {
|
||||
return s.GetToken(MatchParserWHITESPACE, 0)
|
||||
}
|
||||
|
||||
func (s *SeparatorContext) GetRuleContext() antlr.RuleContext {
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *SeparatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
|
||||
return antlr.TreesStringTree(s, ruleNames, recog)
|
||||
}
|
||||
|
||||
func (s *SeparatorContext) EnterRule(listener antlr.ParseTreeListener) {
|
||||
if listenerT, ok := listener.(MatchListener); ok {
|
||||
listenerT.EnterSeparator(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SeparatorContext) ExitRule(listener antlr.ParseTreeListener) {
|
||||
if listenerT, ok := listener.(MatchListener); ok {
|
||||
listenerT.ExitSeparator(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *MatchParser) Separator() (localctx ISeparatorContext) {
|
||||
localctx = NewSeparatorContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 4, MatchParserRULE_separator)
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(33)
|
||||
p.Match(MatchParserWHITESPACE)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
|
||||
errorExit:
|
||||
if p.HasError() {
|
||||
@ -571,12 +691,12 @@ func (s *CriteriaContext) ExitRule(listener antlr.ParseTreeListener) {
|
||||
|
||||
func (p *MatchParser) Criteria() (localctx ICriteriaContext) {
|
||||
localctx = NewCriteriaContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 4, MatchParserRULE_criteria)
|
||||
p.EnterRule(localctx, 6, MatchParserRULE_criteria)
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(29)
|
||||
p.SetState(35)
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&254) != 0) {
|
||||
@ -720,25 +840,15 @@ func (s *ValuesContext) ExitRule(listener antlr.ParseTreeListener) {
|
||||
|
||||
func (p *MatchParser) Values() (localctx IValuesContext) {
|
||||
localctx = NewValuesContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 6, MatchParserRULE_values)
|
||||
p.EnterRule(localctx, 8, MatchParserRULE_values)
|
||||
var _la int
|
||||
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
p.SetState(32)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
{
|
||||
p.SetState(37)
|
||||
p.Value()
|
||||
}
|
||||
_la = p.GetTokenStream().LA(1)
|
||||
|
||||
if _la == MatchParserSTRING {
|
||||
{
|
||||
p.SetState(31)
|
||||
p.Value()
|
||||
}
|
||||
|
||||
}
|
||||
p.SetState(40)
|
||||
p.SetState(44)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -747,14 +857,14 @@ func (p *MatchParser) Values() (localctx IValuesContext) {
|
||||
|
||||
for _la == MatchParserCOMMA {
|
||||
{
|
||||
p.SetState(34)
|
||||
p.SetState(38)
|
||||
p.Match(MatchParserCOMMA)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
goto errorExit
|
||||
}
|
||||
}
|
||||
p.SetState(36)
|
||||
p.SetState(40)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -763,13 +873,13 @@ func (p *MatchParser) Values() (localctx IValuesContext) {
|
||||
|
||||
if _la == MatchParserSTRING {
|
||||
{
|
||||
p.SetState(35)
|
||||
p.SetState(39)
|
||||
p.Value()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
p.SetState(42)
|
||||
p.SetState(46)
|
||||
p.GetErrorHandler().Sync(p)
|
||||
if p.HasError() {
|
||||
goto errorExit
|
||||
@ -862,10 +972,10 @@ func (s *ValueContext) ExitRule(listener antlr.ParseTreeListener) {
|
||||
|
||||
func (p *MatchParser) Value() (localctx IValueContext) {
|
||||
localctx = NewValueContext(p, p.GetParserRuleContext(), p.GetState())
|
||||
p.EnterRule(localctx, 8, MatchParserRULE_value)
|
||||
p.EnterRule(localctx, 10, MatchParserRULE_value)
|
||||
p.EnterOuterAlt(localctx, 1)
|
||||
{
|
||||
p.SetState(43)
|
||||
p.SetState(47)
|
||||
p.Match(MatchParserSTRING)
|
||||
if p.HasError() {
|
||||
// Recognition error - abort rule
|
||||
|
@ -7,10 +7,11 @@ import (
|
||||
func TestComplexExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
offset := uint32(5)
|
||||
input := "User root,admin,alice Address *,!192.168.0.1"
|
||||
|
||||
match := NewMatch()
|
||||
errors := match.Parse(input, 32)
|
||||
errors := match.Parse(input, 32, offset)
|
||||
|
||||
if len(errors) > 0 {
|
||||
t.Fatalf("Expected no errors, but got %v", errors)
|
||||
@ -20,32 +21,32 @@ func TestComplexExample(
|
||||
t.Fatalf("Expected 2 entries, but got %v", len(match.Entries))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Criteria == MatchCriteriaTypeUser) {
|
||||
if !(match.Entries[0].Criteria.Type == MatchCriteriaTypeUser) {
|
||||
t.Fatalf("Expected User, but got %v", match.Entries[0])
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Values[0].Value == "root") {
|
||||
t.Fatalf("Expected root, but got %v", match.Entries[0].Values[0])
|
||||
if !(match.Entries[0].Values.Values[0].Value == "root" && match.Entries[0].Values.Values[0].Start.Character == 5+offset && match.Entries[0].Values.Values[0].End.Character == 8+offset && match.Entries[0].Start.Character == 0+offset && match.Entries[0].End.Character == 20+offset) {
|
||||
t.Errorf("Expected root, but got %v", match.Entries[0].Values.Values[0])
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Values[1].Value == "admin") {
|
||||
t.Fatalf("Expected admin, but got %v", match.Entries[0].Values[1])
|
||||
if !(match.Entries[0].Values.Values[1].Value == "admin" && match.Entries[0].Values.Values[1].Start.Character == 10+offset && match.Entries[0].Values.Values[1].End.Character == 14+offset) {
|
||||
t.Errorf("Expected admin, but got %v", match.Entries[0].Values.Values[1])
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Values[2].Value == "alice") {
|
||||
t.Fatalf("Expected alice, but got %v", match.Entries[0].Values[2])
|
||||
if !(match.Entries[0].Values.Values[2].Value == "alice" && match.Entries[0].Values.Values[2].Start.Character == 16+offset && match.Entries[0].Values.Values[2].End.Character == 20+offset) {
|
||||
t.Errorf("Expected alice, but got %v", match.Entries[0].Values.Values[2])
|
||||
}
|
||||
|
||||
if !(match.Entries[1].Criteria == MatchCriteriaTypeAddress) {
|
||||
t.Fatalf("Expected Address, but got %v", match.Entries[1])
|
||||
if !(match.Entries[1].Criteria.Type == MatchCriteriaTypeAddress) {
|
||||
t.Errorf("Expected Address, but got %v", match.Entries[1])
|
||||
}
|
||||
|
||||
if !(match.Entries[1].Values[0].Value == "*") {
|
||||
t.Fatalf("Expected *, but got %v", match.Entries[1].Values[0])
|
||||
if !(match.Entries[1].Values.Values[0].Value == "*" && match.Entries[1].Values.Values[0].Start.Character == 30+offset && match.Entries[1].Values.Values[0].End.Character == 30+offset) {
|
||||
t.Errorf("Expected *, but got %v", match.Entries[1].Values.Values[0])
|
||||
}
|
||||
|
||||
if !(match.Entries[1].Values[1].Value == "!192.168.0.1") {
|
||||
t.Fatalf("Expected !192.168.0.1, but got %v", match.Entries[1].Values[1])
|
||||
if !(match.Entries[1].Values.Values[1].Value == "!192.168.0.1" && match.Entries[1].Values.Values[1].Start.Character == 32+offset && match.Entries[1].Values.Values[1].End.Character == 43+offset) {
|
||||
t.Errorf("Expected !192.168.0.1, but got %v", match.Entries[1].Values.Values[1])
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +56,7 @@ func TestSecondComplexExample(
|
||||
input := "Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1"
|
||||
|
||||
match := NewMatch()
|
||||
errors := match.Parse(input, 0)
|
||||
errors := match.Parse(input, 0, 20)
|
||||
|
||||
if len(errors) > 0 {
|
||||
t.Fatalf("Expected no errors, but got %v", errors)
|
||||
@ -65,15 +66,69 @@ func TestSecondComplexExample(
|
||||
t.Fatalf("Expected 1 entries, but got %v", len(match.Entries))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Criteria == MatchCriteriaTypeAddress) {
|
||||
if !(match.Entries[0].Criteria.Type == MatchCriteriaTypeAddress) {
|
||||
t.Fatalf("Expected Address, but got %v", match.Entries[0])
|
||||
}
|
||||
|
||||
if !(len(match.Entries[0].Values) == 3) {
|
||||
t.Fatalf("Expected 3 values, but got %v", len(match.Entries[0].Values))
|
||||
if !(len(match.Entries[0].Values.Values) == 3) {
|
||||
t.Fatalf("Expected 3 values, but got %v", len(match.Entries[0].Values.Values))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Values[0].Value == "172.22.100.0/24") {
|
||||
t.Fatalf("Expected 172.22.100.0/24, but got %v", match.Entries[0].Values[0])
|
||||
if !(match.Entries[0].Values.Values[0].Value == "172.22.100.0/24") {
|
||||
t.Fatalf("Expected 172.22.100.0/24, but got %v", match.Entries[0].Values.Values[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncompleteBetweenEntriesExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := "User root,admin,alice "
|
||||
|
||||
match := NewMatch()
|
||||
errors := match.Parse(input, 0, 0)
|
||||
|
||||
if len(errors) > 0 {
|
||||
t.Fatalf("Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
if !(len(match.Entries) == 1) {
|
||||
t.Errorf("Expected 1 entries, but got %v", len(match.Entries))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Criteria.Type == MatchCriteriaTypeUser) {
|
||||
t.Errorf("Expected User, but got %v", match.Entries[0])
|
||||
}
|
||||
|
||||
if !(len(match.Entries[0].Values.Values) == 3) {
|
||||
t.Errorf("Expected 3 values, but got %v", len(match.Entries[0].Values.Values))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Start.Character == 0 && match.Entries[0].End.Character == 20) {
|
||||
t.Errorf("Expected 0-20, but got %v", match.Entries[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncompleteBetweenValuesExample(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := "User "
|
||||
|
||||
match := NewMatch()
|
||||
errors := match.Parse(input, 0, 0)
|
||||
|
||||
if len(errors) > 0 {
|
||||
t.Fatalf("Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
if !(len(match.Entries) == 1) {
|
||||
t.Errorf("Expected 1 entries, but got %v", len(match.Entries))
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Criteria.Type == MatchCriteriaTypeUser) {
|
||||
t.Errorf("Expected User, but got %v", match.Entries[0])
|
||||
}
|
||||
|
||||
if !(match.Entries[0].Values == nil) {
|
||||
t.Errorf("Expected 0 values, but got %v", match.Entries[0].Values)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package fields
|
||||
|
||||
import docvalues "config-lsp/doc-values"
|
||||
|
||||
var MatchAllowedOptions = map[string]struct{}{
|
||||
"AcceptEnv": {},
|
||||
"AllowAgentForwarding": {},
|
||||
@ -61,3 +63,15 @@ var MatchAllowedOptions = map[string]struct{}{
|
||||
"X11Forwarding": {},
|
||||
"X11UseLocalhos": {},
|
||||
}
|
||||
|
||||
var MatchUserField = docvalues.UserValue("", false)
|
||||
var MatchGroupField = docvalues.GroupValue("", false)
|
||||
var MatchHostField = docvalues.DomainValue()
|
||||
var MatchLocalAddressField = docvalues.StringValue{}
|
||||
var MatchLocalPortField = docvalues.StringValue{}
|
||||
var MatchRDomainField = docvalues.StringValue{}
|
||||
var MatchAddressField = docvalues.IPAddressValue{
|
||||
AllowIPv4: true,
|
||||
AllowIPv6: true,
|
||||
AllowRange: true,
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ func GetRootCompletions(
|
||||
func GetOptionCompletions(
|
||||
d *sshdconfig.SSHDocument,
|
||||
entry *ast.SSHOption,
|
||||
matchBlock *ast.SSHMatchBlock,
|
||||
cursor uint32,
|
||||
) ([]protocol.CompletionItem, error) {
|
||||
option, found := fields.Options[entry.Key.Value]
|
||||
@ -63,12 +64,19 @@ func GetOptionCompletions(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if entry.Key.Value == "Match" {
|
||||
return getMatchCompletions(
|
||||
d,
|
||||
matchBlock.MatchValue,
|
||||
cursor-matchBlock.MatchEntry.Start.Character,
|
||||
)
|
||||
}
|
||||
|
||||
line := entry.OptionValue.Value
|
||||
|
||||
if entry.OptionValue == nil {
|
||||
return option.FetchCompletions("", 0), nil
|
||||
}
|
||||
|
||||
relativeCursor := common.CursorToCharacterIndex(cursor - entry.OptionValue.Start.Character)
|
||||
line := entry.OptionValue.Value
|
||||
|
||||
return option.FetchCompletions(line, relativeCursor), nil
|
||||
return option.FetchCompletions(line, common.CursorToCharacterIndex(cursor)), nil
|
||||
}
|
||||
|
111
handlers/sshd_config/handlers/completions_match.go
Normal file
111
handlers/sshd_config/handlers/completions_match.go
Normal file
@ -0,0 +1,111 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
sshdconfig "config-lsp/handlers/sshd_config"
|
||||
"config-lsp/handlers/sshd_config/fields"
|
||||
match_parser "config-lsp/handlers/sshd_config/fields/match-parser"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func getMatchCompletions(
|
||||
d *sshdconfig.SSHDocument,
|
||||
match *match_parser.Match,
|
||||
cursor uint32,
|
||||
) ([]protocol.CompletionItem, error) {
|
||||
if len(match.Entries) == 0 {
|
||||
completions := getMatchCriteriaCompletions()
|
||||
completions = append(completions, getMatchAllKeywordCompletion())
|
||||
|
||||
return completions, nil
|
||||
}
|
||||
|
||||
entry := match.GetEntryByCursor(cursor)
|
||||
|
||||
if entry == nil || entry.Criteria.IsCursorBetween(cursor) {
|
||||
return getMatchCriteriaCompletions(), nil
|
||||
}
|
||||
|
||||
return getMatchValueCompletions(entry, cursor), nil
|
||||
}
|
||||
|
||||
func getMatchCriteriaCompletions() []protocol.CompletionItem {
|
||||
kind := protocol.CompletionItemKindEnum
|
||||
|
||||
return []protocol.CompletionItem{
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeUser),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeGroup),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeHost),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeAddress),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeLocalAddress),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeLocalPort),
|
||||
Kind: &kind,
|
||||
},
|
||||
{
|
||||
Label: string(match_parser.MatchCriteriaTypeRDomain),
|
||||
Kind: &kind,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getMatchAllKeywordCompletion() protocol.CompletionItem {
|
||||
kind := protocol.CompletionItemKindKeyword
|
||||
|
||||
return protocol.CompletionItem{
|
||||
Label: "all",
|
||||
Kind: &kind,
|
||||
}
|
||||
}
|
||||
|
||||
func getMatchValueCompletions(
|
||||
entry *match_parser.MatchEntry,
|
||||
cursor uint32,
|
||||
) []protocol.CompletionItem {
|
||||
value := entry.GetValueByCursor(entry.End.Character)
|
||||
|
||||
var line string
|
||||
var relativeCursor uint32
|
||||
|
||||
if value != nil {
|
||||
line = value.Value
|
||||
relativeCursor = cursor - value.Start.Character
|
||||
} else {
|
||||
line = ""
|
||||
relativeCursor = 0
|
||||
}
|
||||
|
||||
switch entry.Criteria.Type {
|
||||
case match_parser.MatchCriteriaTypeUser:
|
||||
return fields.MatchUserField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeGroup:
|
||||
return fields.MatchGroupField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeHost:
|
||||
return fields.MatchHostField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeAddress:
|
||||
return fields.MatchAddressField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeLocalAddress:
|
||||
return fields.MatchLocalAddressField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeLocalPort:
|
||||
return fields.MatchLocalPortField.FetchCompletions(line, relativeCursor)
|
||||
case match_parser.MatchCriteriaTypeRDomain:
|
||||
return fields.MatchRDomainField.FetchCompletions(line, relativeCursor)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -14,7 +14,7 @@ var isEmptyPattern = regexp.MustCompile(`^\s*$`)
|
||||
|
||||
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
||||
line := params.Position.Line
|
||||
cursor := params.Position.Character
|
||||
cursor := common.CursorToCharacterIndex(params.Position.Character)
|
||||
|
||||
d := sshdconfig.DocumentParserMap[params.TextDocument.URI]
|
||||
|
||||
@ -27,7 +27,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
||||
if entry == nil ||
|
||||
entry.Separator == nil ||
|
||||
entry.Key == nil ||
|
||||
(common.CursorToCharacterIndex(cursor)) <= entry.Key.End.Character {
|
||||
cursor <= entry.Key.End.Character {
|
||||
|
||||
return handlers.GetRootCompletions(
|
||||
d,
|
||||
@ -37,10 +37,11 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
|
||||
)
|
||||
}
|
||||
|
||||
if entry.Separator != nil && cursor > entry.Separator.End.Character {
|
||||
if entry.Separator != nil && cursor >= entry.Separator.End.Character {
|
||||
return handlers.GetOptionCompletions(
|
||||
d,
|
||||
entry,
|
||||
matchBlock,
|
||||
cursor,
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user