Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Async Indexer for new LanguageServer #558

Merged
merged 128 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
b9b2554
IndexParser
brianbok Jan 25, 2019
cd1878d
Workspace Index Manage
brianbok Jan 26, 2019
6a6a38d
Sorting using as configured on repo
brianbok Jan 28, 2019
765653b
Removing unuseful empty property
brianbok Jan 28, 2019
b42d1f4
Moving directory reader to DirectoryInfo
brianbok Jan 28, 2019
8a4d3d6
EnumerateFiles returns non-lazily
brianbok Jan 28, 2019
33d768a
IndexParser throws FileNotFoundException
brianbok Jan 28, 2019
1db8030
Events on files
brianbok Jan 28, 2019
52dd812
Adding update event to index manager
brianbok Jan 29, 2019
7c535c3
Async IndexParser
brianbok Jan 29, 2019
05f3b4e
Async IndexManager
brianbok Jan 29, 2019
e5791d3
Check ArgumentNotNull using Diagnostics
brianbok Jan 29, 2019
b39ecf4
Async fixes
brianbok Jan 29, 2019
b767fbd
PythonVersions.LatestAvailable3X
brianbok Jan 29, 2019
703de21
SymbolIndex fixes
brianbok Jan 30, 2019
af85966
SymbolIndex moving method from HierarchicalSymbol
brianbok Jan 30, 2019
2c7dc2d
SymbolIndex corrections
brianbok Jan 30, 2019
26bef41
SymbolIndex return style
brianbok Jan 30, 2019
93d0464
Adding symbolIndex tests
brianbok Jan 30, 2019
c93c496
SymbolIndex return style
brianbok Jan 30, 2019
28685c6
Using strings (plain path) instead of Uri
brianbok Jan 30, 2019
0091933
More tests
brianbok Jan 31, 2019
c0a0387
More Uri to string type transforming
brianbok Jan 31, 2019
6e4a0f5
Removing FileNotFoundException
brianbok Jan 31, 2019
2e8ecdf
Single Line Return
brianbok Jan 31, 2019
332358f
SymbolIndex Interface
brianbok Jan 31, 2019
0048bf8
Fix AddRoot Test
brianbok Feb 1, 2019
8f4343e
Disposing test fix
brianbok Feb 1, 2019
36ed2e6
Blocking tests new fake
brianbok Feb 1, 2019
d58cc6b
Wait for AddRootTask in symbol querying
brianbok Feb 1, 2019
2b3d450
Refactor tests and async add root
brianbok Feb 2, 2019
36c6f85
Adding license header
brianbok Feb 2, 2019
a897585
TraverseBreadth variable rename
brianbok Feb 2, 2019
7a2b9c3
deleting unused variable
brianbok Feb 5, 2019
b493294
Limiting API
brianbok Feb 5, 2019
fb7f8b3
Dispose test fixed
brianbok Feb 5, 2019
c4dcf23
Limiting API fix and styling
brianbok Feb 5, 2019
aedb206
Dispose testing
brianbok Feb 5, 2019
ac2098a
Merge branch 'master' into indexer
brianbok Feb 7, 2019
1363efc
Moved everything into language server
brianbok Feb 7, 2019
d788f16
Tests refactor and connecting index to ls
brianbok Feb 7, 2019
98c18aa
Adding file events
brianbok Feb 8, 2019
eb83604
async fix
brianbok Feb 8, 2019
8b90ac7
Enumerable fix
brianbok Feb 8, 2019
fae4315
Delete copy of SymbolKind
brianbok Feb 8, 2019
d3f7da1
Revert "Delete copy of SymbolKind"
brianbok Feb 8, 2019
9c0cb66
Deleting cast
brianbok Feb 11, 2019
7d159bc
Async handling update of AST
brianbok Feb 11, 2019
a03c022
Versioned symbolindex
brianbok Feb 12, 2019
f6c854b
More versioned syncronization
brianbok Feb 12, 2019
6cf5057
Removing event handler from doc
brianbok Feb 13, 2019
4406a71
Safely executing matcher
brianbok Feb 13, 2019
ab650eb
Casting instead of 'as'
brianbok Feb 13, 2019
2617c92
Cast
brianbok Feb 13, 2019
a62bf81
Returning on execute matcher
brianbok Feb 13, 2019
fa32e97
Adding empty workspace path check
brianbok Feb 14, 2019
b38e22b
Merge branch 'master' into indexer
brianbok Feb 14, 2019
93e4d0d
Resolving race condition
brianbok Feb 14, 2019
80d4d39
Async rename
brianbok Feb 14, 2019
57d5ec8
Idling for index
brianbok Feb 14, 2019
78f12c8
Adding delay to idling
brianbok Feb 14, 2019
4a724c7
New async interface
brianbok Feb 15, 2019
0f331c2
Passed more tests
brianbok Feb 15, 2019
d3b4761
Removing fields of test
brianbok Feb 15, 2019
74e9bed
Passes every test again
brianbok Feb 15, 2019
59bccd2
Working version
brianbok Feb 15, 2019
0727619
Readonly fields
brianbok Feb 15, 2019
dc7b9eb
IndexParser refactoring
brianbok Feb 16, 2019
935f6ba
IndexParser fixes
brianbok Feb 16, 2019
6578616
No Tcs in IndexParser
brianbok Feb 16, 2019
e5bf1d8
Disposing streams
brianbok Feb 16, 2019
108259f
Implementing tcs pattern
brianbok Feb 16, 2019
1ff0935
PR comments fixes and typos
brianbok Feb 19, 2019
0bc72c3
Rework of tcs in indexmanager
brianbok Feb 19, 2019
2bba9dc
Delete unused variable
brianbok Feb 19, 2019
9c5bb3a
Disposal check
brianbok Feb 19, 2019
8de9f3a
TCS no reuse
brianbok Feb 19, 2019
e2bf0fe
Reorder layers
brianbok Feb 20, 2019
d04d375
Making interface for mostrecent symbols
brianbok Feb 20, 2019
f7f09fb
Copyright comments
brianbok Feb 20, 2019
9952681
Unused var
brianbok Feb 20, 2019
91b836c
Changin default delay
brianbok Feb 20, 2019
29ecef7
Rename and style correct
brianbok Feb 20, 2019
846f9a9
Getting rid of comment
brianbok Feb 20, 2019
8b19e45
Fix limiting in workspace symbols query
brianbok Feb 20, 2019
bad44b1
Better disposal
brianbok Feb 20, 2019
615e483
CancellationToken on querying
brianbok Feb 20, 2019
da29542
Walker walks annotated assignments
brianbok Feb 20, 2019
5dd8e2c
Removing use of MaybeEnumerate in Traverse
brianbok Feb 20, 2019
53766a6
Var instead of explicit Uri type
brianbok Feb 20, 2019
5384825
Null check
brianbok Feb 20, 2019
803b67f
max Concurrency handling
brianbok Feb 20, 2019
66f7ae4
Merge branch 'master' into indexer
brianbok Feb 20, 2019
8f704dd
Simple workspace querying
brianbok Feb 21, 2019
17a9d0a
Simplifying disposing
brianbok Feb 21, 2019
88ba453
Simplification
brianbok Feb 21, 2019
d9f8d57
Unused method
brianbok Feb 21, 2019
2c60d4f
CancellationToken
brianbok Feb 21, 2019
4825065
First state machine
brianbok Feb 21, 2019
fffb215
Tests for states of symbolIndex
brianbok Feb 21, 2019
25b6590
Rename of state
brianbok Feb 21, 2019
4a569ef
Comment on name of state
brianbok Feb 21, 2019
08f6287
File Open FileSystem back to how it was
brianbok Feb 21, 2019
05e711d
Server.Symbols
brianbok Feb 21, 2019
9213ca7
Reference to deleted field
brianbok Feb 21, 2019
0e3c42d
Extra new lines
brianbok Feb 21, 2019
9fcdbe5
Extra spaces
brianbok Feb 21, 2019
08858f0
Delete unused code
brianbok Feb 21, 2019
ccef536
Pattern matching in walker
brianbok Feb 21, 2019
d60b481
Merge branch 'master' into indexer
brianbok Feb 21, 2019
121a8b0
Unused methods
brianbok Feb 21, 2019
c83112b
Using matcher for checking files in workspace
brianbok Feb 21, 2019
eba45f2
State machine changes
brianbok Feb 21, 2019
3881c9c
Change exception type
brianbok Feb 21, 2019
5b87d0f
Double releasing semaphore fix`
brianbok Feb 21, 2019
58d5396
Removing continuewith in mostrecentdoc
brianbok Feb 22, 2019
0ae25d8
Setting state, only one assignment per method
brianbok Feb 22, 2019
8ef5750
Disposing index parser in symbol index
brianbok Feb 22, 2019
14d3d90
Make includePatterns optional for match
brianbok Feb 22, 2019
a87deac
Not calling excludePatterns if unnecessary
brianbok Feb 22, 2019
2ee4b55
Use of concurrent dictionary instead of lock on object
brianbok Feb 25, 2019
ad258cc
Const instead of static
brianbok Feb 25, 2019
190f8a5
Merge branch 'indexer' of github.com:brianbok/python-language-server …
brianbok Feb 25, 2019
4fb33db
IndexParser task creation in a cleaner way
brianbok Feb 25, 2019
61039d5
Use of disposablebag everywhere`
brianbok Feb 25, 2019
2a23b61
Delete unused fields and params
brianbok Feb 25, 2019
6e44942
More disposablebag usage
brianbok Feb 25, 2019
5485c9c
Unused imports
brianbok Feb 25, 2019
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
13 changes: 13 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/IIndexManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Python.Analysis.Documents;

