-
Notifications
You must be signed in to change notification settings - Fork 133
Better progress reporting #96
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Python Tools for Visual Studio | ||
// Copyright(c) Microsoft Corporation | ||
// All rights reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the License); you may not use | ||
// this file except in compliance with the License. You may obtain a copy of the | ||
// License at http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS | ||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY | ||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
// MERCHANTABLITY OR NON-INFRINGEMENT. | ||
// | ||
// See the Apache Version 2.0 License for specific language governing | ||
// permissions and limitations under the License. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using Microsoft.PythonTools.Analysis.Infrastructure; | ||
|
||
namespace Microsoft.Python.LanguageServer.Implementation { | ||
sealed class AnalysisProgressReporter : IDisposable { | ||
private readonly DisposableBag _disposables = new DisposableBag(nameof(AnalysisProgressReporter)); | ||
private readonly Dictionary<Uri, int> _activeAnalysis = new Dictionary<Uri, int>(); | ||
private readonly IProgressService _progressService; | ||
private readonly ILogger _logger; | ||
private readonly Server _server; | ||
private readonly object _lock = new object(); | ||
private IProgress _progress; | ||
|
||
public AnalysisProgressReporter(Server server, IProgressService progressService, ILogger logger) { | ||
_progressService = progressService; | ||
_logger = logger; | ||
|
||
_server = server; | ||
_server.OnAnalysisQueued += OnAnalysisQueued; | ||
_server.OnAnalysisComplete += OnAnalysisComplete; | ||
_disposables | ||
.Add(() => _server.OnAnalysisQueued -= OnAnalysisQueued) | ||
.Add(() => _server.OnAnalysisComplete -= OnAnalysisComplete) | ||
.Add(() => _progress?.Dispose()); | ||
} | ||
|
||
public void Dispose() { | ||
_disposables.TryDispose(); | ||
} | ||
|
||
private void OnAnalysisQueued(object sender, AnalysisQueuedEventArgs e) { | ||
lock (_lock) { | ||
if (_activeAnalysis.ContainsKey(e.uri)) { | ||
_activeAnalysis[e.uri]++; | ||
} else { | ||
_activeAnalysis[e.uri] = 1; | ||
} | ||
UpdateProgressMessage(); | ||
} | ||
} | ||
private void OnAnalysisComplete(object sender, AnalysisCompleteEventArgs e) { | ||
lock (_lock) { | ||
if (_activeAnalysis.TryGetValue(e.uri, out var count)) { | ||
if (count > 1) { | ||
_activeAnalysis[e.uri]--; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. This may explain stale messages in the status bar. I will check it out. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK then, back to monitoring queue. The important part is to make sure we do NOT display progress when nothing is being analyzed. |
||
} else { | ||
_activeAnalysis.Remove(e.uri); | ||
} | ||
} else { | ||
_logger.TraceMessage($"Analysis completed for {e.uri} that is not in the dictionary."); | ||
} | ||
UpdateProgressMessage(); | ||
} | ||
} | ||
|
||
private void UpdateProgressMessage() { | ||
if(_activeAnalysis.Count > 0) { | ||
_progress = _progress ?? _progressService.BeginProgress(); | ||
_progress.Report(_activeAnalysis.Count == 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is more like a status message rather than a progress, cause There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. This is how progresss is reported in VSC - via spinner and message in the status bar. I am not 100% about count but since analysis is recursive and event may fire from threads, I better be safe |
||
? Resources.AnalysisProgress_SingleItemRemaining | ||
: Resources.AnalysisProgress_MultipleItemsRemaining.FormatInvariant(_activeAnalysis.Count)).DoNotWait(); | ||
} else { | ||
_progress?.Dispose(); | ||
_progress = null; | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,12 @@ | |
<resheader name="writer"> | ||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||
</resheader> | ||
<data name="AnalysisProgress_MultipleItemsRemaining" xml:space="preserve"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If those strings go directly to the client, how do we choose the culture? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is to be determined.... Unfortunately, LSP does not specify locale, so we'll have to add some custom notification. Which reminds me to file #98 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we have those strings on VSC side and provide only numbers? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. VSC is not the only client. LSP is public and supported by Eclipse, Vim, Emacs and more. So there is actually a plan to try LS with one of those. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, but isn't this part of the LS protocol is python specific and we will have to add something to the client-side anyway? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like |
||
<value>Analyzing workspace, {0} items remaining...</value> | ||
</data> | ||
<data name="AnalysisProgress_SingleItemRemaining" xml:space="preserve"> | ||
<value>Analyzing workspace, 1 item remaining...</value> | ||
</data> | ||
<data name="RenameVariable_CannotRename" xml:space="preserve"> | ||
<value>Cannot rename</value> | ||
</data> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has an issue of creating strings (lots of strings) even when logging is switched off or doesn't meet the required severity. It creates noticeable performance impact. If we need to get formatted strings from resources and can't use
IFormattable
, we can addTraceMessageFormat(string format, params object[] parameters)
and do formatting only when logging is enabled.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK