提交 aa38480b 编写于 作者: I Ivan Basov

draft of completion support for types (excluding user control files)

上级 2d9dfa9f
......@@ -142,6 +142,7 @@ internal ChangeSignatureResult ChangeSignature(Document document, int position,
return new ChangeSignatureAnalyzedContext(CannotChangeSignatureReason.InsufficientParameters);
}
// TODO add here a span to be typed in
return new ChangeSignatureAnalyzedContext(
document, symbol, parameterConfiguration);
}
......
<vs:DialogWindow
x:Uid="ParameterDetailsDialog"
x:Name="dialog"
x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.AddParameterDialog"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:changesignature="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature"
Height="200" Width="400"
MinHeight="200" MinWidth="400"
Title="{Binding ElementName=dialog, Path=AddParameterDialogTitle}"
HasHelpButton="False"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
HasDialogFrame="True"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<Thickness x:Key="labelPadding">0, 5, 0, 2</Thickness>
<Thickness x:Key="okCancelButtonPadding">9,2,9,2</Thickness>
<Thickness x:Key="selectDeselectButtonPadding">9,2,9,2</Thickness>
<Thickness x:Key="cellPadding">4 0 8 0</Thickness>
<Thickness x:Key="textboxPadding">2</Thickness>
</Window.Resources>
<Grid Name="ContentGrid" Margin="11,6,11,11">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Name="Table" Margin="11,6,11,11">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding ElementName=dialog, Path=TypeNameLabel}" />
<Control Grid.Row="0" Grid.Column="1" Name="TypeControl" Width="200" Visibility="Visible" PreviewKeyDown="TypeControl_PreviewKeyDown" BorderBrush="Black" />
<Label Grid.Row="1" Grid.Column="0" Content="{Binding ElementName=dialog, Path=ParameterNameLabel}" />
<TextBox Grid.Row="1" Grid.Column="1" Width="200" Text="{Binding ParameterName}" HorizontalAlignment="Right"/>
<Label Grid.Row="2" Grid.Column="0" Content="{Binding ElementName=dialog, Path=CallsiteValueLabel}" />
<TextBox Grid.Row="2" Grid.Column="1" Width="200" Text="{Binding CallsiteValue}"/>
</Grid>
<StackPanel Grid.Row="1"
HorizontalAlignment="Right"
Margin="0, 11, 0, 0"
Orientation="Horizontal" Width="153">
<vs:DialogButton x:Uid="OKButton"
Content="{Binding ElementName=dialog, Path=OK}"
Margin="0, 0, 0, 0"
Padding="{StaticResource ResourceKey=okCancelButtonPadding}"
Click="OK_Click"
IsEnabled="{Binding IsOkButtonEnabled, Mode=OneWay}"
IsDefault="True"
MinWidth="73"
MinHeight="21"/>
<vs:DialogButton x:Uid="CancelButton"
Content="{Binding ElementName=dialog, Path=Cancel}"
Margin="7, 0, 0, 0"
Padding="{StaticResource ResourceKey=okCancelButtonPadding}"
Click="Cancel_Click"
IsCancel="True"
MinWidth="73"
MinHeight="21"/>
</StackPanel>
</Grid>
</vs:DialogWindow>
<vs:DialogWindow
x:Uid="ParameterDetailsDialog"
x:Name="dialog"
x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.AddParameterDialog"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0" xmlns:changesignature="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature"
Height="300" Width="600"
MinHeight="300" MinWidth="600"
Title="{Binding ElementName=dialog, Path=AddParameterDialogTitle}"
HasHelpButton="False"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
HasDialogFrame="True"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<Thickness x:Key="labelPadding">0, 5, 0, 2</Thickness>
<Thickness x:Key="okCancelButtonPadding">9,2,9,2</Thickness>
<Thickness x:Key="selectDeselectButtonPadding">9,2,9,2</Thickness>
<Thickness x:Key="cellPadding">4 0 8 0</Thickness>
<Thickness x:Key="textboxPadding">2</Thickness>
</Window.Resources>
<Grid Name="ContentGrid" Margin="11,6,11,11">
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Name="Table" Margin="11,6,11,11">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="400" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="{Binding ElementName=dialog, Path=TypeNameLabel}" />
<Border Grid.Row="0" Grid.Column="1" BorderThickness="1" Margin="6,0,0,0"> <changesignature:IntellisenseTextBlock x:Name="TypeNameTextBox" Padding="0" Width="300" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Focusable="True" AutomationProperties.Name="{Binding SelectedCondition.DisplayName}" /> </Border>
<Label Grid.Row="1" Grid.Column="0" Content="{Binding ElementName=dialog, Path=ParameterNameLabel}" />
<TextBox Grid.Row="1" Grid.Column="1" Width="200" Text="{Binding ParameterName}" />
<Label Grid.Row="2" Grid.Column="0" Content="{Binding ElementName=dialog, Path=CallsiteValueLabel}" />
<TextBox Grid.Row="2" Grid.Column="1" Width="200" Text="{Binding CallsiteValue}" />
</Grid>
<StackPanel Grid.Row="1"
HorizontalAlignment="Right"
Margin="0, 11, 0, 0"
Orientation="Horizontal" Width="153">
<vs:DialogButton x:Uid="OKButton"
Content="{Binding ElementName=dialog, Path=OK}"
Margin="0, 0, 0, 0"
Padding="{StaticResource ResourceKey=okCancelButtonPadding}"
Click="OK_Click"
IsEnabled="{Binding IsOkButtonEnabled, Mode=OneWay}"
IsDefault="True"
MinWidth="73"
MinHeight="21"/>
<vs:DialogButton x:Uid="CancelButton"
Content="{Binding ElementName=dialog, Path=Cancel}"
Margin="7, 0, 0, 0"
Padding="{StaticResource ResourceKey=okCancelButtonPadding}"
Click="Cancel_Click"
IsCancel="True"
MinWidth="73"
MinHeight="21"/>
</StackPanel>
</Grid>
</vs:DialogWindow>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using Microsoft.VisualStudio.Commanding;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding;
using Microsoft.VisualStudio.Text.Editor.Commanding.Commands;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.TextManager.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
......@@ -22,18 +13,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
internal partial class AddParameterDialog : DialogWindow
{
private readonly AddParameterDialogViewModel _viewModel;
private readonly ITextEditorFactoryService _textEditorFactoryService;
private readonly ITextBufferFactoryService _textBufferFactoryService;
private IEditorCommandHandlerServiceFactory _commandServiceFactory;
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
private readonly IContentType _contentType;
private IWpfTextView _wpfView;
private IEditorCommandHandlerService _commandService;
private Action Noop { get; } = new Action(() => { });
private Func<CommandState> Available { get; } = () => CommandState.Available;
private readonly IVsTextBuffer _textBuffer;
private readonly IVsTextView _textView;
private readonly IWpfTextView _wpfTextView;
public string OK { get { return ServicesVSResources.OK; } }
public string Cancel { get { return ServicesVSResources.Cancel; } }
......@@ -48,18 +30,14 @@ internal partial class AddParameterDialog : DialogWindow
public AddParameterDialog(
AddParameterDialogViewModel viewModel,
ITextEditorFactoryService textEditorFactoryService,
ITextBufferFactoryService textBufferFactoryService,
IEditorCommandHandlerServiceFactory commandServiceFactory,
IEditorOperationsFactoryService editorOperationsFactoryService,
IContentType contentType)
IVsTextBuffer textBuffer,
IVsTextView vsTextView,
IWpfTextView wpfTextView)
{
_viewModel = viewModel;
_textEditorFactoryService = textEditorFactoryService;
_textBufferFactoryService = textBufferFactoryService;
_commandServiceFactory = commandServiceFactory;
_editorOperationsFactoryService = editorOperationsFactoryService;
_contentType = contentType;
_textBuffer = textBuffer;
_textView = vsTextView;
_wpfTextView = wpfTextView;
this.Loaded += AddParameterDialog_Loaded;
InitializeComponent();
......@@ -67,15 +45,9 @@ internal partial class AddParameterDialog : DialogWindow
private void AddParameterDialog_Loaded(object sender, RoutedEventArgs e)
{
var buffer = _textBufferFactoryService.CreateTextBuffer(_contentType);
_wpfView = _textEditorFactoryService.CreateTextView(buffer, _textEditorFactoryService.AllPredefinedRoles); // DefaultRoles might be ok
var viewHost = _textEditorFactoryService.CreateTextViewHost(_wpfView, setFocus: true).HostControl;
this.TypeControl = viewHost;
_commandService = _commandServiceFactory.GetService(_wpfView, buffer);
var editorOperations = _editorOperationsFactoryService.GetEditorOperations(_wpfView);
this.TypeControl.Focus();
this.TypeNameTextBox.TextBuffer = _textBuffer;
this.TypeNameTextBox.TextView = _textView;
this.TypeNameTextBox.WpfTextView = _wpfTextView;
}
private void OK_Click(object sender, RoutedEventArgs e)
......@@ -90,83 +62,5 @@ private void Cancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
private void TypeControl_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
// TODO shift/alt
InsertChar(GetCharFromKey(e.Key));
}
// --- Get char from Key, courtesy of https://stackoverflow.com/a/5826175/879243
public enum MapType : uint
{
MAPVK_VK_TO_VSC = 0x0,
MAPVK_VSC_TO_VK = 0x1,
MAPVK_VK_TO_CHAR = 0x2,
MAPVK_VSC_TO_VK_EX = 0x3,
}
[DllImport("user32.dll")]
public static extern int ToUnicode(
uint wVirtKey,
uint wScanCode,
byte[] lpKeyState,
[Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
StringBuilder pwszBuff,
int cchBuff,
uint wFlags);
[DllImport("user32.dll")]
public static extern bool GetKeyboardState(byte[] lpKeyState);
[DllImport("user32.dll")]
public static extern uint MapVirtualKey(uint uCode, MapType uMapType);
public static char GetCharFromKey(Key key)
{
char ch = '\0';
int virtualKey = KeyInterop.VirtualKeyFromKey(key);
byte[] keyboardState = new byte[256];
GetKeyboardState(keyboardState);
uint scanCode = MapVirtualKey((uint)virtualKey, MapType.MAPVK_VK_TO_VSC);
StringBuilder stringBuilder = new StringBuilder(2);
int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
switch (result)
{
case -1:
break;
case 0:
break;
case 1:
{
ch = stringBuilder[0];
break;
}
default:
{
ch = stringBuilder[0];
break;
}
}
return ch;
}
public void InsertChar(char character)
{
QueryAndExecute((v, b) => new TypeCharCommandArgs(v, b, character));
}
public void QueryAndExecute<T>(Func<ITextView, ITextBuffer, T> argsFactory) where T : EditorCommandArgs
{
var state = _commandService.GetCommandState(argsFactory, Available);
if (state.IsAvailable)
{
_commandService.Execute(argsFactory, Noop);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Windows.Input;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
// TODO here or below, we need a split for different languages
// We may do this eiter creating such files for each content type or making the split below.
// Actually, ITextDataModel contains ContentType. So, we may do the split below.
[Export(typeof(ITextViewModelProvider))]
[ContentType(ContentTypeNames.RoslynContentType)]
[TextViewRole(VisualStudioChangeSignatureOptionsService.AddParameterTextViewRole)]
internal class AddParameterTextViewModelProvider : ITextViewModelProvider
{
[Import]
public IProjectionBufferFactoryService ProjectionBufferFactoryService { get; set; }
public ITextViewModel CreateTextViewModel(ITextDataModel dataModel, ITextViewRoleSet roles)
{
var namespaceSpan = GetNamespaceSpan(dataModel.DataBuffer.CurrentSnapshot);
var elisionBuffer = ProjectionBufferFactoryService.CreateElisionBuffer(
null,
new NormalizedSnapshotSpanCollection(namespaceSpan),
ElisionBufferOptions.None);
return new ElisionBufferTextViewModel(dataModel, elisionBuffer);
}
private SnapshotSpan GetNamespaceSpan(ITextSnapshot snapshot)
{
var totalLineNumber = snapshot.LineCount;
var start = snapshot.GetLineFromLineNumber(0).Start;
for (int i = 0; i < totalLineNumber; i++)
{
var currentLine = snapshot.GetLineFromLineNumber(i);
string text = currentLine.GetText().Trim();
//if (text.StartsWith("public virtual SomeCollection<T> Include(string path) => null;", StringComparison.Ordinal))
if (text.StartsWith("namespace", StringComparison.Ordinal))
{
int offset = "namespace".Length;
return new SnapshotSpan(currentLine.Start + offset, text.Length - offset);
//return new SnapshotSpan(currentLine.Start + text.IndexOf(")") - 1, 0);
}
}
throw new Exception("Unable to find namespace span.");
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Editor.Options;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal class ChangeSignatureWorkspace : Workspace
{
public ChangeSignatureWorkspace(Solution solution, Project project)
: base(project.Solution.Workspace.Services.HostServices, nameof(ChangeSignatureWorkspace))
{
// The solution we are handed is still parented by the original workspace. We want to
// inherit it's "no partial solutions" flag so that way this workspace will also act
// deterministically if we're in unit tests
this.TestHookPartialSolutionsDisabled = solution.Workspace.TestHookPartialSolutionsDisabled;
// Create a new document to hold the temporary code
ChangeSignatureDocumentId = DocumentId.CreateNewId(project.Id);
this.SetCurrentSolution(solution.AddDocument(ChangeSignatureDocumentId, Guid.NewGuid().ToString(), GetDocumentText()));
Options = Options.WithChangedOption(EditorCompletionOptions.UseSuggestionMode, true);
}
private string GetDocumentText()
{
return $@"
{{
}}
";
}
public Document ChangeSignatureDocument => this.CurrentSolution.GetDocument(this.ChangeSignatureDocumentId);
public DocumentId ChangeSignatureDocumentId { get; }
public void OpenDocument(DocumentId documentId, SourceTextContainer textContainer)
{
this.OnDocumentOpened(documentId, textContainer);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Windows;
using System.Windows.Media;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
// TODO move to utilities
internal static class DependencyObjectExtensions
{
public static DependencyObject TryGetParent(this DependencyObject obj)
{
return (obj is Visual) ? VisualTreeHelper.GetParent(obj) : null;
}
public static T GetParentOfType<T>(this DependencyObject element) where T : Visual
{
var parent = element.TryGetParent();
if (parent is T)
{
return (T)parent;
}
if (parent == null)
{
return null;
}
return parent.GetParentOfType<T>();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal class ElisionBufferTextViewModel : ITextViewModel
{
public ElisionBufferTextViewModel(ITextDataModel dataModel, IElisionBuffer elisionBuffer)
{
DataModel = dataModel;
ElisionBuffer = elisionBuffer;
Properties = new PropertyCollection();
}
public IElisionBuffer ElisionBuffer { get; }
public ITextDataModel DataModel { get; }
public ITextBuffer DataBuffer => DataModel.DataBuffer;
public ITextBuffer EditBuffer => ElisionBuffer;
public ITextBuffer VisualBuffer => ElisionBuffer;
public PropertyCollection Properties { get; }
public void Dispose()
{
}
public SnapshotPoint GetNearestPointInVisualBuffer(SnapshotPoint editBufferPoint) => editBufferPoint;
public SnapshotPoint GetNearestPointInVisualSnapshot(SnapshotPoint editBufferPoint, ITextSnapshot targetVisualSnapshot, PointTrackingMode trackingMode)
=> editBufferPoint.TranslateTo(targetVisualSnapshot, trackingMode);
public bool IsPointInVisualBuffer(SnapshotPoint editBufferPoint, PositionAffinity affinity) => true;
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.Design;
using System.Net.Mime;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using Constants = Microsoft.VisualStudio.OLE.Interop.Constants;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
{
internal sealed class ParameterTypeEditorControl : TextBox
{
private IVsTextView _vsTextView;
private IWpfTextView _wpfTextView;
private IWpfTextViewHost _host;
private IEditorOperations _editorOperations;
private IVsEditorAdaptersFactoryService _vsEditorAdaptersFactoryService;
private IEditorOperationsFactoryService _editorOperationsFactoryService;
private System.IServiceProvider _serviceProvider;
private IOleCommandTarget _nextCommandTarget;
public void Initialize(
IVsTextView vsTextView,
IWpfTextView wpfTextView,
IWpfTextViewHost textViewHost,
IVsEditorAdaptersFactoryService editorAdaptersFactory,
IEditorOperationsFactoryService editorOperationsFactoryService,
ITextEditorFactoryService textEditorFactoryService,
ITextBufferFactoryService textBufferFactoryService,
System.IServiceProvider serviceProvider,
IContentType contentType)
{
var buffer = textBufferFactoryService.CreateTextBuffer(contentType);
var view = textEditorFactoryService.CreateTextView(buffer, textEditorFactoryService.AllPredefinedRoles); // DefaultRoles might be ok
var viewHost = textEditorFactoryService.CreateTextViewHost((IWpfTextView)view, setFocus: true).HostControl;
//Control viewHost = textViewHost.HostControl;
_vsTextView = vsTextView;
_wpfTextView = wpfTextView;
_host = textViewHost;
_vsEditorAdaptersFactoryService = editorAdaptersFactory;
_editorOperationsFactoryService = editorOperationsFactoryService;
_serviceProvider = serviceProvider;
InstallCommandFilter();
InitializeEditorControl();
}
private void InitializeEditorControl()
{
//AddLogicalChild(_host.HostControl);
//AddVisualChild(_host.HostControl);
}
private void InstallCommandFilter()
{
//if (_vsEditorAdaptersFactoryService != null)
//{
// _editorOperations = _editorOperationsFactoryService.GetEditorOperations(this._host.TextView);
//}
//ErrorHandler.ThrowOnFailure(this._vsTextView.AddCommandFilter(this, out this._nextCommandTarget));
}
public string GetText() => this._wpfTextView.TextSnapshot.GetText();
/// <summary>
/// Query command status
/// </summary>
/// <param name="pguidCmdGroup">Command group guid</param>
/// <param name="cmdCount">The number of commands in the OLECMD array</param>
/// <param name="prgCmds">The set of command ids</param>
/// <param name="cmdText">Unuses pCmdText</param>
/// <returns>A Microsoft.VisualStudio.OLE.Interop.Constants value</returns>
public int QueryStatus(ref Guid pguidCmdGroup, uint cmdCount, OLECMD[] prgCmds, IntPtr cmdText)
{
// Return status UNKNOWNGROUP if the passed command group is different than the ones we know about
if (pguidCmdGroup != VsMenus.guidStandardCommandSet2K &&
pguidCmdGroup != VsMenus.guidStandardCommandSet97)
{
return (int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_UNKNOWNGROUP;
}
// 1. For the commands we support and don't need to have a custom implementation
// simply ask the next command handler in the filter chain for the command status
// 2. For the commands we have a custom implementation, calculate and return status value
// 3. For other commands, set status to NOTSUPPORTED (0)
for (int i = 0; i < cmdCount; i++)
{
if (this.IsPassThroughCommand(ref pguidCmdGroup, prgCmds[i].cmdID))
{
OLECMD[] cmdArray = new OLECMD[] { new OLECMD() };
cmdArray[0].cmdID = prgCmds[i].cmdID;
int hr = this._nextCommandTarget.QueryStatus(ref pguidCmdGroup, 1, cmdArray, cmdText);
if (ErrorHandler.Failed(hr))
{
continue;
}
prgCmds[i].cmdf = cmdArray[0].cmdf;
}
else if ((pguidCmdGroup == VsMenus.guidStandardCommandSet97 && prgCmds[i].cmdID == StandardCommands.Cut.ID) ||
(pguidCmdGroup == VsMenus.guidStandardCommandSet2K && prgCmds[i].cmdID == (uint)VSConstants.VSStd2KCmdID.CUT) ||
(pguidCmdGroup == VsMenus.guidStandardCommandSet97 && prgCmds[i].cmdID == StandardCommands.Copy.ID) ||
(pguidCmdGroup == VsMenus.guidStandardCommandSet2K && prgCmds[i].cmdID == (uint)VSConstants.VSStd2KCmdID.COPY))
{
prgCmds[i].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED;
//if (this.CanCutCopy())
//{
// prgCmds[i].cmdf |= (uint)OLECMDF.OLECMDF_ENABLED;
//}
}
else if ((pguidCmdGroup == VsMenus.guidStandardCommandSet97 && prgCmds[i].cmdID == StandardCommands.Paste.ID) ||
(pguidCmdGroup == VsMenus.guidStandardCommandSet2K && prgCmds[i].cmdID == (uint)VSConstants.VSStd2KCmdID.PASTE))
{
prgCmds[i].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED;
//if (this.CanPaste())
//{
// prgCmds[i].cmdf |= (uint)OLECMDF.OLECMDF_ENABLED;
//}
}
else
{
prgCmds[i].cmdf = 0;
}
}
return VSConstants.S_OK;
}
/// <summary>
/// Executes the given shell command
/// </summary>
/// <param name="pguidCmdGroup">Command group guid</param>
/// <param name="cmdID">Command id</param>
/// <param name="cmdExecOpt">Options for the executing command</param>
/// <param name="pvaIn">The input arguments structure</param>
/// <param name="pvaOut">The command output structure</param>
/// <returns>Exec return value</returns>
public int Exec(ref Guid pguidCmdGroup, uint cmdID, uint cmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
{
// Return status UNKNOWNGROUP if the passed command group is different than the ones we know about
if (pguidCmdGroup != VsMenus.guidStandardCommandSet2K &&
pguidCmdGroup != VsMenus.guidStandardCommandSet97)
{
return (int)Constants.OLECMDERR_E_UNKNOWNGROUP;
}
int hr = 0;
// 1. For the commands we support and don't need to have a custom implementation
// simply pass the command to the next command handler in the filter chain
// 2. For the commands we have a custom implementation, carry out the command
// don't pass it to the next command handler
// 3. For other commands, simply return with NOTSUPPORTED
if (this.IsPassThroughCommand(ref pguidCmdGroup, cmdID))
{
hr = this._nextCommandTarget.Exec(ref pguidCmdGroup, cmdID, cmdExecOpt, pvaIn, pvaOut);
}
else
{
hr = (int)Constants.OLECMDERR_E_NOTSUPPORTED;
}
return hr;
}
/// <summary>
/// Determines whether the given command should be passed to the
/// next command handler in the text view command filter chain.
/// </summary>
/// <param name="pguidCmdGroup">The command group guid</param>
/// <param name="cmdID">The command id</param>
/// <returns>True, if the command is supported and should be passed to the next command handler</returns>
private bool IsPassThroughCommand(ref Guid pguidCmdGroup, uint cmdID)
{
if (pguidCmdGroup == VsMenus.guidStandardCommandSet2K)
{
switch ((VSConstants.VSStd2KCmdID)cmdID)
{
case VSConstants.VSStd2KCmdID.COMPLETEWORD:
case VSConstants.VSStd2KCmdID.TYPECHAR:
case VSConstants.VSStd2KCmdID.BACKSPACE:
case VSConstants.VSStd2KCmdID.TAB:
case VSConstants.VSStd2KCmdID.BACKTAB:
case VSConstants.VSStd2KCmdID.DELETE:
case VSConstants.VSStd2KCmdID.DELETEWORDRIGHT:
case VSConstants.VSStd2KCmdID.DELETEWORDLEFT:
case VSConstants.VSStd2KCmdID.DELETETOBOL:
case VSConstants.VSStd2KCmdID.DELETETOEOL:
case VSConstants.VSStd2KCmdID.UP:
case VSConstants.VSStd2KCmdID.DOWN:
case VSConstants.VSStd2KCmdID.LEFT:
case VSConstants.VSStd2KCmdID.LEFT_EXT:
case VSConstants.VSStd2KCmdID.LEFT_EXT_COL:
case VSConstants.VSStd2KCmdID.RIGHT:
case VSConstants.VSStd2KCmdID.RIGHT_EXT:
case VSConstants.VSStd2KCmdID.RIGHT_EXT_COL:
case VSConstants.VSStd2KCmdID.EditorLineFirstColumn:
case VSConstants.VSStd2KCmdID.EditorLineFirstColumnExtend:
case VSConstants.VSStd2KCmdID.BOL:
case VSConstants.VSStd2KCmdID.BOL_EXT:
case VSConstants.VSStd2KCmdID.BOL_EXT_COL:
case VSConstants.VSStd2KCmdID.EOL:
case VSConstants.VSStd2KCmdID.EOL_EXT:
case VSConstants.VSStd2KCmdID.EOL_EXT_COL:
case VSConstants.VSStd2KCmdID.SELECTALL:
case VSConstants.VSStd2KCmdID.CANCEL:
case VSConstants.VSStd2KCmdID.WORDPREV:
case VSConstants.VSStd2KCmdID.WORDPREV_EXT:
case VSConstants.VSStd2KCmdID.WORDPREV_EXT_COL:
case VSConstants.VSStd2KCmdID.WORDNEXT:
case VSConstants.VSStd2KCmdID.WORDNEXT_EXT:
case VSConstants.VSStd2KCmdID.WORDNEXT_EXT_COL:
case VSConstants.VSStd2KCmdID.SELECTCURRENTWORD:
case VSConstants.VSStd2KCmdID.TOGGLE_OVERTYPE_MODE:
return true;
}
}
else if (pguidCmdGroup == VsMenus.guidStandardCommandSet97)
{
switch ((VSConstants.VSStd97CmdID)cmdID)
{
case VSConstants.VSStd97CmdID.Delete:
case VSConstants.VSStd97CmdID.SelectAll:
case VSConstants.VSStd97CmdID.Undo:
case VSConstants.VSStd97CmdID.Redo:
return true;
}
}
return false;
}
/// <summary>
/// Return visual child at given index
/// </summary>
/// <param name="index">child index</param>
/// <returns>returns visual child</returns>
// protected override Visual GetVisualChild(int index) => this._host?.HostControl;
// protected override Size ArrangeOverride(Size finalSize)
// {
//// _host.HostControl.Arrange(new Rect(new Point(0, 0), finalSize));
// return finalSize;
// }
// protected override void OnGotFocus(RoutedEventArgs e)
// {
// e.Handled = true;
// this._host.TextView.VisualElement.Focus();
// }
private static DependencyObject TryGetParent(DependencyObject obj)
{
return (obj is Visual) ? VisualTreeHelper.GetParent(obj) : null;
}
private static T GetParentOfType<T>(DependencyObject element) where T : Visual
{
var parent = TryGetParent(element);
if (parent is T)
{
return (T)parent;
}
if (parent == null)
{
return null;
}
return GetParentOfType<T>(parent);
}
internal static void HandleKeyDown(object sender, KeyEventArgs e)
{
var parameterTypeEditorControl = Keyboard.FocusedElement as ParameterTypeEditorControl;
if (parameterTypeEditorControl != null && parameterTypeEditorControl._vsTextView != null)
{
switch (e.Key)
{
case Key.Escape:
case Key.Tab:
case Key.Enter:
e.Handled = true;
break;
default:
// Let the editor control handle the keystrokes
var msg = ComponentDispatcher.CurrentKeyboardMessage;
var oleInteropMsg = new OLE.Interop.MSG();
oleInteropMsg.hwnd = msg.hwnd;
oleInteropMsg.message = (uint)msg.message;
oleInteropMsg.wParam = msg.wParam;
oleInteropMsg.lParam = msg.lParam;
oleInteropMsg.pt.x = msg.pt_x;
oleInteropMsg.pt.y = msg.pt_y;
e.Handled = parameterTypeEditorControl.HandleKeyDown(oleInteropMsg);
break;
}
}
else
{
if (e.Key == Key.Escape)
{
//OnCancel();
}
}
}
private bool HandleKeyDown(OLE.Interop.MSG message)
{
uint editCmdID = 0;
Guid editCmdGuid = Guid.Empty;
int VariantSize = 16;
var filterKeys = Package.GetGlobalService(typeof(SVsFilterKeys)) as IVsFilterKeys2;
if (filterKeys != null)
{
int translated;
int firstKeyOfCombo;
var pMsg = new OLE.Interop.MSG[1];
pMsg[0] = message;
ErrorHandler.ThrowOnFailure(filterKeys.TranslateAcceleratorEx(pMsg,
(uint)(__VSTRANSACCELEXFLAGS.VSTAEXF_NoFireCommand | __VSTRANSACCELEXFLAGS.VSTAEXF_UseTextEditorKBScope | __VSTRANSACCELEXFLAGS.VSTAEXF_AllowModalState),
0,
null,
out editCmdGuid,
out editCmdID,
out translated,
out firstKeyOfCombo));
if (translated == 1)
{
var inArg = IntPtr.Zero;
try
{
// if the command is undo (Ctrl + Z) or redo (Ctrl + Y) then leave it as IntPtr.Zero because of a bug in undomgr.cpp where
// it does undo or redo only for null, VT_BSTR and VT_EMPTY
if ((int)message.wParam != Convert.ToInt32('Z') && (int)message.wParam != Convert.ToInt32('Y'))
{
inArg = Marshal.AllocHGlobal(VariantSize);
Marshal.GetNativeVariantForObject(message.wParam, inArg);
}
return Exec(ref editCmdGuid, editCmdID, 0, inArg, IntPtr.Zero) == VSConstants.S_OK;
}
finally
{
if (inArg != IntPtr.Zero)
Marshal.FreeHGlobal(inArg);
}
}
}
// no translation available for this message
return false;
}
}
}
......@@ -10,13 +10,13 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Editor.Commanding;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Text.Projection;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using ImportingConstructorAttribute = System.Composition.ImportingConstructorAttribute;
......@@ -26,16 +26,15 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
[ExportWorkspaceService(typeof(IChangeSignatureOptionsService), ServiceLayer.Host), Shared]
internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptionsService
{
public const string AddParameterTextViewRole = "AddParameter";
private readonly IClassificationFormatMap _classificationFormatMap;
private readonly ClassificationTypeMap _classificationTypeMap;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
private readonly ITextEditorFactoryService _textEditorFactoryService;
private readonly IServiceProvider _originalServiceProvider;
private readonly IContentType _contentType;
private readonly OLE.Interop.IServiceProvider _serviceProvider;
private readonly ITextBufferFactoryService _textBufferFactoryService;
private readonly IEditorCommandHandlerServiceFactory _editorCommandHandlerServiceFactory;
private readonly IProjectionBufferFactoryService _projectionBufferFactoryService;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
......@@ -44,22 +43,17 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio
ClassificationTypeMap classificationTypeMap,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService,
ITextEditorFactoryService textEditorFactoryService,
IEditorOperationsFactoryService editorOperationsFactoryService,
IContentTypeRegistryService contentTypeRegistryService,
ITextBufferFactoryService textBufferFactoryService,
IEditorCommandHandlerServiceFactory editorCommandHandlerServiceFactory,
IProjectionBufferFactoryService projectionBufferFactoryService,
SVsServiceProvider services)
{
_classificationFormatMap = classificationFormatMapService.GetClassificationFormatMap("tooltip");
_classificationTypeMap = classificationTypeMap;
_editorAdaptersFactoryService = editorAdaptersFactoryService;
_textEditorFactoryService = textEditorFactoryService;
_editorOperationsFactoryService = editorOperationsFactoryService;
_contentType = contentTypeRegistryService.GetContentType(ContentTypeNames.CSharpContentType);
_originalServiceProvider = services;
_editorCommandHandlerServiceFactory = editorCommandHandlerServiceFactory;
_serviceProvider = (OLE.Interop.IServiceProvider)services.GetService(typeof(OLE.Interop.IServiceProvider));
_textBufferFactoryService = textBufferFactoryService;
_projectionBufferFactoryService = projectionBufferFactoryService;
}
public ChangeSignatureOptionsResult GetChangeSignatureOptions(
......@@ -91,18 +85,7 @@ internal class VisualStudioChangeSignatureOptionsService : IChangeSignatureOptio
public AddedParameterResult GetAddedParameter(Document document)
{
// TODO async?
var tuple = GetTextViewAsync(document, CancellationToken.None).Result;
var wpfTextView = _editorAdaptersFactoryService.GetWpfTextView(tuple.Item1);
var viewModel = new AddParameterDialogViewModel();
var dialog = new AddParameterDialog(
viewModel,
_textEditorFactoryService,
_textBufferFactoryService,
_editorCommandHandlerServiceFactory,
_editorOperationsFactoryService,
_contentType);
var (dialog, viewModel) = CreateAddParameterDialogAsync(document, CancellationToken.None).Result;
var result = dialog.ShowModal();
if (result.HasValue && result.Value)
......@@ -122,29 +105,22 @@ public AddedParameterResult GetAddedParameter(Document document)
}
}
private async Task<string> GetDocumentTextAsync(Document document, CancellationToken cancellationToken)
private async Task<(AddParameterDialog, AddParameterDialogViewModel)> CreateAddParameterDialogAsync(
Document document, CancellationToken cancellationToken)
{
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var sourceText = await syntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
return sourceText.ToString();
}
public async Task<(IVsTextView, IWpfTextViewHost)> GetTextViewAsync(Document document, CancellationToken cancellationToken)
{
var documentText = await GetDocumentTextAsync(document, cancellationToken).ConfigureAwait(false);
var documentText = sourceText.ToString();
var roleSet = _textEditorFactoryService.CreateTextViewRoleSet(
PredefinedTextViewRoles.Document,
PredefinedTextViewRoles.Editable,
PredefinedTextViewRoles.Interactive);
var textViewAdapter = _editorAdaptersFactoryService.CreateVsTextViewAdapter(_serviceProvider, roleSet);
var bufferAdapter = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(_serviceProvider, _contentType);
bufferAdapter.InitializeContent(documentText, documentText.Length);
PredefinedTextViewRoles.Interactive,
AddParameterTextViewRole);
// var textBuffer = _vsEditorAdaptersFactoryService.GetDataBuffer(bufferAdapter);
// document.Project.Solution.Workspace.OnDocumentOpened(document.Id, textBuffer.AsTextContainer());
var vsTextView = _editorAdaptersFactoryService.CreateVsTextViewAdapter(_serviceProvider, roleSet);
var vsTextBuffer = _editorAdaptersFactoryService.CreateVsTextBufferAdapter(_serviceProvider, _contentType);
vsTextBuffer.InitializeContent(documentText, documentText.Length);
var initView = new[] {
new INITVIEW()
......@@ -156,15 +132,89 @@ public async Task<(IVsTextView, IWpfTextViewHost)> GetTextViewAsync(Document doc
}
};
textViewAdapter.Initialize(
bufferAdapter as IVsTextLines,
vsTextView.Initialize(
vsTextBuffer as IVsTextLines,
IntPtr.Zero,
(uint)TextViewInitFlags3.VIF_NO_HWND_SUPPORT,
initView);
var textViewHost = _editorAdaptersFactoryService.GetWpfTextViewHost(textViewAdapter);
var wpfTextView = _editorAdaptersFactoryService.GetWpfTextView(vsTextView);
var originalContextBuffer = _editorAdaptersFactoryService.GetDataBuffer(vsTextBuffer);
// Get the workspace, and from there, the solution and document containing this buffer.
// If there's an ExternalSource, we won't get a document. Give up in that case.
var solution = document.Project.Solution;
// Get the appropriate ITrackingSpan for the window the user is typing in
var viewSnapshot = wpfTextView.TextSnapshot;
var debuggerMappedSpan = CreateFullTrackingSpan(viewSnapshot, SpanTrackingMode.EdgeInclusive);
// Wrap the original ContextBuffer in a projection buffer that we can make read-only
var contextBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
new object[] { CreateFullTrackingSpan(originalContextBuffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive) }, ProjectionBufferOptions.None, _contentType);
// Make projection readonly so we can't edit it by mistake.
using (var regionEdit = contextBuffer.CreateReadOnlyRegionEdit())
{
regionEdit.CreateReadOnlyRegion(new Span(0, contextBuffer.CurrentSnapshot.Length), SpanTrackingMode.EdgeInclusive, EdgeInsertionMode.Deny);
regionEdit.Apply();
}
// Adjust the context point to ensure that the right information is in scope.
// For example, we may need to move the point to the end of the last statement in a method body
// in order to be able to access all local variables.
// var contextPoint = contextBuffer.CurrentSnapshot.GetLineFromLineNumber(currentStatementSpan.iEndLine).Start + currentStatementSpan.iEndIndex;
//var adjustedContextPoint = GetAdjustedContextPoint(contextPoint, document);
// Get the previous span/text. We might have to insert another newline or something.
// var previousStatementSpan = GetPreviousStatementBufferAndSpan(adjustedContextPoint, document);
// Build the tracking span that includes the rest of the file
// var restOfFileSpan = CreateTrackingSpanFromIndexToEnd(contextBuffer.CurrentSnapshot, adjustedContextPoint, SpanTrackingMode.EdgePositive);
return (textViewAdapter, textViewHost);
// Put it all into a projection buffer
var projectionBuffer = _projectionBufferFactoryService.CreateProjectionBuffer(null,
new object[] { /* previousStatementSpan, */ debuggerMappedSpan, /* this.StatementTerminator */ /*, restOfFileSpan */}, ProjectionBufferOptions.None, _contentType);
// Fork the solution using this new primary buffer for the document and all of its linked documents.
var forkedSolution = solution.WithDocumentText(document.Id, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
foreach (var link in document.GetLinkedDocumentIds())
{
forkedSolution = forkedSolution.WithDocumentText(link, projectionBuffer.CurrentSnapshot.AsText(), PreservationMode.PreserveIdentity);
}
// Put it into a new workspace, and open it and its related documents
// with the projection buffer as the text.
var workspace = new ChangeSignatureWorkspace(forkedSolution, document.Project);
workspace.OpenDocument(workspace.ChangeSignatureDocumentId, originalContextBuffer.AsTextContainer());
foreach (var link in document.GetLinkedDocumentIds())
{
workspace.OpenDocument(link, projectionBuffer.AsTextContainer());
}
// Start getting the compilation so the PartialSolution will be ready when the user starts typing in the window
await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
wpfTextView.TextBuffer.ChangeContentType(_contentType, null);
var viewModel = new AddParameterDialogViewModel();
var dialog = new AddParameterDialog(
viewModel,
vsTextBuffer,
vsTextView,
wpfTextView);
return (dialog, viewModel);
}
public static ITrackingSpan CreateFullTrackingSpan(ITextSnapshot textSnapshot, SpanTrackingMode trackingMode)
{
return textSnapshot.CreateTrackingSpan(Span.FromBounds(0, textSnapshot.Length), trackingMode);
}
public static ITrackingSpan CreateTrackingSpanFromIndexToEnd(ITextSnapshot textSnapshot, int index, SpanTrackingMode trackingMode)
{
return textSnapshot.CreateTrackingSpan(Span.FromBounds(index, textSnapshot.Length), trackingMode);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册