Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Test

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
name: Build
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.23

- name: Check formatting
run: make check-fmt

- name: Test
run: make
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
log.txt
main
Session.vim
10 changes: 7 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
# Release Notes

## v0.4.0 (2025-11-08)
- ✨ Loop directives like `@break`, `@continue`, `@breakIf`, `@continueIf` are now getting suggested only inside of loops.
- 🧑‍💻 Added testing GitHub Actions job to run tests.

## v0.3.1 (2025-06-14)
- 🐛 Update LSP textwire to the latest version which will fix `@break($1)` snippet to `@break`
- 🐛 Updated LSP textwire to the latest version which will fix `@break($1)` snippet to `@break`

## v0.3.0 (2025-06-14)
- 🐛 Update LSP textwire to the latest version which will fix crashing LSP when you make a syntax error in your Textwire code
- 🐛 Updated LSP textwire to the latest version which will fix crashing LSP when you make a syntax error in your Textwire code
- ✨ Autocomplete snippets that appear after you hit enter are now more complex. Instead of simple autocomple like `@if` you know get the full if statement and the cursor placed inside condition. It allows you to hit tab to move to the next place in a snippet

## v0.2.0 (2025-05-30)
- ✨ Add autocompletion for loop object. Now if you type `loop.` inside of a loop, it will show available properties on the object
- ✨ Added autocompletion for loop object. Now if you type `loop.` inside of a loop, it will show available properties on the object

## v0.1.4 (2025-05-17)
- ✨ Autocomplete suggestions show code example with syntax highlighting. Before, it was just displayed as text
Expand Down
6 changes: 3 additions & 3 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
FROM golang:1.24-alpine
FROM golang:1.25-alpine

WORKDIR /app

RUN apk add --no-cache make

COPY go.mod go.sum .
COPY go.* .

RUN go mod download

COPY . .

CMD ["sh"]
CMD ["sh"]
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
w.PHONY: test
.PHONY: test
test:
@echo "🚀 Running tests..."
go test ./...
Expand All @@ -8,4 +8,13 @@ test:
build:
go build main.go

.PHONE: check-fmt
check-fmt:
unformatted=$$(gofmt -l .); \
if [ -n "$$unformatted" ]; then \
echo "The following files are not formatted properly:"; \
echo "$$unformatted"; \
exit 1; \
fi

.DEFAULT_GOAL := test
63 changes: 52 additions & 11 deletions analysis/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package analysis

import (
"regexp"
"slices"
"strings"

"github.com/textwire/lsp/internal/logger"
Expand Down Expand Up @@ -35,18 +36,9 @@ func (s *State) Completion(id int, uri string, pos lsp.Position) (lsp.Completion
var err error

if directiveMatch != nil {
completionItems, err = completions.GetDirectives(locale)
completionItems, err = handleDirectivesAutocomplete(doc, pos, uri)
} else if strings.HasSuffix(textBeforeCursor, "loop.") {
doc = removeTrailingChar(doc, pos.Line, pos.Character, '.')

isInsideLoop, errors := twLsp.IsInLoop(doc, uri, pos.Line, pos.Character)
if len(errors) > 0 {
logger.Error.Println(errors[0])
}

if isInsideLoop {
completionItems, err = completions.GetLoopObjFields(locale)
}
completionItems, err = handleLoopObjectAutocomplete(doc, pos, uri)
}

if err != nil {
Expand All @@ -57,6 +49,55 @@ func (s *State) Completion(id int, uri string, pos lsp.Position) (lsp.Completion
return s.completionResponse(id, s.makeCompletions(completionItems)), nil
}

func handleDirectivesAutocomplete(doc string, pos lsp.Position, uri string) ([]completions.Completion, error) {
dirs, err := completions.GetDirectives(locale)
if err != nil {
return []completions.Completion{}, err
}

isInsideLoop, errors := twLsp.IsInLoop(doc, uri, pos.Line, pos.Character)
if len(errors) > 0 {
logger.Error.Println(errors[0])
}

if isInsideLoop {
return dirs, nil
}

filteredDirs := make([]completions.Completion, 0, len(dirs))
loopDirs := []string{"@break", "@breakIf", "@continue", "@continueIf"}

for _, dir := range dirs {
if slices.Contains(loopDirs, dir.Label) {
continue
}

filteredDirs = append(filteredDirs, dir)
}

return filteredDirs, nil
}

func handleLoopObjectAutocomplete(doc string, pos lsp.Position, uri string) ([]completions.Completion, error) {
doc = removeTrailingChar(doc, pos.Line, pos.Character, '.')

isInsideLoop, errors := twLsp.IsInLoop(doc, uri, pos.Line, pos.Character)
if len(errors) > 0 {
logger.Error.Println(errors[0])
}

if !isInsideLoop {
return []completions.Completion{}, nil
}

fields, err := completions.GetLoopObjFields(locale)
if err != nil {
return []completions.Completion{}, err
}

return fields, nil
}

func removeTrailingChar(doc string, line, col uint, char byte) string {
lines := strings.Split(doc, "\n")
if int(line) >= len(lines) {
Expand Down
2 changes: 1 addition & 1 deletion rpc/rpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestDecodeMessage(t *testing.T) {
expectMethod := "hi"
incomingMsg := fmt.Sprintf("Content-Length: %d\r\n\r\n{\"Method\":\"%s\"}", expectLen, expectMethod)

method, content, err := DecodeMessage([]byte(incomingMsg) )
method, content, err := DecodeMessage([]byte(incomingMsg))
if err != nil {
t.Fatal(err)
}
Expand Down
17 changes: 0 additions & 17 deletions textwire.tw

This file was deleted.