Merge pull request #2 from Myzel394/add-mount-options

Add more mount options to common-documentation
This commit is contained in:
Myzel394 2024-08-07 22:36:43 +02:00 committed by GitHub
commit 223428cf42
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 500 additions and 137 deletions

View File

@ -0,0 +1,28 @@
package commondocumentation
import docvalues "config-lsp/doc-values"
var AdfsDocumentationAssignable = map[docvalues.EnumString]docvalues.Value{
docvalues.CreateEnumStringWithDoc(
"uid",
"Set the owner of the files in the filesystem (default: uid=0).",
): docvalues.UIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"gid",
"Set the group of the files in the filesystem (default: gid=0).",
): docvalues.GIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"ownmask",
"Set the permission mask for ADFS 'owner' permissions (default: 0700).",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"othmask",
"Set the permission mask for ADFS 'other' permissions (default: 0077).",
): docvalues.StringValue{},
}
var AdfsDocumentationEnums = []docvalues.EnumString{}

View File

@ -0,0 +1,91 @@
package commondocumentation
import docvalues "config-lsp/doc-values"
var prefixMaxLength = uint32(30)
var AffsDocumentationAssignable = map[docvalues.EnumString]docvalues.Value{
docvalues.CreateEnumStringWithDoc(
"uid",
"Set the owner and group of the root of the filesystem (default: uid=gid=0, but with option uid or gid without specified value, the UID and GID of the current process are taken).",
): docvalues.UIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"gid",
"Set the owner and group of the root of the filesystem (default: uid=gid=0, but with option uid or gid without specified value, the UID and GID of the current process are taken).",
): docvalues.GIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"setuid",
"Set the owner of all files.",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"setgid",
"Set the group of all files.",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"mode",
"Set the mode of all files to value & 0777 disregarding the original permissions. Add search permission to directories that have read permission. The value is given in octal.",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"prefix",
"Prefix used before volume name, when following a link.",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"volume",
"Prefix (of length at most 30) used before '/' when following a symbolic link.",
): docvalues.StringValue{MaxLength: &prefixMaxLength},
docvalues.CreateEnumStringWithDoc(
"reserved",
"(Default: 2.) Number of unused blocks at the start of the device.",
): docvalues.NumberValue{Min: &zero},
docvalues.CreateEnumStringWithDoc(
"root",
"Give explicitly the location of the root block.",
): docvalues.NumberValue{Min: &zero},
docvalues.CreateEnumStringWithDoc(
"bs",
"Give blocksize. Allowed values are 512, 1024, 2048, 4096.",
): docvalues.EnumValue{
EnforceValues: true,
Values: []docvalues.EnumString{
docvalues.CreateEnumString("512"),
docvalues.CreateEnumString("1024"),
docvalues.CreateEnumString("2048"),
docvalues.CreateEnumString("4096"),
},
},
docvalues.CreateEnumStringWithDoc(
"grpquota",
"These options are accepted but ignored. (However, quota utilities may react to such strings in /etc/fstab.)",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"noquota",
"These options are accepted but ignored. (However, quota utilities may react to such strings in /etc/fstab.)",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"quota",
"These options are accepted but ignored. (However, quota utilities may react to such strings in /etc/fstab.)",
): docvalues.StringValue{},
docvalues.CreateEnumStringWithDoc(
"usrquota",
"These options are accepted but ignored. (However, quota utilities may react to such strings in /etc/fstab.)",
): docvalues.StringValue{},
}
var AffsDocumentationEnums = []docvalues.EnumString{
docvalues.CreateEnumStringWithDoc(
"protect",
"Do not allow any changes to the protection bits on the filesystem.",
),
docvalues.CreateEnumStringWithDoc(
"usemp",
"Set UID and GID of the root of the filesystem to the UID and GID of the mount point upon the first sync or umount, and then clear this option. Strange...",
),
docvalues.CreateEnumStringWithDoc(
"verbose",
"Print an informational message for each successful mount.",
),
}

View File