namespace Microsoft.Python.Analysis.Indexing {
internal interface IIndexManager : IDisposable {
Task AddRootDirectory(CancellationToken workspaceCancellationToken = default);
void ProcessFile(Uri uri, IDocument doc);
Task ProcessClosedFile(Uri uri, CancellationToken fileCancellationToken = default);
void ProcessFileIfIndexed(Uri uri, IDocument doc);
}
}
9 changes: 9 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/IIndexParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Python.Analysis.Indexing {
internal interface IIndexParser : IDisposable {
Task ParseAsync(Uri uri, CancellationToken cancellationToken = default);
}
}
11 changes: 11 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/ISymbolIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using Microsoft.Python.Parsing.Ast;

namespace Microsoft.Python.Analysis.Indexing {
internal interface ISymbolIndex {
void UpdateIndex(Uri uri, PythonAst pythonAst);
IEnumerable<FlatSymbol> WorkspaceSymbols(string query);
void Delete(Uri uri);
}
}
96 changes: 96 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/IndexManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Python.Analysis.Core.Interpreter;
using Microsoft.Python.Analysis.Documents;
using Microsoft.Python.Core.Diagnostics;
using Microsoft.Python.Core.IO;
using Microsoft.Python.Parsing;

namespace Microsoft.Python.Analysis.Indexing {
internal class IndexManager : IIndexManager {
private readonly ISymbolIndex _symbolIndex;
private readonly IFileSystem _fileSystem;
private readonly IndexParser _indexParser;
private readonly string _workspaceRootPath;
private readonly string[] _includeFiles;
private readonly string[] _excludeFiles;
private readonly ConcurrentDictionary<Uri, bool> _indexedFiles = new ConcurrentDictionary<Uri, bool>();
private readonly CancellationTokenSource _allIndexCts = new CancellationTokenSource();

public IndexManager(ISymbolIndex symbolIndex, IFileSystem fileSystem, PythonLanguageVersion version, string rootPath, string[] includeFiles,
string[] excludeFiles) {
Check.ArgumentNotNull(nameof(fileSystem), fileSystem);
Check.ArgumentNotNull(nameof(rootPath), rootPath);
Check.ArgumentNotNull(nameof(includeFiles), includeFiles);
Check.ArgumentNotNull(nameof(excludeFiles), excludeFiles);

_symbolIndex = symbolIndex;
_fileSystem = fileSystem;
_indexParser = new IndexParser(symbolIndex, fileSystem, version);
_workspaceRootPath = rootPath;
_includeFiles = includeFiles;
_excludeFiles = excludeFiles;
}

public Task AddRootDirectory(CancellationToken workspaceCancellationToken = default) {
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(workspaceCancellationToken, _allIndexCts.Token);
var parseTasks = new List<Task>();
foreach (var fileInfo in WorkspaceFiles()) {
if (ModulePath.IsPythonSourceFile(fileInfo.FullName)) {
Uri uri = new Uri(fileInfo.FullName);
parseTasks.Add(_indexParser.ParseAsync(uri, linkedCts.Token).ContinueWith((task) => {
linkedCts.Token.ThrowIfCancellationRequested();
_indexedFiles[uri] = true;
}));
}
}
return Task.WhenAll(parseTasks.ToArray());
}

private IEnumerable<IFileSystemInfo> WorkspaceFiles() {
return _fileSystem.GetDirectoryInfo(_workspaceRootPath).EnumerateFileSystemInfos(_includeFiles, _excludeFiles);
}

private bool IsFileIndexed(Uri uri) {
_indexedFiles.TryGetValue(uri, out var val);
return val;
}

public Task ProcessClosedFile(Uri uri, CancellationToken fileCancellationToken = default) {
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(fileCancellationToken, _allIndexCts.Token);
// If path is on workspace
if (IsFileOnWorkspace(uri)) {
// updates index and ignores previous AST
return _indexParser.ParseAsync(uri, linkedCts.Token);
} else {
// remove file from index
_indexedFiles.TryRemove(uri, out _);
_symbolIndex.Delete(uri);
return Task.CompletedTask;
}
}

private bool IsFileOnWorkspace(Uri uri) {
return _fileSystem.IsPathUnderRoot(_workspaceRootPath, uri.AbsolutePath);
}

public void ProcessFile(Uri uri, IDocument doc) {
_indexedFiles[uri] = true;
_symbolIndex.UpdateIndex(uri, doc.GetAnyAst());
}

public void ProcessFileIfIndexed(Uri uri, IDocument doc) {
if (IsFileIndexed(uri)) {
ProcessFile(uri, doc);
}
}

public void Dispose() {
_allIndexCts.Cancel();
_allIndexCts.Dispose();
}
}
}
45 changes: 45 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/IndexParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Python.Core.Diagnostics;
using Microsoft.Python.Core.IO;
using Microsoft.Python.Parsing;

