Skip to content

Commit

Permalink
add folding provider
Browse files Browse the repository at this point in the history
  • Loading branch information
jozsefsallai committed Dec 9, 2020
1 parent 8b7fd98 commit 118bdcd
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 14 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## v0.1.3 - 2020-12-09

### Added
- Event folding

### Fixed
- Fixed bug where a completion request won't throw an error even if it found one

## v0.1.2 - 2020-11-28

### Fixed
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ stdio.
Please note that this language server is currently not 100% stable, so bugs may
appear here and there.

## Features

- Hover information
- Diagnostics
- Event duplication checking
- Command usage validation
- Message box text overflow checking
- Completions
- Event folding

## Getting Started

Language clients should usually install the language server for you
Expand Down
2 changes: 1 addition & 1 deletion langserver/handlers/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TextDocumentCompletion(ctx context.Context, _ *jrpc2.Request) ([]lsp.Comple
conf, err := lsctx.Config(ctx)

if err != nil {
return []lsp.CompletionItem{}, nil
return []lsp.CompletionItem{}, err
}

completions := tsc.GetCompletions(conf)
Expand Down
52 changes: 52 additions & 0 deletions langserver/handlers/folding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package handlers

import (
"context"

"github.com/creachadair/jrpc2"
"github.com/sourcegraph/go-lsp"
lsctx "pkg.nimblebun.works/tsc-language-server/langserver/context"
"pkg.nimblebun.works/tsc-language-server/langserver/filesystem/filehandler"
"pkg.nimblebun.works/tsc-language-server/tsc"
)

// FoldingRangeParams is a (loosely reproduced) structure that contains the
// fields sent on a textDocument/foldingRange request.
type FoldingRangeParams struct {
TextDocument lsp.TextDocumentIdentifier `json:"textDocument"`
}

// TextDocumentFoldingRange is the callback that runs on the
// "textDocument/foldingRange" method.
func (mh *MethodHandler) TextDocumentFoldingRange(ctx context.Context, req *jrpc2.Request) ([]tsc.FoldingRange, error) {
var params FoldingRangeParams
err := req.UnmarshalParams(jrpc2.NonStrict(&params))
if err != nil {
return []tsc.FoldingRange{}, err
}

fs, err := lsctx.FileSystem(ctx)
if err != nil {
return []tsc.FoldingRange{}, err
}

handler := filehandler.FromDocumentURI(params.TextDocument.URI)
path, err := handler.FullPath()
if err != nil {
return []tsc.FoldingRange{}, err
}

contents, err := fs.ReadFile(path)
if err != nil {
return []tsc.FoldingRange{}, err
}

doc := lsp.TextDocumentItem{
URI: params.TextDocument.URI,
LanguageID: "tsc",
Text: string(contents),
}

ranges := tsc.GetFoldingRanges(doc)
return ranges, nil
}
47 changes: 43 additions & 4 deletions langserver/handlers/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,48 @@ import (
"github.com/sourcegraph/go-lsp"
)

// ServerCapabilities is a temporary workaround for the missing folding range
// provider field in Sourcegraph's go-lsp package. We will work on an in-house
// version of the LSP implementation in Go in the future.
type ServerCapabilities struct {
TextDocumentSync *lsp.TextDocumentSyncOptionsOrKind `json:"textDocumentSync,omitempty"`
HoverProvider bool `json:"hoverProvider,omitempty"`
FoldingRangeProvider bool `json:"foldingRangeProvider,omitempty"`
CompletionProvider *lsp.CompletionOptions `json:"completionProvider,omitempty"`
SignatureHelpProvider *lsp.SignatureHelpOptions `json:"signatureHelpProvider,omitempty"`
DefinitionProvider bool `json:"definitionProvider,omitempty"`
TypeDefinitionProvider bool `json:"typeDefinitionProvider,omitempty"`
ReferencesProvider bool `json:"referencesProvider,omitempty"`
DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"`
DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"`
WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"`
ImplementationProvider bool `json:"implementationProvider,omitempty"`
CodeActionProvider bool `json:"codeActionProvider,omitempty"`
CodeLensProvider *lsp.CodeLensOptions `json:"codeLensProvider,omitempty"`
DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"`
DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"`
DocumentOnTypeFormattingProvider *lsp.DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"`
RenameProvider bool `json:"renameProvider,omitempty"`
ExecuteCommandProvider *lsp.ExecuteCommandOptions `json:"executeCommandProvider,omitempty"`
SemanticHighlighting *lsp.SemanticHighlightingOptions `json:"semanticHighlighting,omitempty"`
XWorkspaceReferencesProvider bool `json:"xworkspaceReferencesProvider,omitempty"`
XDefinitionProvider bool `json:"xdefinitionProvider,omitempty"`
XWorkspaceSymbolByProperties bool `json:"xworkspaceSymbolByProperties,omitempty"`

Experimental interface{} `json:"experimental,omitempty"`
}

// InitializeResult is a temporary workaround for the missing folding range
// provider field in Sourcegraph's go-lsp package. We will work on an in-house
// version of the LSP implementation in Go in the future.
type InitializeResult struct {
Capabilities ServerCapabilities `json:"capabilities"`
}

// Initialize is the callback that runs on the "initialize" method
func (mh *MethodHandler) Initialize(ctx context.Context, _ *jrpc2.Request) (lsp.InitializeResult, error) {
result := lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
func (mh *MethodHandler) Initialize(ctx context.Context, _ *jrpc2.Request) (InitializeResult, error) {
result := InitializeResult{
Capabilities: ServerCapabilities{
TextDocumentSync: &lsp.TextDocumentSyncOptionsOrKind{
Options: &lsp.TextDocumentSyncOptions{
OpenClose: true,
Expand All @@ -20,7 +58,8 @@ func (mh *MethodHandler) Initialize(ctx context.Context, _ *jrpc2.Request) (lsp.
CompletionProvider: &lsp.CompletionOptions{
ResolveProvider: false,
},
HoverProvider: true,
HoverProvider: true,
FoldingRangeProvider: true,
},
}

Expand Down
11 changes: 11 additions & 0 deletions langserver/handlers/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@ func (service *Service) Assigner() (jrpc2.Assigner, error) {
return handle(ctx, req, mh.TextDocumentHover)
},

"textDocument/foldingRange": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := sess.EnsureInitialized()
if err != nil {
return nil, err
}

ctx = lsctx.WithFileSystem(ctx, fs)

return handle(ctx, req, mh.TextDocumentFoldingRange)
},

"tsc/setConfig": func(ctx context.Context, req *jrpc2.Request) (interface{}, error) {
err := sess.EnsureInitialized()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
app := cli.NewApp()
app.Name = "tsc-ls"
app.Usage = "language Server for the TSC scripting language"
app.Version = "0.1.2"
app.Version = "0.1.3"

app.Commands = []*cli.Command{
{
Expand Down
5 changes: 3 additions & 2 deletions tsc/completions_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package tsc
package tsc_test

import (
"testing"

"github.com/sourcegraph/go-lsp"
"pkg.nimblebun.works/tsc-language-server/config"
"pkg.nimblebun.works/tsc-language-server/tsc"
)

func TestGetCompletions(t *testing.T) {
conf := config.New()
completions := GetCompletions(&conf)
completions := tsc.GetCompletions(&conf)

definitionsLength := len(conf.GetTSCDefinitions())
completionsLength := len(completions)
Expand Down
76 changes: 76 additions & 0 deletions tsc/folding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package tsc

import (
"github.com/sourcegraph/go-lsp"
"pkg.nimblebun.works/tsc-language-server/langserver/textdocument"
"pkg.nimblebun.works/tsc-language-server/utils"
)

const (
// FRKComment resolves to the "comment" folding range kind.
FRKComment = "comment"

// FRKImports resolves to the "imports" folding range kind.
FRKImports = "imports"

// FRKRegion resolves to the "region" folding range kind.
FRKRegion = "region"
)

// FoldingRange defines a LSP-compatible folding range.
type FoldingRange struct {
StartLine int `json:"startLine"`
StartCharacter int `json:"startCharacter,omitempty"`
EndLine int `json:"endLine"`
EndCharacter int `json:"endCharacter"`

Kind string `json:"kind,omitempty"`
}

func createFoldingRange(start int, end int, document textdocument.TextDocument) FoldingRange {
startPos := document.PositionAt(start)
endPos := document.PositionAt(end)

return FoldingRange{
StartLine: startPos.Line,
StartCharacter: startPos.Character,

EndLine: endPos.Line,
EndCharacter: endPos.Character,

Kind: FRKRegion,
}
}

// GetFoldingRanges will return all foldable ranges from a given document.
func GetFoldingRanges(textDocumentItem lsp.TextDocumentItem) []FoldingRange {
text := textDocumentItem.Text

document := textdocument.From(textDocumentItem)
ranges := make([]FoldingRange, 0)

start := -1
end := -1

for idx, letter := range text {
if letter == '#' && IsEvent(utils.Substring(text, idx, 5)) {
if end-start > 4 {
foldingRange := createFoldingRange(start, end, document)
ranges = append(ranges, foldingRange)
}

start = idx
}

if letter != '\n' && letter != '\r' {
end = idx
}
}

if end-start > 4 {
foldingRange := createFoldingRange(start, end, document)
ranges = append(ranges, foldingRange)
}

return ranges
}
107 changes: 107 additions & 0 deletions tsc/folding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package tsc_test

import (
"testing"

"github.com/sourcegraph/go-lsp"
"pkg.nimblebun.works/tsc-language-server/tsc"
)

func TestGetFoldingRanges(t *testing.T) {
dummyData := `#0098
<CNP0306:0117:0000<ANP0306:0032:0002<END

#0100
<KEY<FLJ0839:0101
<SOU0011<ANP0100:0000:0002
<FAO0000<TRA0046:0090:0017:0009

#0101
<KEY<MSGIt won't open...<NOD<END

#0200
<KEY
<FLJ0832:0204
<FLJ0824:0203
<FLJ0823:0202
<FLJ0821:0201<MSG
OPEN SHUTTER?<YNJ0000<CLR
OPENING SHUTTER<NOD<CLO<MYD0000
<WAI0030<ANP0250:0010:0001<WAI0010<ANP0300:0001:0002
<WAI0022<ANP0251:0010:0001<ANP0300:0003:0002
<WAI0032<ANP0252:0010:0001
<WAI0032<ANP0253:0010:0001
<WAI0032<ANP0254:0010:0001<DNP0250
<WAI0032<DNP0251
<WAI0032<DNP0252
<ANP0253:0001:0000<WAI0032<DNP0300
<CNP0301:0117:0000
<ANP0301:0021:0002
<FL-0820<FL+0821<FL+0822<MSGABNORMALITY DETECTED IN
SHUTTER NO. 4<NOD<END`

dummyDocument := lsp.TextDocumentItem{
Text: dummyData,
}

t.Run("should return correct number of folding ranges", func(t *testing.T) {
ranges := tsc.GetFoldingRanges(dummyDocument)
actual := len(ranges)
expected := 4

if expected != actual {
t.Errorf("GetFoldingRanges(document) length, got %d, want %d", actual, expected)
}
})

t.Run("should return correct ranges", func(t *testing.T) {
ranges := tsc.GetFoldingRanges(dummyDocument)
expectedRanges := []tsc.FoldingRange{
{
StartLine: 0,
StartCharacter: 0,
EndLine: 1,
EndCharacter: 39,
},
{
StartLine: 3,
StartCharacter: 0,
EndLine: 6,
EndCharacter: 30,
},
{
StartLine: 8,
StartCharacter: 0,
EndLine: 9,
EndCharacter: 31,
},
{
StartLine: 11,
StartCharacter: 0,
EndLine: 30,
EndCharacter: 20,
},
}

for idx := range ranges {
actual := ranges[idx]
expected := expectedRanges[idx]

if actual.StartLine != expected.StartLine {
t.Errorf("GetFoldingRanges(doc) @ %d -> StartLine, got %v, want %v", idx, actual.StartLine, expected.StartLine)
}

if actual.StartCharacter != expected.StartCharacter {
t.Errorf("GetFoldingRanges(doc) @ %d -> StartCharacter, got %v, want %v", idx, actual.StartCharacter, expected.StartCharacter)
}

if actual.EndLine != expected.EndLine {
t.Errorf("GetFoldingRanges(doc) @ %d -> EndLine, got %v, want %v", idx, actual.EndLine, expected.EndLine)
}

if actual.EndCharacter != expected.EndCharacter {
t.Errorf("GetFoldingRanges(doc) @ %d -> EndCharacter, got %v, want %v", idx, actual.EndCharacter, expected.EndCharacter)
}
}
})
}
Loading

0 comments on commit 118bdcd

Please sign in to comment.