Skip to content

Commit 0b0e481

Browse files
committed
feat: Initial project setup
1 parent 540b7c2 commit 0b0e481

File tree

16 files changed

+694
-0
lines changed

16 files changed

+694
-0
lines changed

.github/dependabot.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# yaml-language-server: $schema=https://www.schemastore.org/dependabot-2.0.json
2+
version: 2
3+
updates:
4+
- package-ecosystem: gomod
5+
directory: /
6+
schedule:
7+
interval: monthly
8+
commit-message:
9+
prefix: chore
10+
include: scope
11+
- package-ecosystem: github-actions
12+
directory: /
13+
schedule:
14+
interval: monthly
15+
commit-message:
16+
prefix: chore
17+
include: scope

.github/workflows/ci.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json
2+
name: CI
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
jobs:
9+
build:
10+
name: Build
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
- name: Set up Go
16+
uses: actions/setup-go@v5
17+
with:
18+
go-version-file: go.mod
19+
- name: Build
20+
run: go build ./...
21+
test:
22+
name: Test
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
- name: Set up Go
28+
uses: actions/setup-go@v5
29+
with:
30+
go-version-file: go.mod
31+
- name: Run tests
32+
run: go test ./...
33+
lint:
34+
name: Lint
35+
runs-on: ubuntu-latest
36+
steps:
37+
- name: Checkout code
38+
uses: actions/checkout@v4
39+
- name: Set up Go
40+
uses: actions/setup-go@v5
41+
with:
42+
go-version-file: go.mod
43+
- name: Run linter
44+
uses: golangci/golangci-lint-action@v8
45+
with:
46+
version: v2.1

