feat: Add TimeFormatValue

This commit is contained in:
Myzel394 2024-07-30 23:59:42 +02:00
parent ac2d972d3d
commit 26514ed059
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
7 changed files with 171 additions and 20 deletions

View File

@ -47,11 +47,9 @@ func (p *SimpleConfigParser) AddLine(line string, lineNumber uint32) (string, er
} }
optionIndex := re.SubexpIndex("OptionName") optionIndex := re.SubexpIndex("OptionName")
if optionIndex == -1 { if optionIndex == -1 {
return "", docvalues.MalformedLineError{} return "", docvalues.MalformedLineError{}
} }
option = matches[optionIndex] option = matches[optionIndex]
if _, exists := (*p.Options.AvailableOptions)[option]; !exists { if _, exists := (*p.Options.AvailableOptions)[option]; !exists {
@ -59,17 +57,15 @@ func (p *SimpleConfigParser) AddLine(line string, lineNumber uint32) (string, er
} }
separatorIndex := re.SubexpIndex("Separator") separatorIndex := re.SubexpIndex("Separator")
if separatorIndex == -1 { if separatorIndex == -1 {
return option, docvalues.MalformedLineError{} return option, docvalues.MalformedLineError{}
} }
separator = matches[separatorIndex]
valueIndex := re.SubexpIndex("Value") valueIndex := re.SubexpIndex("Value")
if valueIndex == -1 { if valueIndex == -1 {
return option, docvalues.MalformedLineError{} return option, docvalues.MalformedLineError{}
} }
value = matches[valueIndex] value = matches[valueIndex]
if _, exists := p.Lines[option]; exists { if _, exists := p.Lines[option]; exists {

View File

@ -89,7 +89,6 @@ type groupInfo struct {
var _cachedGroupInfo []groupInfo var _cachedGroupInfo []groupInfo
func fetchGroupInfo() ([]groupInfo, error) { func fetchGroupInfo() ([]groupInfo, error) {
if len(_cachedGroupInfo) > 0 { if len(_cachedGroupInfo) > 0 {
return _cachedGroupInfo, nil return _cachedGroupInfo, nil

View File

@ -90,6 +90,10 @@ func (v ArrayValue) CheckIsValid(value string) error {
} }
func (v ArrayValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem { func (v ArrayValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
if cursor == 0 {
return v.SubValue.FetchCompletions(line, cursor)
}
relativePosition, found := utils.FindPreviousCharacter(line, v.Separator, int(cursor-1)) relativePosition, found := utils.FindPreviousCharacter(line, v.Separator, int(cursor-1))
if found { if found {

View File

@ -55,10 +55,14 @@ func (v KeyValueAssignmentValue) CheckIsValid(value string) error {
} }
func (v KeyValueAssignmentValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem { func (v KeyValueAssignmentValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
if cursor == 0 {
return v.Key.FetchCompletions(line, cursor)
}
relativePosition, found := utils.FindPreviousCharacter(line, v.Separator, int(cursor-1)) relativePosition, found := utils.FindPreviousCharacter(line, v.Separator, int(cursor-1))
if found { if found {
line = line[uint32(relativePosition):] line = line[uint32(relativePosition+len(v.Separator)):]
cursor -= uint32(relativePosition) cursor -= uint32(relativePosition)
return v.Value.FetchCompletions(line, cursor) return v.Value.FetchCompletions(line, cursor)

38
doc-values/value-regex.go Normal file
View File

@ -0,0 +1,38 @@
package docvalues
import (
"fmt"
"regexp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
type RegexInvalidError struct {
Regex string
}
func (e RegexInvalidError) Error() string {
return fmt.Sprintf("This value does not match the regular expression (Pattern: `%s`)", e.Regex)
}
type RegexValue struct {
Regex regexp.Regexp
}
func (v RegexValue) GetTypeDescription() []string {
return []string{
fmt.Sprintf("String matching the regular expression (Pattern: `%s`)", v.Regex.String()),
}
}
func (v RegexValue) CheckIsValid(value string) error {
if value == "" {
return EmptyStringError{}
}
return nil
}
func (v RegexValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
return []protocol.CompletionItem{}
}

View File

@ -147,6 +147,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
SubValue: docvalues.ArrayValue{ SubValue: docvalues.ArrayValue{
Separator: ",", Separator: ",",
DuplicatesExtractor: &docvalues.DuplicatesAllowedExtractor, DuplicatesExtractor: &docvalues.DuplicatesAllowedExtractor,
// TODO: Add
SubValue: docvalues.StringValue{}, SubValue: docvalues.StringValue{},
}, },
}, },
@ -182,7 +183,7 @@ See PATTERNS in ssh_config(5) for more information on patterns. This keyword may
"x11-connection", "x11-connection",
}, },
}, },
Value: docvalues.StringValue{}, Value: TimeFormatValue{},
}, },
}, },
), ),

View File

@ -0,0 +1,109 @@
package openssh
import (
docvalues "config-lsp/doc-values"
"config-lsp/utils"
"fmt"
"regexp"
"strconv"
protocol "github.com/tliron/glsp/protocol_3_16"
)
var timeFormatCompletionsPattern = regexp.MustCompile(`(?i)^(\d+)([smhdw])$`)
var timeFormatCheckPattern = regexp.MustCompile(`(?i)^(\d+)([smhdw]?)$`)
var isJustDigitsPattern = regexp.MustCompile(`^\d+$`)
type TimeFormatValue struct{}
func (v TimeFormatValue) GetTypeDescription() []string {
return []string{"Time value"}
}
func (v TimeFormatValue) CheckIsValid(value string) error {
if !timeFormatCheckPattern.MatchString(value) {
return docvalues.RegexInvalidError{Regex: timeFormatCheckPattern.String()}
}
return nil
}
func calculateInSeconds(value int, unit string) int {
switch unit {
case "s":
return value
case "m":
return value * 60
case "h":
return value * 60 * 60
case "d":
return value * 60 * 60 * 24
case "w":
return value * 60 * 60 * 24 * 7
default:
return 0
}
}
func (v TimeFormatValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
completions := make([]protocol.CompletionItem, 0)
if line != "" && !timeFormatCompletionsPattern.MatchString(line) {
completions = append(
completions,
utils.Map(
[]string{"s", "m", "h", "d", "w"},
func(unit string) protocol.CompletionItem {
kind := protocol.CompletionItemKindValue
unitName := map[string]string{
"s": "seconds",
"m": "minutes",
"h": "hours",
"d": "days",
"w": "weeks",
}[unit]
var detail string
value, err := strconv.Atoi(line)
if err == nil {
if unit == "s" {
detail = fmt.Sprintf("%d seconds", value)
} else {
detail = fmt.Sprintf("%d %s (%d seconds)", value, unitName, calculateInSeconds(value, unit))
}
}
return protocol.CompletionItem{
Label: line + unit,
Kind: &kind,
Detail: &detail,
}
},
)...,
)
}
if line == "" || isJustDigitsPattern.MatchString(line) {
completions = append(
completions,
utils.Map(
[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
func(index int) protocol.CompletionItem {
kind := protocol.CompletionItemKindValue
sortText := strconv.Itoa(index)
return protocol.CompletionItem{
Label: line + strconv.Itoa(index),
Kind: &kind,
SortText: &sortText,
}
},
)...,
)
}
return completions
}