mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
Merge pull request #24 from Myzel394/improvements
This commit is contained in:
commit
fcdd70030f
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
- name: Check version in code matches flake version
|
||||
shell: bash
|
||||
run: |
|
||||
if ! [ $(grep '// CI:CD-VERSION$' server/root-handler/handler.go | cut -d'"' -f 2) = $(grep '# CI:CD-VERSION$' flake.nix | cut -d'"' -f 2) ];
|
||||
if ! [ $(grep '// CI:CD-VERSION$' server/root-handler/common.go | cut -d'"' -f 2) = $(grep '# CI:CD-VERSION$' flake.nix | cut -d'"' -f 2) ];
|
||||
then
|
||||
echo "Version mismatch between code and flake"
|
||||
exit 1
|
||||
|
53
README.md
53
README.md
@ -28,11 +28,52 @@ You are welcome to request any config file, as far as it's fairly well known.
|
||||
|
||||
## Installation
|
||||
|
||||
### VS Code Extension
|
||||
|
||||
[Install the extension from the marketplace](https://marketplace.visualstudio.com/items?itemName=myzel394.config-lsp)
|
||||
|
||||
Alternatively, you can also manually install the extension:
|
||||
|
||||
1. Download the latest extension version from the [release page](https://github.com/Myzel394/config-lsp/releases) - You can find the extension under the "assets" section. The filename ends with `.vsix`
|
||||
2. Open VS Code
|
||||
3. Open the extensions sidebar
|
||||
4. In the top bar, click on the three dots and select "Install from VSIX..."
|
||||
5. Select the just downloaded `.vsix` file
|
||||
6. You may need to restart VS Code
|
||||
7. Enjoy!
|
||||
|
||||
### Manual installation
|
||||
|
||||
To use `config-lsp` in any other editor, you'll need to install it manually.
|
||||
Don't worry, it's easy!
|
||||
|
||||
#### Installing the latest Binary
|
||||
|
||||
##### Brew
|
||||
|
||||
```sh
|
||||
brew install myzel394/formulae/config-lsp
|
||||
```
|
||||
|
||||
##### Manual Binary
|
||||
|
||||
Download the latest binary from the [releases page](https://github.com/Myzel394/config-lsp/releases) and put it in your PATH.
|
||||
|
||||
Follow the instructions for your editor below.
|
||||
##### Compiling
|
||||
|
||||
### Neovim installation
|
||||
You can either compile the binary using go:
|
||||
|
||||
```sh
|
||||
go build -o config-lsp
|
||||
```
|
||||
|
||||
or build it using Nix:
|
||||
|
||||
```sh
|
||||
nix flake build
|
||||
```
|
||||
|
||||
#### Neovim installation
|
||||
|
||||
Using [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) you can add `config-lsp` by adding the following to your `lsp.lua` (filename might differ):
|
||||
|
||||
@ -57,14 +98,6 @@ end
|
||||
lspconfig.config_lsp.setup {}
|
||||
`````
|
||||
|
||||
### VS Code installation
|
||||
|
||||
The VS Code extension is currently in development. An official extension will be released soon.
|
||||
|
||||
However, at the moment you can also compile the extension yourself and run it in development mode.
|
||||
|
||||
**Do not create an extension and publish it yourself. Contribute to the official extension instead.**
|
||||
|
||||
## Supporting config-lsp
|
||||
|
||||
You can either contribute to the project, [see CONTRIBUTING.md](CONTRIBUTING.md), or you can sponsor me via [GitHub Sponsors](https://github.com/sponsors/Myzel394) or via [crypto currencies](https://github.com/Myzel394/contact-me?tab=readme-ov-file#donations).
|
||||
|
@ -23,7 +23,7 @@
|
||||
"aarch64-windows"
|
||||
] (system:
|
||||
let
|
||||
version = "0.1.1"; # CI:CD-VERSION
|
||||
version = "0.1.2"; # CI:CD-VERSION
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [
|
||||
|
@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
roothandler "config-lsp/root-handler"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/tliron/commonlog"
|
||||
|
||||
@ -11,6 +13,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 && (os.Args[1] == "--version" || os.Args[1] == "version") {
|
||||
fmt.Println(roothandler.Version)
|
||||
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
// This increases logging verbosity (optional)
|
||||
commonlog.Configure(1, nil)
|
||||
|
||||
|
5
server/root-handler/common.go
Normal file
5
server/root-handler/common.go
Normal file
@ -0,0 +1,5 @@
|
||||
package roothandler
|
||||
|
||||
// The comment below at the end of the line is required for the CI:CD to work.
|
||||
// Do not remove it
|
||||
var Version = "0.1.2" // CI:CD-VERSION
|
@ -1,6 +1,8 @@
|
||||
package roothandler
|
||||
|
||||
import (
|
||||
"config-lsp/root-handler/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
|
||||
@ -9,32 +11,29 @@ import (
|
||||
|
||||
const lsName = "config-lsp"
|
||||
|
||||
// The comment below at the end of the line is required for the CI:CD to work.
|
||||
// Do not remove it
|
||||
var version = "0.1.1" // CI:CD-VERSION
|
||||
|
||||
var lspHandler protocol.Handler
|
||||
|
||||
// The root handler which handles all the LSP requests and then forwards them to the appropriate handler
|
||||
func SetUpRootHandler() {
|
||||
rootHandler = NewRootHandler()
|
||||
shared.Handler = shared.NewRootHandler()
|
||||
|
||||
lspHandler = protocol.Handler{
|
||||
Initialize: initialize,
|
||||
Initialized: initialized,
|
||||
Shutdown: shutdown,
|
||||
SetTrace: setTrace,
|
||||
TextDocumentDidOpen: TextDocumentDidOpen,
|
||||
TextDocumentDidChange: TextDocumentDidChange,
|
||||
TextDocumentCompletion: TextDocumentCompletion,
|
||||
TextDocumentHover: TextDocumentHover,
|
||||
TextDocumentDidClose: TextDocumentDidClose,
|
||||
TextDocumentCodeAction: TextDocumentCodeAction,
|
||||
TextDocumentDefinition: TextDocumentDefinition,
|
||||
WorkspaceExecuteCommand: WorkspaceExecuteCommand,
|
||||
TextDocumentRename: TextDocumentRename,
|
||||
TextDocumentPrepareRename: TextDocumentPrepareRename,
|
||||
TextDocumentSignatureHelp: TextDocumentSignatureHelp,
|
||||
TextDocumentRangeFormatting: TextDocumentRangeFormattingFunc,
|
||||
TextDocumentDidOpen: lsp.TextDocumentDidOpen,
|
||||
TextDocumentDidChange: lsp.TextDocumentDidChange,
|
||||
TextDocumentCompletion: lsp.TextDocumentCompletion,
|
||||
TextDocumentHover: lsp.TextDocumentHover,
|
||||
TextDocumentDidClose: lsp.TextDocumentDidClose,
|
||||
TextDocumentCodeAction: lsp.TextDocumentCodeAction,
|
||||
TextDocumentDefinition: lsp.TextDocumentDefinition,
|
||||
WorkspaceExecuteCommand: lsp.WorkspaceExecuteCommand,
|
||||
TextDocumentRename: lsp.TextDocumentRename,
|
||||
TextDocumentPrepareRename: lsp.TextDocumentPrepareRename,
|
||||
TextDocumentSignatureHelp: lsp.TextDocumentSignatureHelp,
|
||||
TextDocumentRangeFormatting: lsp.TextDocumentRangeFormattingFunc,
|
||||
}
|
||||
|
||||
server := server.NewServer(&lspHandler, lsName, false)
|
||||
@ -72,7 +71,7 @@ func initialize(context *glsp.Context, params *protocol.InitializeParams) (any,
|
||||
Capabilities: capabilities,
|
||||
ServerInfo: &protocol.InitializeResultServerInfo{
|
||||
Name: lsName,
|
||||
Version: &version,
|
||||
Version: &Version,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -1,149 +0,0 @@
|
||||
package roothandler
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/utils"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
type SupportedLanguage string
|
||||
|
||||
const (
|
||||
LanguageSSHConfig SupportedLanguage = "ssh_config"
|
||||
LanguageSSHDConfig SupportedLanguage = "sshd_config"
|
||||
LanguageFstab SupportedLanguage = "fstab"
|
||||
LanguageWireguard SupportedLanguage = "languagewireguard"
|
||||
LanguageHosts SupportedLanguage = "hosts"
|
||||
LanguageAliases SupportedLanguage = "aliases"
|
||||
)
|
||||
|
||||
var AllSupportedLanguages = []string{
|
||||
string(LanguageSSHConfig),
|
||||
string(LanguageSSHDConfig),
|
||||
string(LanguageFstab),
|
||||
string(LanguageWireguard),
|
||||
string(LanguageHosts),
|
||||
string(LanguageAliases),
|
||||
}
|
||||
|
||||
type FatalFileNotReadableError struct {
|
||||
FileURI protocol.DocumentUri
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e FatalFileNotReadableError) Error() string {
|
||||
return fmt.Sprintf("Fatal error! config-lsp was unable to read the file (%s); error: %s", e.FileURI, e.Err.Error())
|
||||
}
|
||||
|
||||
type UnsupportedLanguageError struct {
|
||||
SuggestedLanguage string
|
||||
}
|
||||
|
||||
func (e UnsupportedLanguageError) Error() string {
|
||||
return fmt.Sprintf("Language '%s' is not supported. Choose one of: %s", e.SuggestedLanguage, strings.Join(AllSupportedLanguages, ", "))
|
||||
}
|
||||
|
||||
type LanguageUndetectableError struct{}
|
||||
|
||||
func (e LanguageUndetectableError) Error() string {
|
||||
return "Please add: '#?lsp.language=<language>' to the top of the file. config-lsp was unable to detect the appropriate language for this file."
|
||||
}
|
||||
|
||||
var valueToLanguageMap = map[string]SupportedLanguage{
|
||||
"sshd_config": LanguageSSHDConfig,
|
||||
"sshdconfig": LanguageSSHDConfig,
|
||||
|
||||
"ssh_config": LanguageSSHConfig,
|
||||
"sshconfig": LanguageSSHConfig,
|
||||
|
||||
".ssh/config": LanguageSSHConfig,
|
||||
"~/.ssh/config": LanguageSSHConfig,
|
||||
|
||||
"fstab": LanguageFstab,
|
||||
"etc/fstab": LanguageFstab,
|
||||
|
||||
"wireguard": LanguageWireguard,
|
||||
"wg": LanguageWireguard,
|
||||
"languagewireguard": LanguageWireguard,
|
||||
"host": LanguageHosts,
|
||||
"hosts": LanguageHosts,
|
||||
"etc/hosts": LanguageHosts,
|
||||
|
||||
"aliases": LanguageAliases,
|
||||
"mailaliases": LanguageAliases,
|
||||
"etc/aliases": LanguageAliases,
|
||||
}
|
||||
|
||||
var typeOverwriteRegex = regexp.MustCompile(`#\?\s*lsp\.language\s*=\s*(\w+)\s*`)
|
||||
var wireguardPattern = regexp.MustCompile(`/wg\d+\.conf$`)
|
||||
|
||||
var undetectableError = common.ParseError{
|
||||
Line: 0,
|
||||
Err: LanguageUndetectableError{},
|
||||
}
|
||||
|
||||
func DetectLanguage(
|
||||
content string,
|
||||
advertisedLanguage string,
|
||||
uri protocol.DocumentUri,
|
||||
) (SupportedLanguage, error) {
|
||||
if match := typeOverwriteRegex.FindStringSubmatch(content); match != nil {
|
||||
suggestedLanguage := strings.ToLower(match[1])
|
||||
|
||||
foundLanguage, ok := valueToLanguageMap[suggestedLanguage]
|
||||
|
||||
if ok {
|
||||
return foundLanguage, nil
|
||||
}
|
||||
|
||||
matchIndex := strings.Index(content, match[0])
|
||||
contentUntilMatch := content[:matchIndex]
|
||||
|
||||
return "", common.ParseError{
|
||||
Line: uint32(utils.CountCharacterOccurrences(contentUntilMatch, '\n')),
|
||||
Err: UnsupportedLanguageError{
|
||||
SuggestedLanguage: suggestedLanguage,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if language, ok := valueToLanguageMap[advertisedLanguage]; ok {
|
||||
return language, nil
|
||||
}
|
||||
|
||||
switch uri {
|
||||
case "file:///etc/ssh/sshd_config":
|
||||
fallthrough
|
||||
case "file:///etc/ssh/ssh_config":
|
||||
return LanguageSSHDConfig, nil
|
||||
|
||||
case "file:///etc/fstab":
|
||||
return LanguageFstab, nil
|
||||
|
||||
// Darwin
|
||||
case "file:///private/etc/hosts":
|
||||
fallthrough
|
||||
case "file:///etc/hosts":
|
||||
return LanguageHosts, nil
|
||||
|
||||
// Darwin
|
||||
case "file:///private/etc/aliases":
|
||||
fallthrough
|
||||
case "file:///etc/aliases":
|
||||
return LanguageAliases, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(uri, "file:///etc/wireguard/") || wireguardPattern.MatchString(uri) {
|
||||
return LanguageWireguard, nil
|
||||
}
|
||||
|
||||
if strings.HasSuffix(uri, ".ssh/config") {
|
||||
return LanguageSSHConfig, nil
|
||||
}
|
||||
|
||||
return "", undetectableError
|
||||
}
|
@ -1,40 +1,36 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
hosts "config-lsp/handlers/hosts/lsp"
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
utils "config-lsp/root-handler/utils"
|
||||
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentCodeAction(context *glsp.Context, params *protocol.CodeActionParams) (any, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, nil
|
||||
return utils.FetchAddLanguageActions(params.TextDocument.URI)
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentCodeAction(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return nil, nil
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentCodeAction(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentCodeAction(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentCodeAction(context, params)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
@ -7,36 +7,30 @@ import (
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentCompletion(context *glsp.Context, params *protocol.CompletionParams) (any, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentCompletion(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentCompletion(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentCompletion(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentCompletion(context, params)
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentCompletion(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentCompletion(context, params)
|
||||
}
|
||||
|
@ -1,39 +1,35 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/root-handler/utils"
|
||||
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentDefinition(context *glsp.Context, params *protocol.DefinitionParams) (any, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, utils.LanguageUndetectableError{}
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return nil, nil
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentDefinition(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentDefinition(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return nil, nil
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentDefinition(context, params)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
@ -7,27 +7,27 @@ import (
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentDidChange(context *glsp.Context, params *protocol.DidChangeTextDocumentParams) error {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
||||
newLanguage, err := initFile(
|
||||
context,
|
||||
content,
|
||||
params.TextDocument.URI,
|
||||
"",
|
||||
)
|
||||
content := params.ContentChanges[0].(protocol.TextDocumentContentChangeEventWhole).Text
|
||||
newLanguage, err := initFile(
|
||||
context,
|
||||
content,
|
||||
params.TextDocument.URI,
|
||||
"",
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if newLanguage != language {
|
||||
language = newLanguage
|
||||
|
||||
params := &protocol.DidOpenTextDocumentParams{
|
||||
@ -40,33 +40,33 @@ func TextDocumentDidChange(context *glsp.Context, params *protocol.DidChangeText
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentDidOpen(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentDidOpen(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentDidOpen(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentDidOpen(context, params)
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentDidOpen(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentDidOpen(context, params)
|
||||
}
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentDidChange(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentDidChange(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentDidChange(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentDidChange(context, params)
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentDidChange(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentDidChange(context, params)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
@ -7,39 +7,34 @@ import (
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentDidClose(context *glsp.Context, params *protocol.DidCloseTextDocumentParams) error {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return undetectableError.Err
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(openedFiles, params.TextDocument.URI)
|
||||
rootHandler.RemoveDocument(params.TextDocument.URI)
|
||||
delete(shared.OpenedFiles, params.TextDocument.URI)
|
||||
delete(shared.LanguagesOverwrites, params.TextDocument.URI)
|
||||
shared.Handler.RemoveDocument(params.TextDocument.URI)
|
||||
|
||||
switch *language {
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentDidClose(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentDidClose(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentDidClose(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentDidClose(context, params)
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentDidClose(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentDidClose(context, params)
|
||||
default:
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/root-handler/utils"
|
||||
"fmt"
|
||||
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
@ -32,60 +34,43 @@ func TextDocumentDidOpen(context *glsp.Context, params *protocol.DidOpenTextDocu
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentDidOpen(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentDidOpen(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentDidOpen(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentDidOpen(context, params)
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentDidOpen(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentDidOpen(context, params)
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("unexpected roothandler.SupportedLanguage: %#v", language))
|
||||
}
|
||||
|
||||
func showParseError(
|
||||
context *glsp.Context,
|
||||
uri protocol.DocumentUri,
|
||||
err common.ParseError,
|
||||
) {
|
||||
context.Notify(
|
||||
"window/showMessage",
|
||||
protocol.ShowMessageParams{
|
||||
Type: protocol.MessageTypeError,
|
||||
Message: err.Err.Error(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func initFile(
|
||||
context *glsp.Context,
|
||||
content string,
|
||||
uri protocol.DocumentUri,
|
||||
advertisedLanguage string,
|
||||
) (*SupportedLanguage, error) {
|
||||
language, err := DetectLanguage(content, advertisedLanguage, uri)
|
||||
) (*shared.SupportedLanguage, error) {
|
||||
language, err := utils.DetectLanguage(content, advertisedLanguage, uri)
|
||||
|
||||
if err != nil {
|
||||
parseError := err.(common.ParseError)
|
||||
showParseError(
|
||||
context,
|
||||
uri,
|
||||
parseError,
|
||||
)
|
||||
utils.NotifyLanguageUndetectable(context, uri)
|
||||
|
||||
return nil, parseError.Err
|
||||
return nil, utils.LanguageUndetectableError{}
|
||||
} else {
|
||||
utils.NotifyDetectedLanguage(context, uri, language)
|
||||
}
|
||||
|
||||
openedFiles[uri] = struct{}{}
|
||||
shared.OpenedFiles[uri] = struct{}{}
|
||||
|
||||
// Everything okay, now we can handle the file
|
||||
rootHandler.AddDocument(uri, language)
|
||||
shared.Handler.AddDocument(uri, language)
|
||||
|
||||
return &language, nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
@ -7,36 +7,30 @@ import (
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
wireguard "config-lsp/handlers/wireguard/lsp"
|
||||
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentHover(context *glsp.Context, params *protocol.HoverParams) (*protocol.Hover, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return hosts.TextDocumentHover(context, params)
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentHover(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentHover(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return fstab.TextDocumentHover(context, params)
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return wireguard.TextDocumentHover(context, params)
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentHover(context, params)
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/root-handler/utils"
|
||||
|
||||
"github.com/tliron/glsp"
|
||||
|
||||
@ -10,30 +12,24 @@ import (
|
||||
)
|
||||
|
||||
func TextDocumentPrepareRename(context *glsp.Context, params *protocol.PrepareRenameParams) (any, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, utils.LanguageUndetectableError{}
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return nil, nil
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return nil, nil
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentPrepareRename(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return nil, nil
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentPrepareRename(context, params)
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/root-handler/utils"
|
||||
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
@ -12,30 +14,24 @@ func TextDocumentRangeFormattingFunc(
|
||||
context *glsp.Context,
|
||||
params *protocol.DocumentRangeFormattingParams,
|
||||
) ([]protocol.TextEdit, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, utils.LanguageUndetectableError{}
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return nil, nil
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentRangeFormatting(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentRangeFormatting(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return nil, nil
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -1,38 +1,34 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/root-handler/utils"
|
||||
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentRename(context *glsp.Context, params *protocol.RenameParams) (*protocol.WorkspaceEdit, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, utils.LanguageUndetectableError{}
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return nil, nil
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return nil, nil
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentRename(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return nil, nil
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentRename(context, params)
|
||||
}
|
||||
|
@ -1,39 +1,33 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
||||
sshconfig "config-lsp/handlers/ssh_config/lsp"
|
||||
sshdconfig "config-lsp/handlers/sshd_config/lsp"
|
||||
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func TextDocumentSignatureHelp(context *glsp.Context, params *protocol.SignatureHelpParams) (*protocol.SignatureHelp, error) {
|
||||
language := rootHandler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
language := shared.Handler.GetLanguageForDocument(params.TextDocument.URI)
|
||||
|
||||
if language == nil {
|
||||
showParseError(
|
||||
context,
|
||||
params.TextDocument.URI,
|
||||
undetectableError,
|
||||
)
|
||||
|
||||
return nil, undetectableError.Err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch *language {
|
||||
case LanguageHosts:
|
||||
case shared.LanguageHosts:
|
||||
return nil, nil
|
||||
case LanguageSSHDConfig:
|
||||
case shared.LanguageSSHDConfig:
|
||||
return sshdconfig.TextDocumentSignatureHelp(context, params)
|
||||
case LanguageSSHConfig:
|
||||
case shared.LanguageSSHConfig:
|
||||
return sshconfig.TextDocumentSignatureHelp(context, params)
|
||||
case LanguageFstab:
|
||||
case shared.LanguageFstab:
|
||||
return nil, nil
|
||||
case LanguageWireguard:
|
||||
case shared.LanguageWireguard:
|
||||
return nil, nil
|
||||
case LanguageAliases:
|
||||
case shared.LanguageAliases:
|
||||
return aliases.TextDocumentSignatureHelp(context, params)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package roothandler
|
||||
package lsp
|
||||
|
||||
import (
|
||||
aliases "config-lsp/handlers/aliases/lsp"
|
@ -1,5 +0,0 @@
|
||||
package roothandler
|
||||
|
||||
import protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
|
||||
var openedFiles = make(map[protocol.DocumentUri]struct{})
|
21
server/root-handler/shared/constants.go
Normal file
21
server/root-handler/shared/constants.go
Normal file
@ -0,0 +1,21 @@
|
||||
package shared
|
||||
|
||||
type SupportedLanguage string
|
||||
|
||||
const (
|
||||
LanguageSSHConfig SupportedLanguage = "ssh_config"
|
||||
LanguageSSHDConfig SupportedLanguage = "sshd_config"
|
||||
LanguageFstab SupportedLanguage = "fstab"
|
||||
LanguageWireguard SupportedLanguage = "languagewireguard"
|
||||
LanguageHosts SupportedLanguage = "hosts"
|
||||
LanguageAliases SupportedLanguage = "aliases"
|
||||
)
|
||||
|
||||
var AllSupportedLanguages = []string{
|
||||
string(LanguageSSHConfig),
|
||||
string(LanguageSSHDConfig),
|
||||
string(LanguageFstab),
|
||||
string(LanguageWireguard),
|
||||
string(LanguageHosts),
|
||||
string(LanguageAliases),
|
||||
}
|
16
server/root-handler/shared/indexes.go
Normal file
16
server/root-handler/shared/indexes.go
Normal file
@ -0,0 +1,16 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
type LanguageOverwrite struct {
|
||||
Language SupportedLanguage
|
||||
|
||||
// The start of the overwrite
|
||||
Raw string
|
||||
Line uint32
|
||||
Character uint32
|
||||
}
|
||||
|
||||
var LanguagesOverwrites = map[protocol.DocumentUri]LanguageOverwrite{}
|
@ -1,10 +1,12 @@
|
||||
package roothandler
|
||||
package shared
|
||||
|
||||
import (
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
var rootHandler RootHandler
|
||||
var Handler RootHandler
|
||||
|
||||
var OpenedFiles = make(map[protocol.DocumentUri]struct{})
|
||||
|
||||
type RootHandler struct {
|
||||
languageMap map[protocol.DocumentUri]SupportedLanguage
|
44
server/root-handler/utils/code-actions.go
Normal file
44
server/root-handler/utils/code-actions.go
Normal file
@ -0,0 +1,44 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"config-lsp/root-handler/shared"
|
||||
"fmt"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
func FetchAddLanguageActions(uri protocol.DocumentUri) ([]protocol.CodeAction, error) {
|
||||
actions := make([]protocol.CodeAction, 0, len(shared.AllSupportedLanguages))
|
||||
|
||||
kind := protocol.CodeActionKindQuickFix
|
||||
isPreferred := true
|
||||
|
||||
for _, language := range shared.AllSupportedLanguages {
|
||||
actions = append(actions, protocol.CodeAction{
|
||||
Title: fmt.Sprintf("Use %s for this file", language),
|
||||
Kind: &kind,
|
||||
IsPreferred: &isPreferred,
|
||||
Edit: &protocol.WorkspaceEdit{
|
||||
Changes: map[protocol.DocumentUri][]protocol.TextEdit{
|
||||
uri: {
|
||||
{
|
||||
Range: protocol.Range{
|
||||
Start: protocol.Position{
|
||||
Line: 0,
|
||||
Character: 0,
|
||||
},
|
||||
End: protocol.Position{
|
||||
Line: 0,
|
||||
Character: 0,
|
||||
},
|
||||
},
|
||||
NewText: fmt.Sprintf("#?lsp.language=%s\n", language),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return actions, nil
|
||||
}
|
158
server/root-handler/utils/language-detection.go
Normal file
158
server/root-handler/utils/language-detection.go
Normal file
@ -0,0 +1,158 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/root-handler/shared"
|
||||
"config-lsp/utils"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
type UnsupportedLanguageError struct {
|
||||
SuggestedLanguage string
|
||||
}
|
||||
|
||||
func (e UnsupportedLanguageError) Error() string {
|
||||
return fmt.Sprintf("Language '%s' is not supported. Choose one of: %s", e.SuggestedLanguage, strings.Join(shared.AllSupportedLanguages, ", "))
|
||||
}
|
||||
|
||||
type LanguageUndetectableError struct{}
|
||||
|
||||
func (e LanguageUndetectableError) Error() string {
|
||||
return "Please add: '#?lsp.language=<language>' to the top of the file. config-lsp was unable to detect the appropriate language for this file."
|
||||
}
|
||||
|
||||
var valueToLanguageMap = map[string]shared.SupportedLanguage{
|
||||
"sshd_config": shared.LanguageSSHDConfig,
|
||||
"sshdconfig": shared.LanguageSSHDConfig,
|
||||
|
||||
"ssh_config": shared.LanguageSSHConfig,
|
||||
"sshconfig": shared.LanguageSSHConfig,
|
||||
|
||||
".ssh/config": shared.LanguageSSHConfig,
|
||||
"~/.ssh/config": shared.LanguageSSHConfig,
|
||||
|
||||
"fstab": shared.LanguageFstab,
|
||||
"etc/fstab": shared.LanguageFstab,
|
||||
|
||||
"wireguard": shared.LanguageWireguard,
|
||||
"wg": shared.LanguageWireguard,
|
||||
"languagewireguard": shared.LanguageWireguard,
|
||||
"host": shared.LanguageHosts,
|
||||
"hosts": shared.LanguageHosts,
|
||||
"etc/hosts": shared.LanguageHosts,
|
||||
|
||||
"aliases": shared.LanguageAliases,
|
||||
"mailaliases": shared.LanguageAliases,
|
||||
"etc/aliases": shared.LanguageAliases,
|
||||
}
|
||||
|
||||
var filenameToLanguageMap = map[string]shared.SupportedLanguage{
|
||||
"sshd_config": shared.LanguageSSHDConfig,
|
||||
"sshdconfig": shared.LanguageSSHDConfig,
|
||||
"sshd": shared.LanguageSSHDConfig,
|
||||
"sshd_conf": shared.LanguageSSHDConfig,
|
||||
"sshdconf": shared.LanguageSSHDConfig,
|
||||
|
||||
"ssh_config": shared.LanguageSSHConfig,
|
||||
"sshconfig": shared.LanguageSSHConfig,
|
||||
"ssh": shared.LanguageSSHConfig,
|
||||
"ssh_conf": shared.LanguageSSHConfig,
|
||||
"sshconf": shared.LanguageSSHConfig,
|
||||
|
||||
"fstab": shared.LanguageFstab,
|
||||
|
||||
"hosts": shared.LanguageHosts,
|
||||
|
||||
"aliases": shared.LanguageAliases,
|
||||
"mailaliases": shared.LanguageAliases,
|
||||
}
|
||||
|
||||
var typeOverwriteRegex = regexp.MustCompile(`#\?\s*lsp\.language\s*=\s*(\w+)\s*`)
|
||||
var wireguardPattern = regexp.MustCompile(`wg(\d+)?(\.conf)?$`)
|
||||
|
||||
var undetectableError = common.ParseError{
|
||||
Line: 0,
|
||||
Err: LanguageUndetectableError{},
|
||||
}
|
||||
|
||||
func DetectLanguage(
|
||||
content string,
|
||||
advertisedLanguage string,
|
||||
uri protocol.DocumentUri,
|
||||
) (shared.SupportedLanguage, error) {
|
||||
if match := typeOverwriteRegex.FindStringSubmatchIndex(content); match != nil {
|
||||
text := content[match[0]:match[1]]
|
||||
language := content[match[2]:match[3]]
|
||||
suggestedLanguage := strings.ToLower(language)
|
||||
|
||||
foundLanguage, ok := valueToLanguageMap[suggestedLanguage]
|
||||
|
||||
contentUntilMatch := content[:match[0]]
|
||||
|
||||
if ok {
|
||||
line := uint32(utils.CountCharacterOccurrences(contentUntilMatch, '\n'))
|
||||
shared.LanguagesOverwrites[uri] = shared.LanguageOverwrite{
|
||||
Language: foundLanguage,
|
||||
Raw: text,
|
||||
Line: line,
|
||||
Character: uint32(match[0]),
|
||||
}
|
||||
|
||||
return foundLanguage, nil
|
||||
}
|
||||
|
||||
return "", common.ParseError{
|
||||
Line: uint32(utils.CountCharacterOccurrences(contentUntilMatch, '\n')),
|
||||
Err: UnsupportedLanguageError{
|
||||
SuggestedLanguage: suggestedLanguage,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if language, ok := valueToLanguageMap[advertisedLanguage]; ok {
|
||||
return language, nil
|
||||
}
|
||||
|
||||
switch uri {
|
||||
case "file:///etc/ssh/sshd_config":
|
||||
fallthrough
|
||||
case "file:///etc/ssh/ssh_config":
|
||||
return shared.LanguageSSHDConfig, nil
|
||||
|
||||
case "file:///etc/fstab":
|
||||
return shared.LanguageFstab, nil
|
||||
|
||||
// Darwin
|
||||
case "file:///private/etc/hosts":
|
||||
fallthrough
|
||||
case "file:///etc/hosts":
|
||||
return shared.LanguageHosts, nil
|
||||
|
||||
// Darwin
|
||||
case "file:///private/etc/aliases":
|
||||
fallthrough
|
||||
case "file:///etc/aliases":
|
||||
return shared.LanguageAliases, nil
|
||||
}
|
||||
|
||||
filename := path.Base(string(uri))
|
||||
|
||||
if language, found := filenameToLanguageMap[filename]; found {
|
||||
return language, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(uri, "file:///etc/wireguard/") || wireguardPattern.MatchString(uri) {
|
||||
return shared.LanguageWireguard, nil
|
||||
}
|
||||
|
||||
if strings.HasSuffix(uri, ".ssh/config") {
|
||||
return shared.LanguageSSHConfig, nil
|
||||
}
|
||||
|
||||
return "", undetectableError
|
||||
}
|
46
server/root-handler/utils/notification.go
Normal file
46
server/root-handler/utils/notification.go
Normal file
@ -0,0 +1,46 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"config-lsp/root-handler/shared"
|
||||
"github.com/tliron/glsp"
|
||||
protocol "github.com/tliron/glsp/protocol_3_16"
|
||||
)
|
||||
|
||||
type lspNotification struct {
|
||||
Uri string
|
||||
}
|
||||
|
||||
type lspDetectedLanguage struct {
|
||||
lspNotification
|
||||
|
||||
Language string
|
||||
}
|
||||
|
||||
func NotifyLanguageUndetectable(context *glsp.Context, uri protocol.DocumentUri) {
|
||||
go context.Notify(
|
||||
"$/config-lsp/languageUndetectable",
|
||||
lspNotification{
|
||||
Uri: string(uri),
|
||||
},
|
||||
)
|
||||
|
||||
go context.Notify(
|
||||
"window/showMessage",
|
||||
protocol.ShowMessageParams{
|
||||
Type: protocol.MessageTypeError,
|
||||
Message: "config-lsp was unable to detect the appropriate language for this file. Please add: '#?lsp.language=<language>'.",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func NotifyDetectedLanguage(context *glsp.Context, uri protocol.DocumentUri, language shared.SupportedLanguage) {
|
||||
go context.Notify(
|
||||
"$/config-lsp/detectedLanguage",
|
||||
lspDetectedLanguage{
|
||||
lspNotification: lspNotification{
|
||||
Uri: string(uri),
|
||||
},
|
||||
Language: string(language),
|
||||
},
|
||||
)
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"name": "config-lsp",
|
||||
"description": "Language Features (completions, diagnostics, etc.) for your config files: gitconfig, fstab, aliases, hosts, wireguard, ssh_config, sshd_config, and more to come!",
|
||||
"author": "Myzel394",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Myzel394/config-lsp"
|
||||
@ -13,6 +13,62 @@
|
||||
"Formatters"
|
||||
],
|
||||
"preview": true,
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "sshconfig",
|
||||
"extensions": ["sshconfig", "ssh_config"],
|
||||
"aliases": ["SSH Config", "sshconfig"],
|
||||
"filenames": ["sshconfig", "ssh_config"],
|
||||
"filenamePatterns": ["~/.ssh/config", "**/sshconfig", "**/ssh_config"]
|
||||
},
|
||||
{
|
||||
"id": "sshdconfig",
|
||||
"extensions": ["sshdconfig", "sshd_config"],
|
||||
"aliases": ["SSH Daemon Config", "sshdconfig"],
|
||||
"filenames": ["sshdconfig", "sshd_config"],
|
||||
"filenamePatterns": ["/etc/ssh/sshd_config", "**/sshdconfig", "**/sshd_config"]
|
||||
},
|
||||
{
|
||||
"id": "aliases",
|
||||
"extensions": ["aliases", "mailaliases"],
|
||||
"aliases": ["Mail Aliases", "aliases", "mailaliases"],
|
||||
"filenames": ["aliases", "mailaliases"],
|
||||
"filenamePatterns": ["/etc/aliases", "**/aliases", "**/mailaliases"]
|
||||
},
|
||||
{
|
||||
"id": "fstab",
|
||||
"extensions": ["fstab"],
|
||||
"aliases": ["fstab"],
|
||||
"filenames": ["fstab"],
|
||||
"filenamePatterns": ["/etc/fstab", "**/fstab", "**/etc/fstab"]
|
||||
},
|
||||
{
|
||||
"id": "hosts",
|
||||
"extensions": ["hosts"],
|
||||
"aliases": ["hosts"],
|
||||
"filenames": ["hosts"],
|
||||
"filenamePatterns": ["/etc/hosts", "**/hosts", "**/etc/hosts"]
|
||||
},
|
||||
{
|
||||
"id": "wireguard",
|
||||
"extensions": ["wireguard", "wg"],
|
||||
"aliases": ["WireGuard", "wireguard", "wg"],
|
||||
"filenames": ["wireguard", "wg0.conf", "wg1.conf", "wg0", "wg1"],
|
||||
"filenamePatterns": ["/etc/wireguard/*.conf", "**/wireguard", "**/wireguard.conf"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:plaintext",
|
||||
"onLanguage:yaml",
|
||||
"onLanguage:sshconfig",
|
||||
"onLanguage:sshdconfig",
|
||||
"onLanguage:aliases",
|
||||
"onLanguage:fstab",
|
||||
"onLanguage:hosts",
|
||||
"onLanguage:wireguard"
|
||||
],
|
||||
"sponsor": {
|
||||
"url": "https://github.com/Myzel394/contact-me"
|
||||
},
|
||||
@ -50,16 +106,12 @@
|
||||
"engines": {
|
||||
"vscode": "^1.74.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:plaintext",
|
||||
"onLanguage:yaml"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"scripts": {
|
||||
"compile": "node esbuild.js",
|
||||
"compile:prod": "node esbuild.js --production",
|
||||
"watch": "tsc -b -w",
|
||||
"lint": "eslint ./src --ext .ts,.tsx"
|
||||
"lint": "eslint ./src"
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^9.0.1",
|
||||
|
34
vs-code-extension/src/events/on-undetectable.ts
Normal file
34
vs-code-extension/src/events/on-undetectable.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { GenericNotificationHandler } from "vscode-languageclient";
|
||||
import * as vscode from "vscode";
|
||||
|
||||
const ACTION_SELECT_LANGUAGE = "Select Language";
|
||||
const ACTION_DISABLE = "Ignore for this file";
|
||||
|
||||
const ignoredFiled = new Set<string>();
|
||||
|
||||
export const onUndetectable: GenericNotificationHandler = async (params: LSPLanguageUndetectable) => {
|
||||
if (ignoredFiled.has(params.Uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await vscode.window.showWarningMessage(
|
||||
"config-lsp was unable to detect the appropriate language for this file",
|
||||
{
|
||||
detail: "Either select a language or add '#?lsp.language=<language>' to the top of the file",
|
||||
},
|
||||
ACTION_SELECT_LANGUAGE,
|
||||
ACTION_DISABLE,
|
||||
)
|
||||
|
||||
switch (result) {
|
||||
case ACTION_SELECT_LANGUAGE:
|
||||
vscode.commands.executeCommand("workbench.action.editor.changeLanguageMode");
|
||||
break;
|
||||
case ACTION_DISABLE:
|
||||
ignoredFiled.add(params.Uri);
|
||||
break;
|
||||
undefined:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
6
vs-code-extension/src/events/types.ts
Normal file
6
vs-code-extension/src/events/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
interface LSPNotification {
|
||||
Uri: string;
|
||||
}
|
||||
|
||||
interface LSPLanguageUndetectable extends LSPNotification {}
|
||||
|
@ -1,32 +1,30 @@
|
||||
import * as path from "path"
|
||||
import { ExtensionContext, workspace } from 'vscode';
|
||||
import * as path from "path";
|
||||
import { ExtensionContext, workspace } from "vscode";
|
||||
|
||||
import {
|
||||
Executable,
|
||||
LanguageClient,
|
||||
type LanguageClientOptions,
|
||||
type ServerOptions,
|
||||
} from 'vscode-languageclient/node';
|
||||
} from "vscode-languageclient/node";
|
||||
import { onUndetectable } from "./events/on-undetectable";
|
||||
|
||||
const IS_DEBUG = process.env.VSCODE_DEBUG_MODE === 'true' || process.env.NODE_ENV === 'development';
|
||||
const IS_DEBUG =
|
||||
process.env.VSCODE_DEBUG_MODE === "true" ||
|
||||
process.env.NODE_ENV === "development";
|
||||
let client: LanguageClient;
|
||||
|
||||
export function activate(context: ExtensionContext) {
|
||||
export async function activate({subscriptions}: ExtensionContext) {
|
||||
console.info("config-lsp activated");
|
||||
const initOptions = workspace.getConfiguration('config-lsp');
|
||||
const initOptions = workspace.getConfiguration("config-lsp");
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [
|
||||
{
|
||||
scheme: 'file',
|
||||
language: 'plaintext',
|
||||
pattern: "**/{config,sshconfig,sshd_config,sshdconfig,fstab,hosts,aliases}",
|
||||
},
|
||||
// Some configs seem to be incorrectly detected as yaml
|
||||
{
|
||||
scheme: 'file',
|
||||
language: 'yaml',
|
||||
pattern: "**/{config,sshconfig,sshd_config,sshdconfig,fstab,hosts,aliases}",
|
||||
},
|
||||
{language: "sshconfig"},
|
||||
{language: "sshdconfig"},
|
||||
{language: "aliases"},
|
||||
{language: "fstab"},
|
||||
{language: "hosts"},
|
||||
{language: "wireguard"},
|
||||
],
|
||||
initializationOptions: initOptions,
|
||||
};
|
||||
@ -34,39 +32,29 @@ export function activate(context: ExtensionContext) {
|
||||
const path = getBundledPath();
|
||||
console.info(`Found config-lsp path at ${path}`);
|
||||
const run: Executable = {
|
||||
command: getBundledPath(),
|
||||
}
|
||||
command: getBundledPath() ,
|
||||
};
|
||||
const serverOptions: ServerOptions = {
|
||||
run,
|
||||
debug: run,
|
||||
}
|
||||
};
|
||||
|
||||
client = new LanguageClient(
|
||||
'config-lsp',
|
||||
"config-lsp",
|
||||
serverOptions,
|
||||
clientOptions,
|
||||
IS_DEBUG,
|
||||
IS_DEBUG
|
||||
);
|
||||
|
||||
console.info("Starting config-lsp...");
|
||||
await client.start();
|
||||
console.info("Started config-lsp");
|
||||
|
||||
client.start();
|
||||
console.info("config-lsp started");
|
||||
|
||||
// const serverOptions: ServerOptions = {
|
||||
// }
|
||||
//
|
||||
// // Create the language client and start the client.
|
||||
// client = new LanguageClient(
|
||||
// 'languageServerExample',
|
||||
// clientOptions
|
||||
// );
|
||||
//
|
||||
// // Start the client. This will also launch the server
|
||||
// client.start();
|
||||
subscriptions.push(client.onNotification("$/config-lsp/languageUndetectable", onUndetectable))
|
||||
}
|
||||
|
||||
function getBundledPath(): string {
|
||||
const filePath = path.resolve(__dirname, "config-lsp")
|
||||
const filePath = path.resolve(__dirname, "config-lsp");
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user