namespace Microsoft.Python.Analysis.Indexing {
internal sealed class IndexParser : IIndexParser {
private readonly ISymbolIndex _symbolIndex;
private readonly IFileSystem _fileSystem;
private readonly PythonLanguageVersion _version;
private readonly CancellationTokenSource _allProcessingCts = new CancellationTokenSource();

public IndexParser(ISymbolIndex symbolIndex, IFileSystem fileSystem, PythonLanguageVersion version) {
Check.ArgumentNotNull(nameof(symbolIndex), symbolIndex);
Check.ArgumentNotNull(nameof(fileSystem), fileSystem);

_symbolIndex = symbolIndex;
_fileSystem = fileSystem;
_version = version;
}

public void Dispose() {
_allProcessingCts.Cancel();
_allProcessingCts.Dispose();
}

public Task ParseAsync(Uri uri, CancellationToken parseCancellationToken = default) {
var linkedParseCts = CancellationTokenSource.CreateLinkedTokenSource(_allProcessingCts.Token, parseCancellationToken);
var linkedParseToken = linkedParseCts.Token;
return Task.Run(() => {
if (!_fileSystem.FileExists(uri.AbsolutePath)) {
throw new FileNotFoundException($"{uri.AbsolutePath} does not exist", uri.AbsolutePath);
}
using (var stream = _fileSystem.FileOpen(uri.AbsolutePath, FileMode.Open)) {
var parser = Parser.CreateParser(stream, _version);
linkedParseToken.ThrowIfCancellationRequested();
_symbolIndex.UpdateIndex(uri, parser.ParseFile());
}
}, linkedParseToken);
}
}
}
48 changes: 48 additions & 0 deletions src/Analysis/Ast/Impl/Indexing/SymbolIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Python.Core;
using Microsoft.Python.Parsing.Ast;

