Skip to content

Commit

Permalink
Optimize didChange for single files
Browse files Browse the repository at this point in the history
- detect if file has already been parsed and rpc request is for didChange
- only process changed file if above is true
  • Loading branch information
jpogran committed Sep 13, 2023
1 parent e22a021 commit 01cad71
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 4 deletions.
4 changes: 4 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,7 @@ func WithRPCContext(ctx context.Context, rpcc RPCContextData) context.Context {
func RPCContext(ctx context.Context) RPCContextData {
return ctx.Value(ctxRPCContext).(RPCContextData)
}

func (ctxData RPCContextData) IsDidChangeRequest() bool{
return ctxData.Method == "textDocument/didChange"
}
2 changes: 2 additions & 0 deletions internal/decoder/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

"github.com/hashicorp/hcl-lang/decoder"
"github.com/hashicorp/hcl-lang/lang"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
idecoder "github.com/hashicorp/terraform-ls/internal/decoder"
"github.com/hashicorp/terraform-ls/internal/state"
"github.com/hashicorp/terraform-ls/internal/terraform/module"
Expand Down Expand Up @@ -60,6 +61,7 @@ func TestDecoder_CodeLensesForFile_concurrencyBug(t *testing.T) {
if err != nil {
t.Error(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = module.ParseModuleConfiguration(ctx, mapFs, ss.Modules, dirName)
if err != nil {
t.Error(err)
Expand Down
24 changes: 20 additions & 4 deletions internal/terraform/module/module_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ import (
"github.com/hashicorp/hcl-lang/decoder"
"github.com/hashicorp/hcl-lang/lang"
tfjson "github.com/hashicorp/terraform-json"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
idecoder "github.com/hashicorp/terraform-ls/internal/decoder"
"github.com/hashicorp/terraform-ls/internal/document"
"github.com/hashicorp/terraform-ls/internal/job"
ilsp "github.com/hashicorp/terraform-ls/internal/lsp"
"github.com/hashicorp/terraform-ls/internal/registry"
"github.com/hashicorp/terraform-ls/internal/schemas"
"github.com/hashicorp/terraform-ls/internal/state"
"github.com/hashicorp/terraform-ls/internal/terraform/ast"
"github.com/hashicorp/terraform-ls/internal/terraform/datadir"
op "github.com/hashicorp/terraform-ls/internal/terraform/module/operation"
"github.com/hashicorp/terraform-ls/internal/terraform/parser"
"github.com/hashicorp/terraform-ls/internal/uri"
tfaddr "github.com/hashicorp/terraform-registry-address"
"github.com/hashicorp/terraform-schema/earlydecoder"
"github.com/hashicorp/terraform-schema/module"
Expand Down Expand Up @@ -359,19 +362,32 @@ func ParseModuleConfiguration(ctx context.Context, fs ReadOnlyFS, modStore *stat

// TODO: Avoid parsing if the content matches existing AST

// TODO: Only parse the file that's being changed/opened, unless this is 1st-time parsing

// Avoid parsing if it is already in progress or already known
if mod.ModuleParsingState != op.OpStateUnknown && !job.IgnoreState(ctx) {
return job.StateNotChangedErr{Dir: document.DirHandleFromPath(modPath)}
}

err = modStore.SetModuleParsingState(modPath, op.OpStateLoading)
var files ast.ModFiles
var diags ast.ModDiags
rpcContext := lsctx.RPCContext(ctx)
// Only parse the file that's being changed/opened, unless this is 1st-time parsing
if mod.ModuleParsingState == op.OpStateLoaded && rpcContext.IsDidChangeRequest() {
// the file has already been parsed, so only examine this file and not the whole module
fileName, _ := uri.PathFromURI(rpcContext.URI)
files, diags, err = parser.ParseModuleFile(fs, fileName)
} else {
// this is the first time file is opened so parse the whole module
files, diags, err = parser.ParseModuleFiles(fs, modPath)
}

if err != nil {
return err
}

files, diags, err := parser.ParseModuleFiles(fs, modPath)
err = modStore.SetModuleParsingState(modPath, op.OpStateLoading)
if err != nil {
return err
}

sErr := modStore.UpdateParsedModuleFiles(modPath, files, err)
if sErr != nil {
Expand Down
9 changes: 9 additions & 0 deletions internal/terraform/module/module_ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/hashicorp/go-version"
"github.com/hashicorp/hcl-lang/lang"
tfjson "github.com/hashicorp/terraform-json"
lsctx "github.com/hashicorp/terraform-ls/internal/context"
"github.com/hashicorp/terraform-ls/internal/document"
"github.com/hashicorp/terraform-ls/internal/filesystem"
"github.com/hashicorp/terraform-ls/internal/job"
Expand Down Expand Up @@ -56,6 +57,7 @@ func TestGetModuleDataFromRegistry_singleModule(t *testing.T) {
}

fs := filesystem.NewFilesystem(ss.DocumentStore)
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, fs, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -128,6 +130,7 @@ func TestGetModuleDataFromRegistry_moduleNotFound(t *testing.T) {
}

fs := filesystem.NewFilesystem(ss.DocumentStore)
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, fs, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -228,6 +231,7 @@ func TestGetModuleDataFromRegistry_apiTimeout(t *testing.T) {
}

fs := filesystem.NewFilesystem(ss.DocumentStore)
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, fs, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -522,6 +526,7 @@ func TestParseProviderVersions_multipleVersions(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, fs, ss.Modules, modPathFirst)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -691,6 +696,7 @@ func TestPreloadEmbeddedSchema_basic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, cfgFS, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -761,6 +767,7 @@ func TestPreloadEmbeddedSchema_unknownProviderOnly(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, cfgFS, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -824,6 +831,7 @@ func TestPreloadEmbeddedSchema_idempotency(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, cfgFS, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -903,6 +911,7 @@ func TestPreloadEmbeddedSchema_raceCondition(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ctx = lsctx.WithRPCContext(ctx, lsctx.RPCContextData{})
err = ParseModuleConfiguration(ctx, cfgFS, ss.Modules, modPath)
if err != nil {
t.Fatal(err)
Expand Down
23 changes: 23 additions & 0 deletions internal/terraform/parser/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,26 @@ func ParseModuleFiles(fs FS, modPath string) (ast.ModFiles, ast.ModDiags, error)

return files, diags, nil
}

func ParseModuleFile(fs FS, fileName string) (ast.ModFiles, ast.ModDiags, error) {
files := make(ast.ModFiles, 0)
diags := make(ast.ModDiags, 0)

src, err := fs.ReadFile(fileName)
if err != nil {
// If a file isn't accessible, return
return nil, nil, err
}

name := filepath.Base((fileName))
filename := ast.ModFilename(name)

f, pDiags := parseFile(src, filename)

diags[filename] = pDiags
if f != nil {
files[filename] = f
}

return files, diags, nil
}

0 comments on commit 01cad71

Please sign in to comment.