diff --git a/server/handlers/fstab/ast/fstab.go b/server/handlers/fstab/ast/fstab.go index 125e624..6346ecb 100644 --- a/server/handlers/fstab/ast/fstab.go +++ b/server/handlers/fstab/ast/fstab.go @@ -43,3 +43,4 @@ type FstabConfig struct { // [uint32]{} - line number to empty struct for comments CommentLines map[uint32]struct{} } + diff --git a/server/handlers/fstab/ast/fstab_fields.go b/server/handlers/fstab/ast/fstab_fields.go new file mode 100644 index 0000000..bbf52db --- /dev/null +++ b/server/handlers/fstab/ast/fstab_fields.go @@ -0,0 +1,35 @@ +package ast + +// func (c FstabConfig) GetEntry(line uint32) *FstabEntry { +// entry, found := c.Entries.Get(line) +// +// if !found { +// return nil +// } +// +// return entry.(*FstabEntry) +// } + +func (e FstabEntry) GetFieldAtPosition(cursor uint32) FstabFieldName { + if e.Fields.Spec == nil || (cursor >= e.Fields.Spec.Start.Character && cursor <= e.Fields.Spec.End.Character) { + return FstabFieldSpec + } + + if e.Fields.MountPoint == nil || (cursor >= e.Fields.MountPoint.Start.Character && cursor <= e.Fields.MountPoint.End.Character) { + return FstabFieldMountPoint + } + + if e.Fields.FilesystemType == nil || (cursor >= e.Fields.FilesystemType.Start.Character && cursor <= e.Fields.FilesystemType.End.Character) { + return FstabFieldFileSystemType + } + + if e.Fields.Options == nil || (cursor >= e.Fields.Options.Start.Character && cursor <= e.Fields.Options.End.Character) { + return FstabFieldOptions + } + + if e.Fields.Freq == nil || (cursor >= e.Fields.Freq.Start.Character && cursor <= e.Fields.Freq.End.Character) { + return FstabFieldFreq + } + + return FstabFieldPass +} diff --git a/server/handlers/fstab/documentation/documentation-freq.go b/server/handlers/fstab/fields/freq.go similarity index 100% rename from server/handlers/fstab/documentation/documentation-freq.go rename to server/handlers/fstab/fields/freq.go diff --git a/server/handlers/fstab/documentation/documentation-mount-point.go b/server/handlers/fstab/fields/mount-point.go similarity index 100% rename from server/handlers/fstab/documentation/documentation-mount-point.go rename to server/handlers/fstab/fields/mount-point.go diff --git a/server/handlers/fstab/documentation/documentation-mountoptions.go b/server/handlers/fstab/fields/mountoptions.go similarity index 86% rename from server/handlers/fstab/documentation/documentation-mountoptions.go rename to server/handlers/fstab/fields/mountoptions.go index 191bd3d..a268551 100644 --- a/server/handlers/fstab/documentation/documentation-mountoptions.go +++ b/server/handlers/fstab/fields/mountoptions.go @@ -193,13 +193,13 @@ var defaultOptions = []docvalues.EnumString{ ), docvalues.CreateEnumStringWithDoc( "x-systemd.automount", - `An automount unit will be created for the file system. See systemd.automount(5) for details. + `An automount unit will be created for the file system. See systemd.automount(5) for details. Added in version 215.`, ), docvalues.CreateEnumStringWithDoc( "x-systemd.makefs", - `The file system will be initialized on the device. If the device is not "empty", i.e. it contains any signature, the operation will be skipped. It is hence expected that this option remains set even after the device has been initialized. + `The file system will be initialized on the device. If the device is not "empty", i.e. it contains any signature, the operation will be skipped. It is hence expected that this option remains set even after the device has been initialized. Note that this option can only be used in /etc/fstab, and will be ignored when part of the Options= setting in a unit file. @@ -211,7 +211,7 @@ Added in version 236.`, ), docvalues.CreateEnumStringWithDoc( "x-systemd.growfs", - `The file system will be grown to occupy the full block device. If the file system is already at maximum size, no action will be performed. It is hence expected that this option remains set even after the file system has been grown. Only certain file system types are supported, see systemd-makefs@.service(8) for details. + `The file system will be grown to occupy the full block device. If the file system is already at maximum size, no action will be performed. It is hence expected that this option remains set even after the file system has been grown. Only certain file system types are supported, see systemd-makefs@.service(8) for details. Note that this option can only be used in /etc/fstab, and will be ignored when part of the Options= setting in a unit file. @@ -219,7 +219,7 @@ Added in version 236.`, ), docvalues.CreateEnumStringWithDoc( "x-systemd.pcrfs", - `Measures file system identity information (mount point, type, label, UUID, partition label, partition UUID) into PCR 15 after the file system has been mounted. This ensures the systemd-pcrfs@.service(8) or systemd-pcrfs-root.service services are pulled in by the mount unit. + `Measures file system identity information (mount point, type, label, UUID, partition label, partition UUID) into PCR 15 after the file system has been mounted. This ensures the systemd-pcrfs@.service(8) or systemd-pcrfs-root.service services are pulled in by the mount unit. Note that this option can only be used in /etc/fstab, and will be ignored when part of the Options= setting in a unit file. It is also implied for the root and /usr/ partitions discovered by systemd-gpt-auto-generator(8). @@ -227,13 +227,13 @@ Added in version 253.`, ), docvalues.CreateEnumStringWithDoc( "x-systemd.rw-only", - `If a mount operation fails to mount the file system read-write, it normally tries mounting the file system read-only instead. This option disables that behaviour, and causes the mount to fail immediately instead. This option is translated into the ReadWriteOnly= setting in a unit file. + `If a mount operation fails to mount the file system read-write, it normally tries mounting the file system read-only instead. This option disables that behaviour, and causes the mount to fail immediately instead. This option is translated into the ReadWriteOnly= setting in a unit file. Added in version 246.`, ), docvalues.CreateEnumStringWithDoc( "x-initrd.mount", - `An additional filesystem to be mounted in the initrd. See initrd-fs.target description in systemd.special(7). This is both an indicator to the initrd to mount this partition early and an indicator to the host to leave the partition mounted until final shutdown. Or in other words, if this flag is set it is assumed the mount shall be active during the entire regular runtime of the system, i.e. established before the initrd transitions into the host all the way until the host transitions to the final shutdown phase. + `An additional filesystem to be mounted in the initrd. See initrd-fs.target description in systemd.special(7). This is both an indicator to the initrd to mount this partition early and an indicator to the host to leave the partition mounted until final shutdown. Or in other words, if this flag is set it is assumed the mount shall be active during the entire regular runtime of the system, i.e. established before the initrd transitions into the host all the way until the host transitions to the final shutdown phase. Added in version 215.`, ), @@ -299,19 +299,19 @@ Added in version 245.`, ): docvalues.StringValue{}, docvalues.CreateEnumStringWithDoc( "x-systemd.wants-mounts-for", - `Configures a RequiresMountsFor= or WantsMountsFor= dependency between the created mount unit and other mount units. The argument must be an absolute path. This option may be specified more than once. See RequiresMountsFor= or WantsMountsFor= in systemd.unit(5) for details. + `Configures a RequiresMountsFor= or WantsMountsFor= dependency between the created mount unit and other mount units. The argument must be an absolute path. This option may be specified more than once. See RequiresMountsFor= or WantsMountsFor= in systemd.unit(5) for details. Added in version 220.`, ): docvalues.StringValue{}, docvalues.CreateEnumStringWithDoc( "x-systemd.requires-mounts-for", - `Configures a RequiresMountsFor= or WantsMountsFor= dependency between the created mount unit and other mount units. The argument must be an absolute path. This option may be specified more than once. See RequiresMountsFor= or WantsMountsFor= in systemd.unit(5) for details. + `Configures a RequiresMountsFor= or WantsMountsFor= dependency between the created mount unit and other mount units. The argument must be an absolute path. This option may be specified more than once. See RequiresMountsFor= or WantsMountsFor= in systemd.unit(5) for details. Added in version 220.`, ): docvalues.StringValue{}, docvalues.CreateEnumStringWithDoc( "x-systemd.device-bound", - `Takes a boolean argument. If true or no argument, a BindsTo= dependency on the backing device is set. If false, the mount unit is not stopped no matter whether the backing device is still present. This is useful when the file system is backed by volume managers. If not set, and the mount comes from unit fragments, i.e. generated from /etc/fstab by systemd-fstab-generator(8) or loaded from a manually configured mount unit, a combination of Requires= and StopPropagatedFrom= dependencies is set on the backing device. If doesn't, only Requires= is used. + `Takes a boolean argument. If true or no argument, a BindsTo= dependency on the backing device is set. If false, the mount unit is not stopped no matter whether the backing device is still present. This is useful when the file system is backed by volume managers. If not set, and the mount comes from unit fragments, i.e. generated from /etc/fstab by systemd-fstab-generator(8) or loaded from a manually configured mount unit, a combination of Requires= and StopPropagatedFrom= dependencies is set on the backing device. If doesn't, only Requires= is used. Added in version 233.`, ): docvalues.EnumValue{ @@ -323,13 +323,13 @@ Added in version 233.`, }, docvalues.CreateEnumStringWithDoc( "x-systemd.idle-timeout", - `Configures the idle timeout of the automount unit. See TimeoutIdleSec= in systemd.automount(5) for details. + `Configures the idle timeout of the automount unit. See TimeoutIdleSec= in systemd.automount(5) for details. Added in version 220.`, ): docvalues.StringValue{}, docvalues.CreateEnumStringWithDoc( "x-systemd.device-timeout", - `Configure how long systemd should wait for a device to show up before giving up on an entry from /etc/fstab. Specify a time in seconds or explicitly append a unit such as "s", "min", "h", "ms". + `Configure how long systemd should wait for a device to show up before giving up on an entry from /etc/fstab. Specify a time in seconds or explicitly append a unit such as "s", "min", "h", "ms". Note that this option can only be used in /etc/fstab, and will be ignored when part of the Options= setting in a unit file. @@ -337,7 +337,7 @@ Added in version 215.`, ): docvalues.StringValue{}, docvalues.CreateEnumStringWithDoc( "x-systemd.mount-timeout", - `Configure how long systemd should wait for the mount command to finish before giving up on an entry from /etc/fstab. Specify a time in seconds or explicitly append a unit such as "s", "min", "h", "ms". + `Configure how long systemd should wait for the mount command to finish before giving up on an entry from /etc/fstab. Specify a time in seconds or explicitly append a unit such as "s", "min", "h", "ms". Note that this option can only be used in /etc/fstab, and will be ignored when part of the Options= setting in a unit file. diff --git a/server/handlers/fstab/documentation/documentation-pass.go b/server/handlers/fstab/fields/pass.go similarity index 100% rename from server/handlers/fstab/documentation/documentation-pass.go rename to server/handlers/fstab/fields/pass.go diff --git a/server/handlers/fstab/documentation/documentation-spec.go b/server/handlers/fstab/fields/spec.go similarity index 90% rename from server/handlers/fstab/documentation/documentation-spec.go rename to server/handlers/fstab/fields/spec.go index 2cf7db2..5d63a39 100644 --- a/server/handlers/fstab/documentation/documentation-spec.go +++ b/server/handlers/fstab/fields/spec.go @@ -15,7 +15,7 @@ var LabelField = docvalues.RegexValue{ var SpecField = docvalues.OrValue{ Values: []docvalues.DeprecatedValue{ docvalues.PathValue{ - RequiredType: docvalues.PathTypeFile & docvalues.PathTypeExistenceOptional, + RequiredType: docvalues.PathTypeFile, }, docvalues.KeyEnumAssignmentValue{ Separator: "=", diff --git a/server/handlers/fstab/documentation/documentation-type.go b/server/handlers/fstab/fields/type.go similarity index 100% rename from server/handlers/fstab/documentation/documentation-type.go rename to server/handlers/fstab/fields/type.go diff --git a/server/handlers/fstab/fstab_test.go b/server/handlers/fstab/fstab_test.go index 629c690..9f16e01 100644 --- a/server/handlers/fstab/fstab_test.go +++ b/server/handlers/fstab/fstab_test.go @@ -1,7 +1,7 @@ package fstab import ( - fstabdocumentation "config-lsp/handlers/fstab/documentation" + fstabdocumentation "config-lsp/handlers/fstab/fields" handlers "config-lsp/handlers/fstab/handlers" "config-lsp/handlers/fstab/parser" "config-lsp/utils" @@ -158,6 +158,12 @@ UUID=b411dc99-f0a0-4c87-9e05-184977be8539 /home ext4 defaults 0 2 if len(errors) > 0 { t.Fatalf("ParseFromContent failed with error %v", errors) } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } } func TestArchExample2(t *testing.T) { @@ -192,6 +198,12 @@ LABEL=Swap none swap defaults 0 0 if len(errors) > 0 { t.Fatalf("ParseFromContent failed with error %v", errors) } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } } func TestArchExample4(t *testing.T) { @@ -209,6 +221,12 @@ UUID=f9fe0b69-a280-415d-a03a-a32752370dee none swap defaults 0 0 if len(errors) > 0 { t.Fatalf("ParseFromContent failed with error %v", errors) } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } } func TestArchExample5(t *testing.T) { @@ -226,6 +244,12 @@ PARTLABEL=Swap none swap defaults 0 0 if len(errors) > 0 { t.Fatalf("ParseFromContent failed with error %v", errors) } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } } func TestArchExample6(t *testing.T) { @@ -243,5 +267,89 @@ PARTUUID=039b6c1c-7553-4455-9537-1befbc9fbc5b none swap defaults 0 0 if len(errors) > 0 { t.Fatalf("ParseFromContent failed with error %v", errors) } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } } +func TestLinuxConfigExample(t *testing.T) { + input := utils.Dedent(` +UUID=80b496fa-ce2d-4dcf-9afc-bcaa731a67f1 /mnt/example ext4 defaults 0 2 +`) + p := parser.FstabParser{} + p.Clear() + + errors := p.ParseFromContent(input) + + if len(errors) > 0 { + t.Fatalf("ParseFromContent failed with error %v", errors) + } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } +} + +func Test1(t *testing.T) { + input := utils.Dedent(` +PARTLABEL="rootfs" / ext4 noatime,lazytime,rw 0 0 +`) + p := parser.FstabParser{} + p.Clear() + + errors := p.ParseFromContent(input) + + if len(errors) > 0 { + t.Fatalf("ParseFromContent failed with error %v", errors) + } + + diagnostics := p.AnalyzeValues() + + if len(diagnostics) > 0 { + t.Errorf("AnalyzeValues failed with error %v", diagnostics) + } +} + +func Test2(t *testing.T) { + input := utils.Dedent(` +/dev/sda /home1 xfs defaults 1 2 +/dev/sdb /homeB xfs noauto,nobarrier,rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0 +/dev/sdc /homeC xfs noauto,defaults 0 0 +/dev/sdd /homeD xfs noauto,rw,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0 +/dev/sde /homeE xfs defaults 0 0 +`) + p := parser.FstabParser{} + p.Clear() + + errors := p.ParseFromContent(input) + + if len(errors) > 0 { + t.Fatalf("ParseFromContent failed with error %v", errors) + } +} + +func Test3(t *testing.T) { + input := utils.Dedent(` +/dev/disk/by-label/dsp /dsp auto ro +/dev/disk/by-partlabel/modem_a /firmware auto ro +/dev/disk/by-partlabel/persist /persist auto ro,discard,nosuid,nodev,noexec +/dev/disk/by-partlabel/userdata /data auto discard,noatime,nodiratime,nosuid,nodev,nofail 0 0 +/dev/disk/by-partlabel/cache /cache ext4 relatime,data=ordered,noauto_da_alloc,discard,noexec,nodev,nosuid,x-systemd.makefs 0 0 +/dev/nvme0n1 /data/media auto discard,nosuid,nodev,nofail,x-systemd.device-timeout=5s 0 0 +tmpfs /var tmpfs rw,nosuid,nodev,size=128M,mode=755 0 0 +tmpfs /tmp tmpfs rw,nosuid,nodev,size=150M,mode=1777 0 0 +`) + p := parser.FstabParser{} + p.Clear() + + errors := p.ParseFromContent(input) + + if len(errors) > 0 { + t.Fatalf("ParseFromContent failed with error %v", errors) + } +} diff --git a/server/handlers/fstab/handlers/completions.go b/server/handlers/fstab/handlers/completions.go index 35b79e2..8743fe6 100644 --- a/server/handlers/fstab/handlers/completions.go +++ b/server/handlers/fstab/handlers/completions.go @@ -2,41 +2,42 @@ package handlers import ( "config-lsp/doc-values" - "config-lsp/handlers/fstab/documentation" - "config-lsp/handlers/fstab/parser" + "config-lsp/handlers/fstab/ast" + "config-lsp/handlers/fstab/fields" + "github.com/tliron/glsp/protocol_3_16" ) func GetCompletion( - line parser.FstabLine, + entry *ast.FstabEntry, cursor uint32, ) ([]protocol.CompletionItem, error) { - targetField := line.GetFieldAtPosition(cursor) + targetField := entry.GetFieldAtPosition(cursor) switch targetField { - case parser.FstabFieldSpec: - value, cursor := GetFieldSafely(line.Fields.Spec, cursor) + case ast.FstabFieldSpec: + value, cursor := getFieldSafely(entry.Fields.Spec, cursor) return fstabdocumentation.SpecField.DeprecatedFetchCompletions( value, cursor, ), nil - case parser.FstabFieldMountPoint: - value, cursor := GetFieldSafely(line.Fields.MountPoint, cursor) + case ast.FstabFieldMountPoint: + value, cursor := getFieldSafely(entry.Fields.MountPoint, cursor) return fstabdocumentation.MountPointField.DeprecatedFetchCompletions( value, cursor, ), nil - case parser.FstabFieldFileSystemType: - value, cursor := GetFieldSafely(line.Fields.FilesystemType, cursor) + case ast.FstabFieldFileSystemType: + value, cursor := getFieldSafely(entry.Fields.FilesystemType, cursor) return fstabdocumentation.FileSystemTypeField.DeprecatedFetchCompletions( value, cursor, ), nil - case parser.FstabFieldOptions: - fileSystemType := line.Fields.FilesystemType.Value + case ast.FstabFieldOptions: + fileSystemType := entry.Fields.FilesystemType.Value.Value var optionsField docvalues.DeprecatedValue @@ -46,7 +47,7 @@ func GetCompletion( optionsField = fstabdocumentation.DefaultMountOptionsField } - value, cursor := GetFieldSafely(line.Fields.Options, cursor) + value, cursor := getFieldSafely(entry.Fields.Options, cursor) completions := optionsField.DeprecatedFetchCompletions( value, @@ -54,15 +55,15 @@ func GetCompletion( ) return completions, nil - case parser.FstabFieldFreq: - value, cursor := GetFieldSafely(line.Fields.Freq, cursor) + case ast.FstabFieldFreq: + value, cursor := getFieldSafely(entry.Fields.Freq, cursor) return fstabdocumentation.FreqField.DeprecatedFetchCompletions( value, cursor, ), nil - case parser.FstabFieldPass: - value, cursor := GetFieldSafely(line.Fields.Pass, cursor) + case ast.FstabFieldPass: + value, cursor := getFieldSafely(entry.Fields.Pass, cursor) return fstabdocumentation.PassField.DeprecatedFetchCompletions( value, @@ -75,14 +76,14 @@ func GetCompletion( // Safely get value and new cursor position // If field is nil, return empty string and 0 -func GetFieldSafely(field *parser.Field, character uint32) (string, uint32) { +func getFieldSafely(field *ast.FstabField, character uint32) (string, uint32) { if field == nil { return "", 0 } - if field.Value == "" { + if field.Value.Value == "" { return "", 0 } - return field.Value, character - field.Start + return field.Value.Raw, character - field.Start.Character } diff --git a/server/handlers/fstab/handlers/hover.go b/server/handlers/fstab/handlers/hover.go index 33fd213..7f07045 100644 --- a/server/handlers/fstab/handlers/hover.go +++ b/server/handlers/fstab/handlers/hover.go @@ -2,25 +2,29 @@ package handlers import ( "config-lsp/doc-values" - "config-lsp/handlers/fstab/documentation" - "config-lsp/handlers/fstab/parser" - "github.com/tliron/glsp/protocol_3_16" + "config-lsp/handlers/fstab/ast" + "config-lsp/handlers/fstab/fields" "strings" + + "github.com/tliron/glsp/protocol_3_16" ) -func GetHoverInfo(entry *parser.FstabEntry, cursor uint32) (*protocol.Hover, error) { - line := entry.Line - targetField := line.GetFieldAtPosition(cursor) +func GetHoverInfo( + line uint32, + cursor uint32, + entry *ast.FstabEntry, +) (*protocol.Hover, error) { + targetField := entry.GetFieldAtPosition(cursor) switch targetField { - case parser.FstabFieldSpec: + case ast.FstabFieldSpec: return &SpecHoverField, nil - case parser.FstabFieldMountPoint: + case ast.FstabFieldMountPoint: return &MountPointHoverField, nil - case parser.FstabFieldFileSystemType: + case ast.FstabFieldFileSystemType: return &FileSystemTypeField, nil - case parser.FstabFieldOptions: - fileSystemType := line.Fields.FilesystemType.Value + case ast.FstabFieldOptions: + fileSystemType := entry.Fields.FilesystemType.Value.Value var optionsField docvalues.DeprecatedValue if foundField, found := fstabdocumentation.MountOptionsMapField[fileSystemType]; found { @@ -29,8 +33,8 @@ func GetHoverInfo(entry *parser.FstabEntry, cursor uint32) (*protocol.Hover, err optionsField = fstabdocumentation.DefaultMountOptionsField } - relativeCursor := cursor - line.Fields.Options.Start - fieldInfo := optionsField.DeprecatedFetchHoverInfo(line.Fields.Options.Value, relativeCursor) + relativeCursor := cursor - entry.Fields.Options.Start.Character + fieldInfo := optionsField.DeprecatedFetchHoverInfo(entry.Fields.Options.Value.Value, relativeCursor) hover := protocol.Hover{ Contents: protocol.MarkupContent{ @@ -40,9 +44,9 @@ func GetHoverInfo(entry *parser.FstabEntry, cursor uint32) (*protocol.Hover, err } return &hover, nil - case parser.FstabFieldFreq: + case ast.FstabFieldFreq: return &FreqHoverField, nil - case parser.FstabFieldPass: + case ast.FstabFieldPass: return &PassHoverField, nil } diff --git a/server/handlers/fstab/lsp/text-document-completion.go b/server/handlers/fstab/lsp/text-document-completion.go index 375fbd2..f91c598 100644 --- a/server/handlers/fstab/lsp/text-document-completion.go +++ b/server/handlers/fstab/lsp/text-document-completion.go @@ -2,9 +2,9 @@ package lsp import ( "config-lsp/common" - fstabdocumentation "config-lsp/handlers/fstab/documentation" + "config-lsp/handlers/fstab/ast" + fstabdocumentation "config-lsp/handlers/fstab/fields" "config-lsp/handlers/fstab/handlers" - "config-lsp/handlers/fstab/parser" "config-lsp/handlers/fstab/shared" "github.com/tliron/glsp" @@ -12,9 +12,9 @@ import ( ) func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) { - p := shared.DocumentParserMap[params.TextDocument.URI] + c := shared.DocumentParserMap[params.TextDocument.URI] - entry, found := p.GetEntry(params.Position.Line) + rawEntry, found := c.Entries.Get(params.Position.Line) if !found { // Empty line, return spec completions @@ -24,12 +24,9 @@ func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionPa ), nil } - if entry.Type == parser.FstabEntryTypeComment { - return nil, nil - } + entry := rawEntry.(*ast.FstabEntry) cursor := common.CursorToCharacterIndex(params.Position.Character) - line := entry.Line - return handlers.GetCompletion(line, cursor) + return handlers.GetCompletion(entry, cursor) } diff --git a/server/handlers/fstab/lsp/text-document-did-change.go b/server/handlers/fstab/lsp/text-document-did-change.go index 2864e19..a997aec 100644 --- a/server/handlers/fstab/lsp/text-document-did-change.go +++ b/server/handlers/fstab/lsp/text-document-did-change.go @@ -19,17 +19,17 @@ func TextDocumentDidChange( p.Clear() diagnostics := make([]protocol.Diagnostic, 0) - errors := p.ParseFromContent(content) + errors := p.Parse(content) if len(errors) > 0 { diagnostics = append(diagnostics, utils.Map( errors, - func(err common.ParseError) protocol.Diagnostic { + func(err common.LSPError) protocol.Diagnostic { return err.ToDiagnostic() }, )...) } else { - diagnostics = append(diagnostics, p.AnalyzeValues()...) + // diagnostics = append(diagnostics, p.AnalyzeValues()...) } if len(diagnostics) > 0 { diff --git a/server/handlers/fstab/lsp/text-document-did-open.go b/server/handlers/fstab/lsp/text-document-did-open.go index 6658b21..7e89ca6 100644 --- a/server/handlers/fstab/lsp/text-document-did-open.go +++ b/server/handlers/fstab/lsp/text-document-did-open.go @@ -2,9 +2,10 @@ package lsp import ( "config-lsp/common" - "config-lsp/handlers/fstab/parser" + "config-lsp/handlers/fstab/ast" "config-lsp/handlers/fstab/shared" "config-lsp/utils" + "github.com/tliron/glsp" protocol "github.com/tliron/glsp/protocol_3_16" ) @@ -15,24 +16,23 @@ func TextDocumentDidOpen( ) error { common.ClearDiagnostics(context, params.TextDocument.URI) - p := parser.FstabParser{} - p.Clear() - shared.DocumentParserMap[params.TextDocument.URI] = &p + p := ast.NewFstabConfig() + shared.DocumentParserMap[params.TextDocument.URI] = p content := params.TextDocument.Text diagnostics := make([]protocol.Diagnostic, 0) - errors := p.ParseFromContent(content) + errors := p.Parse(content) if len(errors) > 0 { diagnostics = append(diagnostics, utils.Map( errors, - func(err common.ParseError) protocol.Diagnostic { + func(err common.LSPError) protocol.Diagnostic { return err.ToDiagnostic() }, )...) } else { - diagnostics = append(diagnostics, p.AnalyzeValues()...) + // diagnostics = append(diagnostics, p.AnalyzeValues()...) } if len(diagnostics) > 0 { diff --git a/server/handlers/fstab/lsp/text-document-hover.go b/server/handlers/fstab/lsp/text-document-hover.go index 310706e..c29ab2f 100644 --- a/server/handlers/fstab/lsp/text-document-hover.go +++ b/server/handlers/fstab/lsp/text-document-hover.go @@ -1,29 +1,32 @@ package lsp import ( + "config-lsp/handlers/fstab/ast" "config-lsp/handlers/fstab/handlers" - "config-lsp/handlers/fstab/parser" "config-lsp/handlers/fstab/shared" + "github.com/tliron/glsp" protocol "github.com/tliron/glsp/protocol_3_16" ) func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) { + line := params.Position.Line cursor := params.Position.Character p := shared.DocumentParserMap[params.TextDocument.URI] - entry, found := p.GetEntry(params.Position.Line) + rawEntry, found := p.Entries.Get(params.Position.Line) // Empty line if !found { return nil, nil } - // Comment line - if entry.Type == parser.FstabEntryTypeComment { - return nil, nil - } + entry := rawEntry.(*ast.FstabEntry) - return handlers.GetHoverInfo(entry, cursor) + return handlers.GetHoverInfo( + line, + cursor, + entry, + ) } diff --git a/server/handlers/fstab/parser/parser.go b/server/handlers/fstab/parser/parser.go index a57165a..3d9b2a7 100644 --- a/server/handlers/fstab/parser/parser.go +++ b/server/handlers/fstab/parser/parser.go @@ -3,7 +3,7 @@ package parser import ( "config-lsp/common" docvalues "config-lsp/doc-values" - fstabdocumentation "config-lsp/handlers/fstab/documentation" + fstabdocumentation "config-lsp/handlers/fstab/fields" "fmt" "regexp" "strings" @@ -378,8 +378,6 @@ func (p *FstabParser) AnalyzeValues() []protocol.Diagnostic { if len(newDiagnostics) > 0 { diagnostics = append(diagnostics, newDiagnostics...) } - case FstabEntryTypeComment: - // Do nothing } } diff --git a/server/handlers/fstab/shared/document.go b/server/handlers/fstab/shared/document.go index e25de3b..a8fc0d2 100644 --- a/server/handlers/fstab/shared/document.go +++ b/server/handlers/fstab/shared/document.go @@ -1,8 +1,10 @@ package shared import ( - "config-lsp/handlers/fstab/parser" + "config-lsp/handlers/fstab/ast" + protocol "github.com/tliron/glsp/protocol_3_16" ) -var DocumentParserMap = map[protocol.DocumentUri]*parser.FstabParser{} +var DocumentParserMap = map[protocol.DocumentUri]*ast.FstabConfig{} +