namespace Microsoft.Python.Analysis.Indexing {
internal sealed class SymbolIndex : ISymbolIndex {
private readonly ConcurrentDictionary<Uri, IReadOnlyList<HierarchicalSymbol>> _index = new ConcurrentDictionary<Uri, IReadOnlyList<HierarchicalSymbol>>();

public IEnumerable<HierarchicalSymbol> HierarchicalDocumentSymbols(Uri uri)
=> _index.TryGetValue(uri, out var list) ? list : Enumerable.Empty<HierarchicalSymbol>();

public IEnumerable<FlatSymbol> WorkspaceSymbols(string query) {
foreach (var kvp in _index) {
foreach (var found in WorkspaceSymbolsQuery(query, kvp.Key, kvp.Value)) {
yield return found;
}
}
}

private IEnumerable<FlatSymbol> WorkspaceSymbolsQuery(string query, Uri uri, IEnumerable<HierarchicalSymbol> symbols) {
// Some semblance of a BFS.
var queue = new Queue<(HierarchicalSymbol, string)>(symbols.Select(s => (s, (string)null)));

while (queue.Count > 0) {
var (sym, parent) = queue.Dequeue();

if (sym.Name.ContainsOrdinal(query, ignoreCase: true)) {
yield return new FlatSymbol(sym.Name, sym.Kind, uri, sym.SelectionRange, parent);
}

foreach (var child in sym.Children.MaybeEnumerate()) {
queue.Enqueue((child, sym.Name));
}
}
}

public void UpdateIndex(Uri uri, PythonAst ast) {
var walker = new SymbolIndexWalker(ast);
ast.Walk(walker);
_index[uri] = walker.Symbols;
}

public void Delete(Uri uri) => _index.TryRemove(uri, out var _);
}
}
Loading