Skip to content

Commit 30cd027

Browse files
committed
添加"异步完成模式"选项,用于启用新的异步完成逻辑;
1 parent f3c7918 commit 30cd027

21 files changed

+319
-106
lines changed

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
# ChinesePinyinIntelliSenseExtender
1+
# ChinesePinyinIntelliSenseExtender
22

3-
VisualStudio中文代码拼音补全拓展
3+
VisualStudio表意文字补全拓展(汉语拼音、五笔等)
44

5-
- 仅在 `C#``F#` 下进行了测试,理论上支持所有基于 `IAsyncCompletionSource` 的完成。
6-
- 支持自定义字符映射。
5+
- 支持自定义字符映射,可支持任意表意文字的表音补全。
76

87
View at [VisualStudio Marketplace](https://marketplace.visualstudio.com/items?itemName=stratos.ChinesePinyinIntelliSenseExtender)
98

src/ChinesePinyinIntelliSenseExtender.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
</Compile>
7171
<Compile Include="Options\Model\DictionaryManageOptions.cs" />
7272
<Compile Include="Options\Model\Options.cs" />
73+
<Compile Include="Options\Model\AsyncCompletionMode.cs" />
7374
<Compile Include="Options\Model\StringPreCheckRule.cs" />
7475
<Compile Include="Options\Model\PreMatchType.cs" />
7576
<Compile Include="Options\DictionaryManagePage.cs">
@@ -114,6 +115,7 @@
114115
<Compile Include="Util\CompletionSetSelectBestMatchHelper.cs" />
115116
<Compile Include="Util\EnumerableExtend.cs" />
116117
<Compile Include="Util\InputTextMatchHelper.cs" />
118+
<Compile Include="Internal\IPreCheckPredicate.cs" />
117119
<Compile Include="Util\StringPreMatchUtil.cs" />
118120
<Compile Include="Util\InputMethodDictionaryLoader.cs" />
119121
<Compile Include="Intellisense\AsyncCompletion\IdeographAsyncCompletionSource.cs" />

src/Intellisense/AsyncCompletion/IdeographAsyncCompletionItemManager.cs

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,33 @@
1212

1313
namespace ChinesePinyinIntelliSenseExtender.Intellisense.AsyncCompletion;
1414

15-
internal class IdeographAsyncCompletionItemManager(IPatternMatcherFactory _patternMatcherFactory) : IAsyncCompletionItemManager
15+
internal class IdeographAsyncCompletionItemManager(GeneralOptions options, IPatternMatcherFactory patternMatcherFactory) : IAsyncCompletionItemManager
1616
{
17-
//private void write(TimeSpan t, string msg = "", [CallerMemberName] string n = "")
18-
//{
19-
// using var s = File.AppendText("D:\\time.txt");
20-
// s.WriteLine($"[{DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond}] {n}: {t.TotalMilliseconds}ms ({msg})");
21-
//}
17+
#region Private 字段
2218

23-
private InputMethodDictionaryGroup? _inputMethodDictionaryGroup;
19+
/// <summary>
20+
/// 匹配缓存,当前没有移除?可能需要处理
21+
/// </summary>
2422
private readonly ConcurrentDictionary<(PreMatchType, StringPreCheckRule, string), string> _filterTextCache = [];
25-
private GeneralOptions? _options;
2623

27-
private async Task<InputMethodDictionaryGroup> GetInputMethodDictionaryGroupAsync()
28-
{
29-
if (_inputMethodDictionaryGroup is null
30-
|| _inputMethodDictionaryGroup.IsDisposed)
31-
{
32-
_inputMethodDictionaryGroup = await InputMethodDictionaryGroupProvider.GetAsync();
33-
}
34-
return _inputMethodDictionaryGroup;
35-
}
24+
private readonly GeneralOptions _options = options ?? throw new ArgumentNullException(nameof(options));
3625

37-
private static IReadOnlyList<CompletionItem> SortCompletionItem(IReadOnlyList<CompletionItem> items)
38-
{
39-
bool CheckShouldSort()
40-
{
41-
return !(Parallel.For(1, items.Count, (i, p) =>
42-
{
43-
if (items[i - 1].SortText.CompareTo(items[i].SortText) > 0) p.Stop();
44-
}).IsCompleted);
45-
}
26+
private readonly IPatternMatcherFactory _patternMatcherFactory = patternMatcherFactory ?? throw new ArgumentNullException(nameof(patternMatcherFactory));
4627

47-
if (CheckShouldSort()) { return items.AsParallel().OrderBy(i => i.SortText).ToArray(); }
48-
return items;
49-
}
28+
private InputMethodDictionaryGroup? _inputMethodDictionaryGroup;
29+
30+
#endregion Private 字段
31+
32+
#region Public 方法
5033

5134
public Task<ImmutableArray<CompletionItem>> SortCompletionListAsync(IAsyncCompletionSession session, AsyncCompletionSessionInitialDataSnapshot data, CancellationToken token)
5235
{
36+
if (!_options.Enable
37+
|| _options.AsyncCompletionMode != AsyncCompletionMode.Experimental)
38+
{
39+
return Task.FromResult<ImmutableArray<CompletionItem>>(default);
40+
}
41+
5342
//var st = ValueStopwatch.StartNew();
5443
var sortedItems = SortCompletionItem(data.InitialList).ToImmutableArray();
5544
//var t = st.Elapsed;
@@ -59,6 +48,12 @@ public Task<ImmutableArray<CompletionItem>> SortCompletionListAsync(IAsyncComple
5948

6049
public async Task<FilteredCompletionModel> UpdateCompletionListAsync(IAsyncCompletionSession session, AsyncCompletionSessionDataSnapshot data, CancellationToken token)
6150
{
51+
if (!_options.Enable
52+
|| _options.AsyncCompletionMode != AsyncCompletionMode.Experimental)
53+
{
54+
return default!;
55+
}
56+
6257
//var st = ValueStopwatch.StartNew();
6358
//TimeSpan t;
6459

@@ -83,7 +78,6 @@ public async Task<FilteredCompletionModel> UpdateCompletionListAsync(IAsyncCompl
8378
return new FilteredCompletionModel(listHighlighted, 0, data.SelectedFilters);
8479
}
8580

86-
_options ??= await GeneralOptions.GetLiveInstanceAsync();
8781
var shouldProcessChecker = StringPreMatchUtil.GetPreCheckPredicate(_options.PreMatchType, _options.PreCheckRule);
8882
var inputMethodDictionaryGroup = await GetInputMethodDictionaryGroupAsync();
8983

@@ -187,9 +181,17 @@ string AddToCacheAndReturn(string v)
187181
return new FilteredCompletionModel(listWithHighlights, selectedItemIndex, updatedFilters);
188182
}
189183

190-
private static bool ShouldBeInCompletionList(
191-
CompletionItem item,
192-
ImmutableArray<CompletionFilterWithState> filtersWithState)
184+
#endregion Public 方法
185+
186+
#region Private 方法
187+
188+
//private void write(TimeSpan t, string msg = "", [CallerMemberName] string n = "")
189+
//{
190+
// using var s = File.AppendText("D:\\time.txt");
191+
// s.WriteLine($"[{DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond}] {n}: {t.TotalMilliseconds}ms ({msg})");
192+
//}
193+
194+
private static bool ShouldBeInCompletionList(CompletionItem item, ImmutableArray<CompletionFilterWithState> filtersWithState)
193195
{
194196
foreach (var filterWithState in filtersWithState.Where(n => n.IsSelected))
195197
{
@@ -200,4 +202,30 @@ private static bool ShouldBeInCompletionList(
200202
}
201203
return false;
202204
}
205+
206+
private static IReadOnlyList<CompletionItem> SortCompletionItem(IReadOnlyList<CompletionItem> items)
207+
{
208+
bool CheckShouldSort()
209+
{
210+
return !(Parallel.For(1, items.Count, (i, p) =>
211+
{
212+
if (items[i - 1].SortText.CompareTo(items[i].SortText) > 0) p.Stop();
213+
}).IsCompleted);
214+
}
215+
216+
if (CheckShouldSort()) { return items.AsParallel().OrderBy(i => i.SortText).ToArray(); }
217+
return items;
218+
}
219+
220+
private async Task<InputMethodDictionaryGroup> GetInputMethodDictionaryGroupAsync()
221+
{
222+
if (_inputMethodDictionaryGroup is null
223+
|| _inputMethodDictionaryGroup.IsDisposed)
224+
{
225+
_inputMethodDictionaryGroup = await InputMethodDictionaryGroupProvider.GetAsync();
226+
}
227+
return _inputMethodDictionaryGroup;
228+
}
229+
230+
#endregion Private 方法
203231
}

src/Intellisense/AsyncCompletion/IdeographAsyncCompletionItemManagerProvider.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#nullable enable
22

33
using System.ComponentModel.Composition;
4+
using System.Threading;
5+
using ChinesePinyinIntelliSenseExtender.Options;
46
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
57
using Microsoft.VisualStudio.Text.Editor;
68
using Microsoft.VisualStudio.Text.PatternMatching;
@@ -17,10 +19,59 @@ namespace ChinesePinyinIntelliSenseExtender.Intellisense.AsyncCompletion;
1719
[method: ImportingConstructor]
1820
internal class IdeographAsyncCompletionItemManagerProvider(IPatternMatcherFactory patternMatcherFactory) : IAsyncCompletionItemManagerProvider
1921
{
22+
#region Private 字段
23+
24+
/// <summary>
25+
/// 递归标记
26+
/// </summary>
27+
private static readonly AsyncLocal<bool> s_completionItemManagerProviderRecursionTag = new();
28+
2029
private static IdeographAsyncCompletionItemManager? s_instance;
2130

31+
[ImportMany]
32+
private readonly Lazy<IAsyncCompletionItemManagerProvider>[] _lazyIAsyncCompletionItemManagerProviders = null!;
33+
34+
private readonly IPatternMatcherFactory _patternMatcherFactory = patternMatcherFactory ?? throw new ArgumentNullException(nameof(patternMatcherFactory));
35+
36+
#endregion Private 字段
37+
38+
#region Public 方法
39+
2240
public IAsyncCompletionItemManager GetOrCreate(ITextView textView)
2341
{
24-
return s_instance ??= new IdeographAsyncCompletionItemManager(patternMatcherFactory);
42+
if (s_completionItemManagerProviderRecursionTag.Value)
43+
{
44+
return null!;
45+
}
46+
47+
var options = GeneralOptions.Instance;
48+
49+
//非实验模式不使用 IdeographAsyncCompletionItemManager
50+
if (!options.Enable
51+
|| options.AsyncCompletionMode != AsyncCompletionMode.Experimental)
52+
{
53+
try
54+
{
55+
s_completionItemManagerProviderRecursionTag.Value = true;
56+
57+
foreach (var provider in _lazyIAsyncCompletionItemManagerProviders)
58+
{
59+
if (provider.Value.GetOrCreate(textView) is IAsyncCompletionItemManager asyncCompletionItemManager)
60+
{
61+
return asyncCompletionItemManager;
62+
}
63+
}
64+
//返回null应该是没问题的
65+
return null!;
66+
}
67+
finally
68+
{
69+
s_completionItemManagerProviderRecursionTag.Value = false;
70+
}
71+
}
72+
73+
return s_instance ??= new IdeographAsyncCompletionItemManager(options, _patternMatcherFactory);
2574
}
75+
76+
#endregion Public 方法
2677
}

src/Intellisense/AsyncCompletion/IdeographAsyncCompletionSource.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Collections.Immutable;
55
using System.Diagnostics;
66
using System.Threading;
7-
7+
using ChinesePinyinIntelliSenseExtender.Internal;
88
using ChinesePinyinIntelliSenseExtender.Options;
99
using ChinesePinyinIntelliSenseExtender.Util;
1010

@@ -43,11 +43,12 @@ public IdeographAsyncCompletionSource(IEnumerable<IAsyncCompletionSource> otherA
4343
public async Task<CompletionContext?> GetCompletionContextAsync(IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
4444
{
4545
if (s_completionContextRecursionTag.Value
46-
|| !Options.Enable)
46+
|| !Options.Enable
47+
|| Options.AsyncCompletionMode != AsyncCompletionMode.Default)
4748
{
4849
return null;
4950
}
50-
51+
5152
try
5253
{
5354
s_completionContextRecursionTag.Value = true;

src/Intellisense/AsyncCompletion/IdeographAsyncCompletionSourceProvider.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
using System.ComponentModel.Composition;
44
using System.Diagnostics;
55
using System.Threading;
6+
using ChinesePinyinIntelliSenseExtender.Options;
67
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
78
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data;
89
using Microsoft.VisualStudio.Text;
910
using Microsoft.VisualStudio.Text.Editor;
11+
using Microsoft.VisualStudio.Utilities;
1012

1113
namespace ChinesePinyinIntelliSenseExtender.Intellisense.AsyncCompletion;
1214

13-
//[Export(typeof(IAsyncCompletionSourceProvider))]
14-
//[Name("表意文字表音补全")]
15-
//[ContentType("text")]
15+
[Export(typeof(IAsyncCompletionSourceProvider))]
16+
[Name("表意文字表音补全")]
17+
[ContentType("text")]
1618
internal class IdeographAsyncCompletionSourceProvider : CompletionSourceProviderBase<ITextView, IAsyncCompletionSource>, IAsyncCompletionSourceProvider
1719
{
1820
#region Private 字段
@@ -35,6 +37,13 @@ public IAsyncCompletionSource GetOrCreate(ITextView textView)
3537

3638
protected override IAsyncCompletionSource CreateCompletionSource(ITextView dependence)
3739
{
40+
//实验模式时不使用 IdeographAsyncCompletionSource
41+
if (!Options.Enable
42+
|| Options.AsyncCompletionMode == AsyncCompletionMode.Experimental)
43+
{
44+
return EmptyAsyncCompletionSource.Instance;
45+
}
46+
3847
var currentContentType = dependence.TextBuffer.ContentType;
3948

4049
var otherAsyncCompletionSources = _lazyAsyncCompletionSourceProviders

src/Intellisense/CompletionSourceProviderBase.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Reflection;
66
using System.Runtime.CompilerServices;
77
using System.Threading;
8-
using ChinesePinyinIntelliSenseExtender.Intellisense.AsyncCompletion;
98
using ChinesePinyinIntelliSenseExtender.Intellisense.SyncCompletion;
109
using ChinesePinyinIntelliSenseExtender.Options;
1110
using Microsoft.VisualStudio.Utilities;

src/Intellisense/SyncCompletion/IdeographCompletionCommandHandler.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ internal IdeographCompletionCommandHandler(IVsTextView textViewAdapter, ITextVie
4747
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
4848
{
4949
//see https://learn.microsoft.com/zh-cn/visualstudio/extensibility/walkthrough-displaying-statement-completion?view=vs-2022&tabs=csharp#tabpanel_19_csharp
50-
50+
5151
if (VsShellUtilities.IsInAutomationFunction(_serviceProvider)
52-
|| !_options.EnableSyncCompletionSupport
53-
// 跳过 C#/F#,防止输入卡顿
54-
|| _textView.TextBuffer.ContentType.BaseTypes.Any(i => i.TypeName == "Roslyn Languages"))
52+
|| !_options.EnableSyncCompletionSupport)
5553
{
5654
return _nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
5755
}

src/Intellisense/SyncCompletion/IdeographCompletionHandlerProvider.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,17 @@ public void VsTextViewCreated(IVsTextView textViewAdapter)
4040

4141
var options = GeneralOptions.Instance;
4242

43-
if (options.EnableSyncCompletionSupport)
43+
if (options.Enable
44+
&& options.EnableSyncCompletionSupport)
4445
{
45-
textView.Properties.GetOrCreateSingletonProperty(() => new IdeographCompletionCommandHandler(textViewAdapter, textView, CompletionBroker, ServiceProvider, options));
46+
//RoslynLanguages 都为异步完成
47+
//此处可以进一步缓存与完善异步完成的类型
48+
//前置检查,理论上 ContentType 不会在编辑过程中改变?
49+
var isRoslynLanguagesBase = textView.TextBuffer.ContentType.BaseTypes.Any(i => i.TypeName == "Roslyn Languages");
50+
if (!isRoslynLanguagesBase) //异步完成不需要此逻辑,跳过 CommandHandler 处理
51+
{
52+
textView.Properties.GetOrCreateSingletonProperty(() => new IdeographCompletionCommandHandler(textViewAdapter, textView, CompletionBroker, ServiceProvider, options));
53+
}
4654
}
4755
}
4856

src/Internal/IPreCheckPredicate.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace ChinesePinyinIntelliSenseExtender.Internal;
2+
3+
internal interface IPreCheckPredicate
4+
{
5+
#region Public 方法
6+
7+
bool Check(string value);
8+
9+
#endregion Public 方法
10+
}

0 commit comments

Comments
 (0)