Skip to content

Commit

Permalink
Add support for ignored files in ls formatting (#845)
Browse files Browse the repository at this point in the history
Adding functionality to manage the contents of ignored files when
formatting documents.

Signed-off-by: Charlie Egan <[email protected]>
  • Loading branch information
charlieegan3 committed Jun 17, 2024
1 parent d8dda73 commit 8dd71c8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 5 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ rules:

### Ignoring Files Globally

**Note**: Ignoring files will disable most language server features
for those files. Only formatting will remain available.
Ignored files won't be used for completions, linting, or definitions
in other files.

If you want to ignore certain files for all rules, you can use the global ignore attribute in your configuration file:

```yaml
Expand Down
36 changes: 33 additions & 3 deletions internal/lsp/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ type Cache struct {
fileContents map[string]string
fileContentsMu sync.Mutex

// ignoredFileContents is a similar map of file URI to raw file contents
// but it's not queried for project level operations like goto definition,
// linting etc.
// ignoredFileContents is also cleared on the delete operation.
ignoredFileContents map[string]string
ignoredFileContentsMu sync.Mutex

// modules is a map of file URI to parsed AST modules from the latest file contents value
modules map[string]*ast.Module
moduleMu sync.Mutex
Expand Down Expand Up @@ -52,8 +59,10 @@ type Cache struct {

func NewCache() *Cache {
return &Cache{
fileContents: make(map[string]string),
modules: make(map[string]*ast.Module),
fileContents: make(map[string]string),
ignoredFileContents: make(map[string]string),

modules: make(map[string]*ast.Module),

diagnosticsFile: make(map[string][]types.Diagnostic),
diagnosticsAggregate: make(map[string][]types.Diagnostic),
Expand Down Expand Up @@ -111,6 +120,22 @@ func (c *Cache) SetFileContents(uri string, content string) {
c.fileContents[uri] = content
}

func (c *Cache) GetIgnoredFileContents(uri string) (string, bool) {
c.ignoredFileContentsMu.Lock()
defer c.ignoredFileContentsMu.Unlock()

val, ok := c.ignoredFileContents[uri]

return val, ok
}

func (c *Cache) SetIgnoredFileContents(uri string, content string) {
c.ignoredFileContentsMu.Lock()
defer c.ignoredFileContentsMu.Unlock()

c.ignoredFileContents[uri] = content
}

func (c *Cache) GetAllModules() map[string]*ast.Module {
c.moduleMu.Lock()
defer c.moduleMu.Unlock()
Expand Down Expand Up @@ -256,7 +281,8 @@ func (c *Cache) GetUsedRefs(uri string) ([]string, bool) {
return refs, ok
}

// Delete removes all cached data for a given URI.
// Delete removes all cached data for a given URI. Ignored file contents are
// also removed if found for a matching URI.
func (c *Cache) Delete(uri string) {
c.fileContentsMu.Lock()
delete(c.fileContents, uri)
Expand Down Expand Up @@ -289,6 +315,10 @@ func (c *Cache) Delete(uri string) {
c.usedRefsMu.Lock()
delete(c.usedRefs, uri)
c.usedRefsMu.Unlock()

c.ignoredFileContentsMu.Lock()
delete(c.ignoredFileContents, uri)
c.ignoredFileContentsMu.Unlock()
}

func UpdateCacheForURIFromDisk(cache *Cache, uri, path string) (string, error) {
Expand Down
68 changes: 66 additions & 2 deletions internal/lsp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func (l *LanguageServer) Handle(
case "textDocument/didOpen":
return l.handleTextDocumentDidOpen(ctx, conn, req)
case "textDocument/didClose":
return struct{}{}, nil
return l.handleTextDocumentDidClose(ctx, conn, req)
case "textDocument/didSave":
return l.handleTextDocumentDidSave(ctx, conn, req)
case "textDocument/documentSymbol":
Expand Down Expand Up @@ -748,6 +748,10 @@ func (l *LanguageServer) handleTextDocumentInlayHint(
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}

if l.ignoreURI(params.TextDocument.URI) {
return []types.InlayHint{}, nil
}

// when a file cannot be parsed, we do a best effort attempt to provide inlay hints
// by finding the location of the first parse error and attempting to parse up to that point
parseErrors, ok := l.cache.GetParseErrors(params.TextDocument.URI)
Expand Down Expand Up @@ -931,18 +935,49 @@ func (l *LanguageServer) handleTextDocumentDidOpen(
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}

// if the opened file is ignored in config, then we only store the
// contents for file level operations like formatting.
if l.ignoreURI(params.TextDocument.URI) {
l.cache.SetIgnoredFileContents(
params.TextDocument.URI,
params.TextDocument.Text,
)

return struct{}{}, nil
}

evt := fileUpdateEvent{
Reason: "textDocument/didOpen",
URI: params.TextDocument.URI,
Content: params.TextDocument.Text,
}

l.diagnosticRequestFile <- evt

l.builtinsPositionFile <- evt

return struct{}{}, nil
}

func (l *LanguageServer) handleTextDocumentDidClose(
_ context.Context,
_ *jsonrpc2.Conn,
req *jsonrpc2.Request,
) (result any, err error) {
var params types.TextDocumentDidCloseParams
if err := json.Unmarshal(*req.Params, &params); err != nil {
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}

// if the file being closed is ignored in config, then we
// need to clear it from the ignored state in the cache.
if l.ignoreURI(params.TextDocument.URI) {
l.cache.Delete(params.TextDocument.URI)
}

return struct{}{}, nil
}

func (l *LanguageServer) handleTextDocumentDidChange(
_ context.Context,
_ *jsonrpc2.Conn,
Expand All @@ -953,6 +988,21 @@ func (l *LanguageServer) handleTextDocumentDidChange(
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}

if len(params.ContentChanges) == 0 {
return struct{}{}, nil
}

// if the changed file is ignored in config, then we only store the
// contents for file level operations like formatting.
if l.ignoreURI(params.TextDocument.URI) {
l.cache.SetIgnoredFileContents(
params.TextDocument.URI,
params.ContentChanges[0].Text,
)

return struct{}{}, nil
}

evt := fileUpdateEvent{
Reason: "textDocument/didChange",
URI: params.TextDocument.URI,
Expand Down Expand Up @@ -1025,6 +1075,10 @@ func (l *LanguageServer) handleTextDocumentDocumentSymbol(
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}

if l.ignoreURI(params.TextDocument.URI) {
return []types.DocumentSymbol{}, nil
}

contents, ok := l.cache.GetFileContents(params.TextDocument.URI)
if !ok {
l.logError(fmt.Errorf("failed to get file contents for uri %q", params.TextDocument.URI))
Expand Down Expand Up @@ -1079,7 +1133,17 @@ func (l *LanguageServer) handleTextDocumentFormatting(
l.logError(fmt.Errorf("formatting params validation warnings: %v", warnings))
}

oldContent, ok := l.cache.GetFileContents(params.TextDocument.URI)
var oldContent string

var ok bool

// Fetch the contents used for formatting from the appropriate cache location.
if l.ignoreURI(params.TextDocument.URI) {
oldContent, ok = l.cache.GetIgnoredFileContents(params.TextDocument.URI)
} else {
oldContent, ok = l.cache.GetFileContents(params.TextDocument.URI)
}

if !ok {
return nil, fmt.Errorf("failed to get file contents for uri %q", params.TextDocument.URI)
}
Expand Down
4 changes: 4 additions & 0 deletions internal/lsp/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ type TextDocumentDidOpenParams struct {
TextDocument TextDocumentItem `json:"textDocument"`
}

type TextDocumentDidCloseParams struct {
TextDocument TextDocumentItem `json:"textDocument"`
}

type TextDocumentItem struct {
LanguageID string `json:"languageId"`
Text string `json:"text"`
Expand Down

0 comments on commit 8dd71c8

Please sign in to comment.