config-lsp/handlers/ssh_config/ast/ssh_config_fields.go

244 lines
4.9 KiB
Go

package ast
import (
"config-lsp/common"
"config-lsp/utils"
"github.com/emirpasic/gods/maps/treemap"
)
type SSHBlockType uint8
const (
SSHBlockTypeMatch SSHBlockType = iota
SSHBlockTypeHost
)
type SSHBlock interface {
GetBlockType() SSHBlockType
AddOption(option *SSHOption)
SetEnd(common.Location)
GetOptions() *treemap.Map
GetEntryOption() *SSHOption
GetLocation() common.LocationRange
}
func (b *SSHMatchBlock) GetBlockType() SSHBlockType {
return SSHBlockTypeMatch
}
func (b *SSHMatchBlock) AddOption(option *SSHOption) {
b.Options.Put(option.LocationRange.Start.Line, option)
}
func (b *SSHMatchBlock) SetEnd(end common.Location) {
b.LocationRange.End = end
}
func (b *SSHMatchBlock) GetOptions() *treemap.Map {
return b.Options
}
func (b *SSHMatchBlock) GetEntryOption() *SSHOption {
return b.MatchOption
}
func (b *SSHMatchBlock) GetLocation() common.LocationRange {
return b.LocationRange
}
func (b *SSHHostBlock) GetBlockType() SSHBlockType {
return SSHBlockTypeHost
}
func (b *SSHHostBlock) AddOption(option *SSHOption) {
b.Options.Put(option.LocationRange.Start.Line, option)
}
func (b *SSHHostBlock) SetEnd(end common.Location) {
b.LocationRange.End = end
}
func (b *SSHHostBlock) GetOptions() *treemap.Map {
return b.Options
}
func (b *SSHHostBlock) GetEntryOption() *SSHOption {
return b.HostOption
}
func (b *SSHHostBlock) GetLocation() common.LocationRange {
return b.LocationRange
}
type SSHType uint8
const (
SSHTypeOption SSHType = iota
SSHTypeMatch
SSHTypeHost
)
type SSHEntry interface {
GetType() SSHType
GetOption() *SSHOption
}
func (o *SSHOption) GetType() SSHType {
return SSHTypeOption
}
func (o *SSHOption) GetOption() *SSHOption {
return o
}
func (b *SSHMatchBlock) GetType() SSHType {
return SSHTypeMatch
}
func (b *SSHMatchBlock) GetOption() *SSHOption {
return b.MatchOption
}
func (b *SSHHostBlock) GetType() SSHType {
return SSHTypeHost
}
func (b *SSHHostBlock) GetOption() *SSHOption {
return b.HostOption
}
// FindBlock Gets the block based on the line number
// Note: This does not find the block strictly.
// This means an empty line will belong to the previous block
// However, this is required for example for completions, as the
// user is about to type the new option, and we therefore need to know
// which block this new option will belong to.
//
// You will probably need this in most cases
func (c SSHConfig) FindBlock(line uint32) SSHBlock {
it := c.Options.Iterator()
it.End()
for it.Prev() {
entry := it.Value().(SSHEntry)
if entry.GetType() == SSHTypeOption {
continue
}
block := entry.(SSHBlock)
if line >= block.GetLocation().Start.Line {
return block
}
}
return nil
}
func (c SSHConfig) FindOption(line uint32) (*SSHOption, SSHBlock) {
block := c.FindBlock(line)
var option *SSHOption
if block == nil {
if rawOption, found := c.Options.Get(line); found {
option = rawOption.(*SSHOption)
}
} else {
if line == block.GetLocation().Start.Line {
return block.GetEntryOption(), block
}
if rawOption, found := block.GetOptions().Get(line); found {
option = rawOption.(*SSHOption)
}
}
return option, block
}
type AllOptionInfo struct {
Block SSHBlock
Option *SSHOption
}
func (c SSHConfig) GetAllOptionsForBlock(block SSHBlock) []AllOptionInfo {
if block == nil {
return c.GetAllOptions()
}
return utils.Map(
block.GetOptions().Values(),
func(rawOption interface{}) AllOptionInfo {
option := rawOption.(*SSHOption)
return AllOptionInfo{
Block: block,
Option: option,
}
},
)
}
func (c SSHConfig) GetAllOptions() []AllOptionInfo {
options := make([]AllOptionInfo, 0, 50)
for _, rawEntry := range c.Options.Values() {
switch rawEntry.(type) {
case *SSHOption:
option := rawEntry.(*SSHOption)
options = append(options, AllOptionInfo{
Block: nil,
Option: option,
})
case *SSHMatchBlock:
block := rawEntry.(SSHBlock)
options = append(options, AllOptionInfo{
Block: block,
Option: block.GetEntryOption(),
})
for _, rawOption := range block.GetOptions().Values() {
option := rawOption.(*SSHOption)
options = append(options, AllOptionInfo{
Block: block,
Option: option,
})
}
case *SSHHostBlock:
block := rawEntry.(SSHBlock)
options = append(options, AllOptionInfo{
Block: block,
Option: block.GetEntryOption(),
})
for _, rawOption := range block.GetOptions().Values() {
option := rawOption.(*SSHOption)
options = append(options, AllOptionInfo{
Block: block,
Option: option,
})
}
}
}
return options
}
func (c SSHConfig) GetOptionsInRange(startLine uint32, endLine uint32) []AllOptionInfo {
options := make([]AllOptionInfo, 0, 50)
for _, info := range c.GetAllOptions() {
if info.Option.LocationRange.Start.Line >= startLine && info.Option.LocationRange.End.Line <= endLine {
options = append(options, info)
}
}
return options
}