Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 6add40c

Browse files
committed
[Debugger] Implemented code-completion for the new MacObjectValueTreeView
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/999418/
1 parent a50f147 commit 6add40c

File tree

8 files changed

+465
-9
lines changed

8 files changed

+465
-9
lines changed

main/src/addins/MonoDevelop.Debugger/MonoDevelop.Debugger.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@
208208
<Compile Include="MonoDevelop.Debugger\ObjectValue\Mac\MacDebuggerObjectPinView.cs" />
209209
<Compile Include="MonoDevelop.Debugger\ObjectValue\ExpressionEventArgs.cs" />
210210
<Compile Include="MonoDevelop.Debugger\ObjectValue\Mac\MacDebuggerTextField.cs" />
211+
<Compile Include="MonoDevelop.Debugger\DebuggerAsyncCompletionSource.cs" />
212+
<Compile Include="MonoDevelop.Debugger\DebuggerCompletionCommandHandler.cs" />
211213
</ItemGroup>
212214
<ItemGroup Condition="$(OS) != 'Windows_NT'">
213215
<Compile Include="MonoDevelop.Debugger.VSTextView\ExceptionCaught\ExceptionCaughtProvider.cs" />
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//
2+
// DebuggerAsyncCompletionSource.cs
3+
//
4+
// Author:
5+
// David Karlas <[email protected]>
6+
//
7+
// Copyright (c) 2019 Microsoft Corp.
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System;
28+
using System.Threading;
29+
using System.Threading.Tasks;
30+
using System.Collections.Generic;
31+
using System.Collections.Immutable;
32+
using System.ComponentModel.Composition;
33+
34+
using Microsoft.VisualStudio.Text;
35+
using Microsoft.VisualStudio.Utilities;
36+
using Microsoft.VisualStudio.Text.Editor;
37+
using Microsoft.VisualStudio.Text.Adornments;
38+
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
39+
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion.Data;
40+
41+
using ObjectValueFlags = Mono.Debugging.Client.ObjectValueFlags;
42+
43+
namespace MonoDevelop.Debugger
44+
{
45+
static class DebuggerCompletion
46+
{
47+
public const string ContentType = "DebuggerCompletion";
48+
}
49+
50+
[Export (typeof (IAsyncCompletionSourceProvider))]
51+
[Name ("Debugger Completion Source Provider")]
52+
[ContentType (DebuggerCompletion.ContentType)]
53+
sealed class DebuggerAsyncCompletionSourceProvider : IAsyncCompletionSourceProvider
54+
{
55+
public IAsyncCompletionSource GetOrCreate (ITextView textView)
56+
{
57+
return new DebuggerAsyncCompletionSource ();
58+
}
59+
}
60+
61+
sealed class DebuggerAsyncCompletionSource : IAsyncCompletionSource
62+
{
63+
static readonly Task<object> EmptyDescription = Task.FromResult<object> (null);
64+
65+
public async Task<CompletionContext> GetCompletionContextAsync (IAsyncCompletionSession session, CompletionTrigger trigger, SnapshotPoint triggerLocation, SnapshotSpan applicableToSpan, CancellationToken token)
66+
{
67+
var text = triggerLocation.Snapshot.GetText (0, triggerLocation.Position);
68+
var data = await DebuggingService.GetCompletionDataAsync (DebuggingService.CurrentFrame, text, token);
69+
70+
if (data == null)
71+
return new CompletionContext (ImmutableArray<CompletionItem>.Empty);
72+
73+
var builder = ImmutableArray.CreateBuilder<CompletionItem> (data.Items.Count);
74+
75+
foreach (var item in data.Items) {
76+
var image = new ImageElement (ObjectValueTreeViewController.GetImageId (item.Flags));
77+
78+
builder.Add (new CompletionItem (item.Name, this, image));
79+
}
80+
81+
return new CompletionContext (builder.MoveToImmutable ());
82+
}
83+
84+
public Task<object> GetDescriptionAsync (IAsyncCompletionSession session, CompletionItem item, CancellationToken token)
85+
{
86+
return EmptyDescription;
87+
}
88+
89+
public CompletionStartData InitializeCompletion (CompletionTrigger trigger, SnapshotPoint triggerLocation, CancellationToken token)
90+
{
91+
var text = triggerLocation.Snapshot.GetText (0, triggerLocation.Position);
92+
var span = GetWordSpan (text, triggerLocation.Position);
93+
94+
return new CompletionStartData (CompletionParticipation.ProvidesItems, new SnapshotSpan (triggerLocation.Snapshot, span));
95+
}
96+
97+
public static Span GetWordSpan (string text, int position)
98+
{
99+
var start = position;
100+
while (start > 0 && char.IsLetterOrDigit (text[start - 1]))
101+
start--;
102+
103+
// If we're brought up in the middle of a word, extend to the end of the word as well.
104+
// This means that if a user brings up the completion list at the start of the word they
105+
// will "insert" the text before what's already there (useful for qualifying existing
106+
// text). However, if they bring up completion in the "middle" of a word, then they will
107+
// "overwrite" the text. Useful for correcting misspellings or just replacing unwanted
108+
// code with new code.
109+
var end = position;
110+
if (start != position) {
111+
while (end < text.Length && char.IsLetterOrDigit (text[end]))
112+
end++;
113+
}
114+
115+
return Span.FromBounds (start, end);
116+
}
117+
}
118+
119+
[Export (typeof (IAsyncCompletionCommitManagerProvider))]
120+
[Name ("Debugger Completion Commit Manager")]
121+
[ContentType (DebuggerCompletion.ContentType)]
122+
sealed class DebuggerAsyncCompletionCommitManagerProvider : IAsyncCompletionCommitManagerProvider
123+
{
124+
public IAsyncCompletionCommitManager GetOrCreate (ITextView textView)
125+
{
126+
return new DebuggerAsyncCompletionCommitManager ();
127+
}
128+
}
129+
130+
sealed class DebuggerAsyncCompletionCommitManager : IAsyncCompletionCommitManager
131+
{
132+
static readonly char[] CommitCharacters = new char[] { ' ', '\t', '\n', '.', ',', '<', '>', '(', ')', '[', ']' };
133+
134+
public IEnumerable<char> PotentialCommitCharacters {
135+
get { return CommitCharacters; }
136+
}
137+
138+
public bool ShouldCommitCompletion (IAsyncCompletionSession session, SnapshotPoint location, char typedChar, CancellationToken token)
139+
{
140+
return true;
141+
}
142+
143+
public CommitResult TryCommit (IAsyncCompletionSession session, ITextBuffer buffer, CompletionItem item, char typedChar, CancellationToken token)
144+
{
145+
// Note: Hitting Return should *always* complete the current selection, but other typed chars require examining context...
146+
if (typedChar != '\0' && typedChar != '\n') {
147+
var text = buffer.CurrentSnapshot.GetText ();
148+
var span = DebuggerAsyncCompletionSource.GetWordSpan (text, text.Length);
149+
150+
if (span.Length == 0)
151+
return new CommitResult (true, CommitBehavior.None);
152+
153+
var typedWord = text.AsSpan (span.Start, span.Length);
154+
155+
if (!item.InsertText.AsSpan ().Contains (typedWord, StringComparison.Ordinal))
156+
return new CommitResult (true, CommitBehavior.None);
157+
}
158+
159+
return CommitResult.Unhandled;
160+
}
161+
}
162+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// MacDebuggerCompletionCommandHandler.cs
3+
//
4+
// Author:
5+
// Jeffrey Stedfast <[email protected]>
6+
//
7+
// Copyright (c) 2019 Microsoft Corp.
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
using System.ComponentModel.Composition;
28+
29+
using Microsoft.VisualStudio.Utilities;
30+
using Microsoft.VisualStudio.Commanding;
31+
using Microsoft.VisualStudio.Text.Editor;
32+
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
33+
using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion;
34+
35+
namespace MonoDevelop.Debugger
36+
{
37+
[Name ("Debbugger Completion CommandHandler")]
38+
[ContentType (DebuggerCompletion.ContentType)]
39+
[TextViewRole (PredefinedTextViewRoles.Interactive)]
40+
[Export (typeof (ICommandHandler))]
41+
[Order (After = PredefinedCompletionNames.CompletionCommandHandler)]
42+
sealed class DebuggerCompletionCommandHandler :
43+
ICommandHandler<EscapeKeyCommandArgs>,
44+
ICommandHandler<ReturnKeyCommandArgs>,
45+
ICommandHandler<TabKeyCommandArgs>
46+
{
47+
public string DisplayName => nameof (DebuggerCompletionCommandHandler);
48+
49+
#region EscapeKey
50+
51+
public CommandState GetCommandState (EscapeKeyCommandArgs args)
52+
{
53+
return CommandState.Available;
54+
}
55+
56+
public bool ExecuteCommand (EscapeKeyCommandArgs args, CommandExecutionContext executionContext)
57+
{
58+
var cocoaTextView = (ICocoaTextView) args.TextView;
59+
var bgView = cocoaTextView.VisualElement.Superview; // the NSView that draws the background color
60+
var superview = bgView?.Superview;
61+
62+
if (superview is MacDebuggerObjectNameView nameView)
63+
nameView.CancelEdit ();
64+
else
65+
System.Console.WriteLine ("superview is {0}", superview.GetType ().FullName);
66+
67+
return true;
68+
}
69+
70+
#endregion // EscapeKey
71+
72+
#region ReturnKey
73+
74+
public CommandState GetCommandState (ReturnKeyCommandArgs args)
75+
{
76+
return CommandState.Available;
77+
}
78+
79+
public bool ExecuteCommand (ReturnKeyCommandArgs args, CommandExecutionContext executionContext)
80+
{
81+
var cocoaTextView = (ICocoaTextView) args.TextView;
82+
83+
cocoaTextView.VisualElement.ResignFirstResponder ();
84+
85+
return true;
86+
}
87+
88+
#endregion // ReturnKey
89+
90+
#region TabKey
91+
92+
public CommandState GetCommandState (TabKeyCommandArgs args)
93+
{
94+
return CommandState.Available;
95+
}
96+
97+
public bool ExecuteCommand (TabKeyCommandArgs args, CommandExecutionContext executionContext)
98+
{
99+
var cocoaTextView = (ICocoaTextView) args.TextView;
100+
101+
cocoaTextView.VisualElement.ResignFirstResponder ();
102+
103+
return true;
104+
}
105+
106+
#endregion // TabKey
107+
}
108+
}

0 commit comments

Comments
 (0)