.golangci.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: '2'
2+
linters:
3+
settings:
4+
govet:
5+
disable:
6+
- structtag # participle uses nonconventional tags
7+
formatters:
8+
enable:
9+
- gofumpt
10+
settings:
11+
gofumpt:
12+
module-path: github.com/armsnyder/gdshader-language-server
13+
extra-rules: true

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Adam Snyder
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Godot Shader Language Server
2+
3+
![Go](https://img.shields.io/badge/Made%20with-Go-00ADD8?logo=go&logoColor=white)
4+
![License](https://img.shields.io/github/license/armsnyder/gdshader-language-server)
5+
6+
External editor support for `.gdshader` files.
7+
8+
> [!WARNING]
9+
> 🚧 Early Work in Progress
10+
>
11+
> This project is in its infancy and currently has no features. Feel free to ⭐
12+
> the repo to track progress and signal to me that there is interest!
13+
14+
Godot's shader language is powerful, but editing `.gdshader` files outside the
15+
Godot editor is painful. This project aims to bring proper language tooling
16+
(autocomplete, hover, references, etc.) to editors like Neovim and VSCode.
17+
18+
## 📦 Install
19+
20+
Install from source:
21+
22+
```shell
23+
go install github.com/armsnyder/gdshader-language-server@latest
24+
```
25+
26+
## ⚙️ Configure
27+
28+
### Neovim
29+
30+
Add the following to your `init.lua`, adjusting the path to the
31+
`gdshader-language-server` binary if necessary:
32+
33+
```lua
34+
vim.api.nvim_create_autocmd("FileType", {
35+
pattern = "gdshader",
36+
callback = function()
37+
vim.lsp.start({
38+
name = "gdshader",
39+
cmd = { vim.fs.expand('$HOME/go/bin/gdshader-language-server') },
40+
})
41+
end,
42+
})
43+
```
44+
45+
### VSCode
46+
47+
Coming soon? Contributions welcome!
48+
49+
## Roadmap
50+
51+
Planned features:
52+
53+
- [ ] Go to definition
54+
- [ ] Find references
55+
- [ ] Formatting
56+
- [ ] Hover (show documentation)
57+
- [ ] Signature help
58+
- [ ] VSCode wrapper extension
59+
60+
## 🤝 Contributing
61+
62+
I love to see issues and pull requests! Just note that this is a side project
63+
for me, and I cannot promise to respond quickly. I will generally accept pull
64+
requests which are relevant to the project goals, are tested, and follow
65+
existing code conventions.
66+
67+
### 📁 Code structure
68+
69+
```graphql
70+
.
71+
├── main.go # Entry point
72+
└── internal
73+
├── ast # .gdshader file parser library (application agnostic)
74+
├── handler # Main application logic
75+
└── lsp # LSP server library (application agnostic)
76+
```
77+
78+
## License
79+
80+
MIT

go.mod

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module github.com/armsnyder/gdshader-language-server
2+
3+
go 1.24.4
4+
5+
require (
6+
github.com/alecthomas/participle/v2 v2.1.4 // indirect
7+
github.com/google/go-cmp v0.7.0 // indirect
8+
github.com/onsi/gomega v1.37.0 // indirect
9+
github.com/samber/lo v1.51.0 // indirect
10+
golang.org/x/net v0.37.0 // indirect
11+
golang.org/x/text v0.23.0 // indirect
12+
gopkg.in/yaml.v3 v3.0.1 // indirect
13+
)

go.sum

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U=
2+
github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI=
3+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
4+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
5+
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
6+
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
7+
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
8+
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
9+
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
10+
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
11+
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
12+
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
13+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
14+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
15+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/ast/parser.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package ast
2+
3+
import (
4+
"io"
5+
6+
"github.com/alecthomas/participle/v2"
7+
)
8+
9+
var parser *participle.Parser[File]
10+
11+
func init() {
12+
parser = participle.MustBuild[File]()
13+
}
14+
15+
func Parse(filename string, reader io.Reader) (*File, error) {
16+
return parser.Parse(filename, reader, participle.AllowTrailing(true))
17+
}

internal/ast/parser_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package ast_test
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/alecthomas/participle/v2/lexer"
10+
"github.com/armsnyder/gdshader-language-server/internal/ast"
11+
"github.com/google/go-cmp/cmp"
12+
"github.com/samber/lo"
13+
14+
. "github.com/onsi/gomega"
15+
)
16+
17+
func TestParser(t *testing.T) {
18+
g := NewWithT(t)
19+
content := lo.Must(os.ReadFile("testdata/valid/shader.gdshader"))
20+
const filename = "shader.gdshader"
21+
shader, err := ast.Parse(filename, bytes.NewReader(content))
22+
g.Expect(err).ToNot(HaveOccurred())
23+
expected := &ast.File{
24+
Declarations: []*ast.Declaration{
25+
{
26+
UniformDecl: &ast.UniformDecl{
27+
Type: "sampler2D",
28+
Name: "texture",
29+
},
30+
},
31+
{
32+
FunctionDecl: &ast.FunctionDecl{
33+
ReturnType: "void",
34+
Name: "vertex",
35+
Body: &ast.BlockStmt{},
36+
},
37+
},
38+
{
39+
FunctionDecl: &ast.FunctionDecl{
40+
ReturnType: "void",
41+
Name: "fragment",
42+
Body: &ast.BlockStmt{},
43+
},
44+
},
45+
},
46+
}
47+
48+
g.Expect(shader).To(BeComparableTo(expected, IgnorePos))
49+
}
50+
51+
func TestCanParseAllValidPrograms(t *testing.T) {
52+
files := lo.Must(os.ReadDir("testdata/valid"))
53+
for _, file := range files {
54+
t.Run(file.Name(), func(t *testing.T) {
55+
content := lo.Must(os.ReadFile(filepath.Join("testdata/valid", file.Name())))
56+
_, err := ast.Parse(file.Name(), bytes.NewReader(content))
57+
NewWithT(t).Expect(err).ToNot(HaveOccurred())
58+
})
59+
}
60+
}
61+
62+
var IgnorePos = cmp.FilterValues(func(_, _ lexer.Position) bool { return true }, cmp.Ignore())
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
uniform sampler2D texture;
2+
3+
void vertex() {
4+
}
5+
6+
void fragment() {
7+
}

0 commit comments

Comments
 (0)