@ -0,0 +1,24 @@
package commondocumentation
import docvalues "config-lsp/doc-values"
var DebugfsDocumentationAssignable = map[docvalues.EnumString]docvalues.Value{
docvalues.CreateEnumStringWithDoc(
"uid",
"Set the owner of the mountpoint.",
): docvalues.UIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"gid",
"Set the group of the mountpoint.",
): docvalues.GIDValue{
EnforceUsingExisting: true,
},
docvalues.CreateEnumStringWithDoc(
"mode",
"Sets the mode of the mountpoint.",
): docvalues.StringValue{},
}
var DebugfsDocumentationEnums = []docvalues.EnumString{}

View File

@ -159,6 +159,12 @@ func PositiveNumberValue() Value {
}
}
func MaskValue() Value {
min := 0
max := 777
return NumberValue{Min: &min, Max: &max}
}
func SingleEnumValue(value string) EnumValue {
return EnumValue{
EnforceValues: true,

View File

@ -29,7 +29,7 @@ func MergeKeyEnumAssignmentMaps(maps ...map[EnumString]Value) map[EnumString]Val
for _, m := range maps {
for key, value := range m {
if _, ok := existingEnums[key.InsertText]; !ok {
if _, ok := existingEnums[key.InsertText]; ok {
continue
}

View File

@ -122,8 +122,8 @@ func (v ArrayValue) FetchCompletions(line string, cursor uint32) []protocol.Comp
relativePosition, found := utils.FindPreviousCharacter(line, v.Separator, int(cursor-1))
if found {
line = line[uint32(relativePosition):]
cursor -= uint32(relativePosition)
line = line[uint32(relativePosition+1):]
cursor -= uint32(relativePosition + 1)
}
return v.SubValue.FetchCompletions(line, cursor)

View File

@ -30,6 +30,17 @@ type EnumString struct {
Documentation string
}
func (v EnumString) ToCompletionItem() protocol.CompletionItem {
textFormat := protocol.InsertTextFormatPlainText
kind := protocol.CompletionItemKindEnum
return protocol.CompletionItem{
Label: v.InsertText,
InsertTextFormat: &textFormat,
Kind: &kind,
Documentation: &v.Documentation,
}
}
func CreateEnumString(value string) EnumString {
return EnumString{
InsertText: value,

128
doc-values/value-gid.go Normal file
View File

@ -0,0 +1,128 @@
package docvalues
import (
"config-lsp/utils"
"strconv"
protocol "github.com/tliron/glsp/protocol_3_16"
)
type GIDNotInPasswdErr struct{}
func (e GIDNotInPasswdErr) Error() string {
return "This UID does not exist"
}
type InvalidGIDError struct{}
func (e InvalidGIDError) Error() string {
return "This UID is invalid"
}
type GIDNotInRangeError struct{}
func (e GIDNotInRangeError) Error() string {
return "UIDs must be between 0 and 65535"
}
type GIDValue struct {
EnforceUsingExisting bool
}
func (v GIDValue) GetTypeDescription() []string {
return []string{"Group ID"}
}
func (v GIDValue) CheckIsValid(value string) []*InvalidValue {
uid, err := strconv.Atoi(value)
if err != nil {
return []*InvalidValue{{
Err: InvalidGIDError{},
Start: 0,
End: uint32(len(value)),
}}
}
if uid < 0 || uid > 65535 {
return []*InvalidValue{{
Err: GIDNotInRangeError{},
Start: 0,
End: uint32(len(value)),
}}
}
if v.EnforceUsingExisting {
infos, err := fetchPasswdInfo()
if err != nil {
return []*InvalidValue{}
}
found := false
for _, info := range infos {
if info.GID == value {
found = true
break
}
}
if !found {
return []*InvalidValue{{
Err: GIDNotInPasswdErr{},
Start: 0,
End: uint32(len(value)),
}}
}
}
return []*InvalidValue{}
}
var defaultGIDsExplanation = []EnumString{
{
InsertText: "0",
DescriptionText: "root",
Documentation: "The group of the root user",
},
}
func (v GIDValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
infos, err := fetchGroupInfo()
if err != nil {
return utils.Map(defaultUIDsExplanation, func(enum EnumString) protocol.CompletionItem {
return enum.ToCompletionItem()
})
}
textFormat := protocol.InsertTextFormatPlainText
kind := protocol.CompletionItemKindValue
completions := make([]protocol.CompletionItem, len(infos))
for index, info := range infos {
// Find default gids
var existingGID *EnumString
for _, defaultGID := range defaultUIDsExplanation {
if defaultGID.InsertText == info.GID {
existingGID = &defaultGID
break
}
}
if existingGID != nil {
completions[index] = existingGID.ToCompletionItem()
} else {
completions[index] = protocol.CompletionItem{
InsertTextFormat: &textFormat,
Kind: &kind,
InsertText: &info.GID,
Documentation: info.Name,
}
}
}
return completions
}

View File

@ -111,13 +111,23 @@ func (v KeyEnumAssignmentValue) FetchEnumCompletions() []protocol.CompletionItem
for enumKey := range v.Values {
textFormat := protocol.InsertTextFormatPlainText
kind := protocol.CompletionItemKindEnum
kind := protocol.CompletionItemKindField
val := v.Values[enumKey]
description := val.GetTypeDescription()
var documentation string
if len(description) == 1 {
documentation = fmt.Sprintf("%s%s<%s> \n\n%s", enumKey.InsertText, v.Separator, description[0], enumKey.Documentation)
} else {
documentation = fmt.Sprintf("%s%s<value> \n\n%s", enumKey.InsertText, v.Separator, enumKey.Documentation)
}
completions = append(completions, protocol.CompletionItem{
Label: enumKey.InsertText,
InsertTextFormat: &textFormat,
Kind: &kind,
Documentation: &enumKey.Documentation,
Documentation: documentation,
})
}

View File

@ -1,6 +1,7 @@
package docvalues
import (
"config-lsp/utils"
"strings"
protocol "github.com/tliron/glsp/protocol_3_16"
@ -49,6 +50,26 @@ func (v OrValue) CheckIsValid(value string) []*InvalidValue {
return errors
}
func (v OrValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
// Check for special cases
if len(v.Values) == 2 {
switch v.Values[0].(type) {
case KeyEnumAssignmentValue:
if cursor > 0 {
// KeyEnumAssignment + other values
// If there is an separator, we only want to show
// the values of the KeyEnumAssignment
keyEnumValue := v.Values[0].(KeyEnumAssignmentValue)
println("line eta cursor", line, cursor)
_, found := utils.FindPreviousCharacter(line, keyEnumValue.Separator, int(cursor-1))
if found {
return keyEnumValue.FetchCompletions(line, cursor)
}
}
}
}
completions := make([]protocol.CompletionItem, 0)
for _, subValue := range v.Values {

View File

@ -62,7 +62,7 @@ var powers = []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192
func (v PowerOfTwoValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
textFormat := protocol.InsertTextFormatPlainText
kind := protocol.CompletionItemKindEnum
kind := protocol.CompletionItemKindValue
return utils.Map(
powers,

View File

@ -26,16 +26,15 @@ func (v RegexValue) GetTypeDescription() []string {
}
func (v RegexValue) CheckIsValid(value string) []*InvalidValue {
if value == "" {
if !v.Regex.MatchString(value) {
return []*InvalidValue{{
Err: EmptyStringError{},
Err: RegexInvalidError{Regex: v.Regex.String()},
Start: 0,
End: uint32(len(value)),
},
}
}}
}
return nil
return []*InvalidValue{}
}
func (v RegexValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {

View File

@ -10,7 +10,15 @@ func (e EmptyStringError) Error() string {
return "This setting may not be empty"
}
type StringValue struct{}
type StringTooLongError struct{}
func (e StringTooLongError) Error() string {
return "This setting is too long"
}
type StringValue struct {
MaxLength *uint32
}
func (v StringValue) GetTypeDescription() []string {
return []string{"String"}
@ -26,6 +34,14 @@ func (v StringValue) CheckIsValid(value string) []*InvalidValue {
}
}
if v.MaxLength != nil && uint32(len(value)) > *v.MaxLength {
return []*InvalidValue{{
Err: StringTooLongError{},
Start: 0,
End: uint32(len(value)),
}}
}
return nil
}

129
doc-values/value-uid.go Normal file
View File

@ -0,0 +1,129 @@
package docvalues
import (
"config-lsp/utils"
"fmt"
"strconv"
protocol "github.com/tliron/glsp/protocol_3_16"
)
type UIDNotInPasswdErr struct{}
func (e UIDNotInPasswdErr) Error() string {
return "This UID does not exist"
}
type InvalidUIDError struct{}
func (e InvalidUIDError) Error() string {
return "This UID is invalid"
}
type UIDNotInRangeError struct{}
func (e UIDNotInRangeError) Error() string {
return "UIDs must be between 0 and 65535"
}
type UIDValue struct {
EnforceUsingExisting bool
}
func (v UIDValue) GetTypeDescription() []string {
return []string{"User ID"}
}
func (v UIDValue) CheckIsValid(value string) []*InvalidValue {
uid, err := strconv.Atoi(value)
if err != nil {
return []*InvalidValue{{
Err: InvalidUIDError{},
Start: 0,
End: uint32(len(value)),
}}
}
if uid < 0 || uid > 65535 {
return []*InvalidValue{{
Err: UIDNotInRangeError{},
Start: 0,
End: uint32(len(value)),
}}
}
if v.EnforceUsingExisting {
infos, err := fetchPasswdInfo()
if err != nil {
return []*InvalidValue{}
}
found := false
for _, info := range infos {
if info.UID == value {
found = true
break
}
}
if !found {
return []*InvalidValue{{
Err: UIDNotInPasswdErr{},
Start: 0,
End: uint32(len(value)),
}}
}
}
return []*InvalidValue{}
}
var defaultUIDsExplanation = []EnumString{
{
InsertText: "0",
DescriptionText: "root",
Documentation: "The root user",
},
}
func (v UIDValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
infos, err := fetchPasswdInfo()
if err != nil {
return utils.Map(defaultUIDsExplanation, func(enum EnumString) protocol.CompletionItem {
return enum.ToCompletionItem()
})
}
textFormat := protocol.InsertTextFormatPlainText
kind := protocol.CompletionItemKindValue
completions := make([]protocol.CompletionItem, len(infos))
for index, info := range infos {
// Find default uids
var existingUID *EnumString
for _, defaultUID := range defaultUIDsExplanation {
if defaultUID.InsertText == info.UID {
existingUID = &defaultUID
break
}
}
if existingUID != nil {
completions[index] = existingUID.ToCompletionItem()
} else {
completions[index] = protocol.CompletionItem{
InsertTextFormat: &textFormat,
Kind: &kind,
InsertText: &info.UID,
Documentation: fmt.Sprintf("User %s; Home: %s", info.Name, info.HomePath),
}
}
}
return completions
}

View File

@ -245,25 +245,18 @@ func createMountOptionField(
var DefaultMountOptionsField = createMountOptionField([]docvalues.EnumString{}, map[docvalues.EnumString]docvalues.Value{})
var MountOptionsMapField = map[string]docvalues.Value{
// "adfs": createMountOptionField(
// []docvalues.EnumString{},
// map[string]commondocumentation.AssignableOption{
// "uid": {
// Documentation: "Set the owner of the files in the filesystem",
// Handler: func(context docvalues.KeyValueAssignmentContext) docvalues.Value {
// min := 0
// return docvalues.NumberValue{Min: &min}
// },
// },
// "gid": {
// Documentation: "Set the group of the files in the filesystem",
// Handler: func(context docvalues.KeyValueAssignmentContext) docvalues.Value {
// min := 0
// return docvalues.NumberValue{Min: &min}
// },
// },
// },
// ),
"adfs": createMountOptionField(
commondocumentation.AdfsDocumentationEnums,
commondocumentation.AdfsDocumentationAssignable,
),
"affs": createMountOptionField(
commondocumentation.AffsDocumentationEnums,
commondocumentation.AffsDocumentationAssignable,
),
"debugfs": createMountOptionField(
commondocumentation.DebugfsDocumentationEnums,
commondocumentation.DebugfsDocumentationAssignable,
),
"ext2": createMountOptionField(
commondocumentation.Ext2DocumentationEnums,
commondocumentation.Ext2DocumentationAssignable,

View File

@ -1,108 +1,20 @@
package fstabdocumentation
import docvalues "config-lsp/doc-values"
import (
docvalues "config-lsp/doc-values"
"config-lsp/utils"
)
var FileSystemTypeField = docvalues.ArrayValue{
Separator: ",",
DuplicatesExtractor: &docvalues.SimpleDuplicatesExtractor,
SubValue: docvalues.EnumValue{
EnforceValues: false,
Values: []docvalues.EnumString{
{
InsertText: "none",
DescriptionText: "none",
Documentation: "An entry _none_ is useful for bind or move mounts.",
Values: utils.Map(
utils.KeysOfMap(MountOptionsMapField),
func(key string) docvalues.EnumString {
return docvalues.CreateEnumString(key)
},
{
InsertText: "swap",
DescriptionText: "swap",
Documentation: "An entry _swap_ denotes a file or partition to be used for swapping, cf. swapon(8)",
},
{
InsertText: "ext2",
DescriptionText: "ext2",
Documentation: "Mount as ext2 filesystem",
},
{
InsertText: "ext3",
DescriptionText: "ext3",
Documentation: "Mount as ext2 filesystem",
},
{
InsertText: "ext4",
DescriptionText: "ext4",
Documentation: "Mount as ext4 filesystem",
},
{
InsertText: "xfs",
DescriptionText: "xfs",
Documentation: "Mount as xfs filesystem",
},
{
InsertText: "btrfs",
DescriptionText: "btrfs",
Documentation: "Mount as btrfs filesystem",
},
{
InsertText: "f2fs",
DescriptionText: "f2fs",
Documentation: "Mount as f2fs filesystem",
},
{
InsertText: "vfat",
DescriptionText: "vfat",
Documentation: "Mount as vfat filesystem",
},
{
InsertText: "ntfs",
DescriptionText: "ntfs",
Documentation: "Mount as ntfs filesystem",
},
{
InsertText: "hfsplus",
DescriptionText: "hfsplus",
Documentation: "Mount as hfsplus filesystem",
},
{
InsertText: "tmpfs",
DescriptionText: "tmpfs",
Documentation: "Mount as tmpfs filesystem",
},
{
InsertText: "sysfs",
DescriptionText: "sysfs",
Documentation: "Mount as sysfs filesystem",
},
{
InsertText: "proc",
DescriptionText: "proc",
Documentation: "Mount as proc filesystem",
},
{
InsertText: "iso9660",
DescriptionText: "iso9660",
Documentation: "Mount as iso9660 filesystem",
},
{
InsertText: "udf",
DescriptionText: "udf",
Documentation: "Mount as udf filesystem",
},
{
InsertText: "squashfs",
DescriptionText: "squashfs",
Documentation: "Mount as squashfs filesystem",
},
{
InsertText: "nfs",
DescriptionText: "nfs",
Documentation: "Mount as nfs filesystem",
},
{
InsertText: "cifs",
DescriptionText: "cifs",
Documentation: "Mount as cifs filesystem",
},
},
),
},
}

View File

@ -3,7 +3,6 @@ package fstab
import (
docvalues "config-lsp/doc-values"
fstabdocumentation "config-lsp/handlers/fstab/documentation"
"fmt"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
@ -25,8 +24,6 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
cursor := params.Position.Character
targetField := entry.GetFieldAtPosition(cursor - 1)
println("cursor at", cursor, "target field", targetField)
switch targetField {
case FstabFieldSpec:
value, cursor := GetFieldSafely(entry.Fields.Spec, cursor)
@ -43,9 +40,7 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
cursor,
), nil
case FstabFieldFileSystemType:
println(fmt.Sprintf("file system type: %s", entry.Fields.FilesystemType))
value, cursor := GetFieldSafely(entry.Fields.FilesystemType, cursor)
println("CURSOR", cursor)
return fstabdocumentation.FileSystemTypeField.FetchCompletions(
value,
@ -64,10 +59,12 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa
value, cursor := GetFieldSafely(entry.Fields.Options, cursor)
return optionsField.FetchCompletions(
completions := optionsField.FetchCompletions(
value,
cursor,
), nil
)
return completions, nil
case FstabFieldFreq:
value, cursor := GetFieldSafely(entry.Fields.Freq, cursor)

View File

@ -11,8 +11,6 @@ import (
func TextDocumentDidOpen(context *glsp.Context, params *protocol.DidOpenTextDocumentParams) error {
readBytes, err := os.ReadFile(params.TextDocument.URI[len("file://"):])
println("opened i la language eta", params.TextDocument.LanguageID)
if err != nil {
return err
}