提交 4fac0edf 编写于 作者: D David Kean

Merge pull request #8229 from diryboy/AddStar

Add "*" on enter pressed within comment blocks
// 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 System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Editor.Implementation.BlockCommentEditing;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.CSharp.BlockCommentEditing
{
[ExportCommandHandler(nameof(BlockCommentEditingCommandHandler), ContentTypeNames.CSharpContentType)]
[Order(After = PredefinedCommandHandlerNames.Completion)]
internal class BlockCommentEditingCommandHandler : AbstractBlockCommentEditingCommandHandler
{
[ImportingConstructor]
public BlockCommentEditingCommandHandler(
ITextUndoHistoryRegistry undoHistoryRegistry,
IEditorOperationsFactoryService editorOperationsFactoryService) : base(undoHistoryRegistry, editorOperationsFactoryService)
{
}
protected override string GetExteriorTextForNextLine(SnapshotPoint caretPosition)
{
var currentLine = caretPosition.GetContainingLine();
var firstNonWhitespacePosition = currentLine.GetFirstNonWhitespacePosition() ?? -1;
if (firstNonWhitespacePosition == -1)
{
return null;
}
var currentLineStartsWithBlockCommentStartString = currentLine.StartsWith(firstNonWhitespacePosition, "/*", ignoreCase: false);
var currentLineStartsWithBlockCommentEndString = currentLine.StartsWith(firstNonWhitespacePosition, "*/", ignoreCase: false);
var currentLineStartsWithBlockCommentMiddleString = currentLine.StartsWith(firstNonWhitespacePosition, "*", ignoreCase: false);
if (!currentLineStartsWithBlockCommentStartString && !currentLineStartsWithBlockCommentMiddleString)
{
return null;
}
if (!IsCaretInsideBlockCommentSyntax(caretPosition))
{
return null;
}
if (currentLineStartsWithBlockCommentStartString)
{
if (BlockCommentEndsRightAfterCaret(caretPosition))
{
// /*|*/
return " ";
}
else if (caretPosition == firstNonWhitespacePosition + 1)
{
// /|*
return null; // The newline inserted could break the syntax in a way that this handler cannot fix, let's leave it.
}
else
{
// /*|
return " *" + GetPaddingOrIndentation(currentLine, caretPosition, firstNonWhitespacePosition, "/*");
}
}
if (currentLineStartsWithBlockCommentEndString)
{
if (BlockCommentEndsRightAfterCaret(caretPosition))
{
// /*
// |*/
return " ";
}
else if (caretPosition == firstNonWhitespacePosition + 1)
{
// *|/
return "*";
}
else
{
// /*
// | */
return " * ";
}
}
if (currentLineStartsWithBlockCommentMiddleString)
{
if (BlockCommentEndsRightAfterCaret(caretPosition))
{
// *|*/
return "";
}
else if (caretPosition > firstNonWhitespacePosition)
{
// *|
return "*" + GetPaddingOrIndentation(currentLine, caretPosition, firstNonWhitespacePosition, "*");
}
else
{
// /*
// | *
return " * ";
}
}
return null;
}
private static bool BlockCommentEndsRightAfterCaret(SnapshotPoint caretPosition)
{
var snapshot = caretPosition.Snapshot;
return ((int)caretPosition + 2 <= snapshot.Length) ? snapshot.GetText(caretPosition, 2) == "*/" : false;
}
private static string GetPaddingOrIndentation(ITextSnapshotLine currentLine, int caretPosition, int firstNonWhitespacePosition, string exteriorText)
{
Debug.Assert(caretPosition >= firstNonWhitespacePosition + exteriorText.Length);
var firstNonWhitespaceOffset = firstNonWhitespacePosition - currentLine.Start;
Debug.Assert(firstNonWhitespaceOffset > -1);
var lineText = currentLine.GetText();
if ((lineText.Length == firstNonWhitespaceOffset + exteriorText.Length))
{
// *|
return " ";
}
var interiorText = lineText.Substring(firstNonWhitespaceOffset + exteriorText.Length);
var interiorFirstNonWhitespaceOffset = interiorText.GetFirstNonWhitespaceOffset() ?? -1;
if (interiorFirstNonWhitespaceOffset == 0)
{
// /****|
return " ";
}
var interiorFirstWhitespacePosition = firstNonWhitespacePosition + exteriorText.Length;
if (interiorFirstNonWhitespaceOffset == -1 || caretPosition <= interiorFirstWhitespacePosition + interiorFirstNonWhitespaceOffset)
{
// * |
// or
// * | 1.
// ^^
return currentLine.Snapshot.GetText(interiorFirstWhitespacePosition, caretPosition - interiorFirstWhitespacePosition);
}
else
{
// * 1. |
// ^^^
return currentLine.Snapshot.GetText(interiorFirstWhitespacePosition, interiorFirstNonWhitespaceOffset);
}
}
private static bool IsCaretInsideBlockCommentSyntax(SnapshotPoint caretPosition)
{
var document = caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
{
return false;
}
var syntaxTree = document.GetSyntaxTreeAsync().WaitAndGetResult(CancellationToken.None);
var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(caretPosition, CancellationToken.None);
return trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia);
}
}
}
......@@ -79,6 +79,7 @@
<Compile Include="AutomaticCompletion\Sessions\LessAndGreaterThanCompletionSession.cs" />
<Compile Include="AutomaticCompletion\Sessions\ParenthesisCompletionSession.cs" />
<Compile Include="AutomaticCompletion\Sessions\StringLiteralCompletionSession.cs" />
<Compile Include="BlockCommentEditing\BlockCommentEditingCommandHandler.cs" />
<Compile Include="BraceMatching\AbstractCSharpBraceMatcher.cs" />
<Compile Include="BraceMatching\LessThanGreaterThanBraceMatcher.cs" />
<Compile Include="BraceMatching\OpenCloseBraceBraceMatcher.cs" />
......
// 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.Tasks;
using Microsoft.CodeAnalysis.Editor.Commands;
using Microsoft.CodeAnalysis.Editor.CSharp.BlockCommentEditing;
using Microsoft.CodeAnalysis.Editor.UnitTests.BlockCommentEditing;
using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.BlockCommentEditing
{
public class BlockCommentEditingTests : AbstractBlockCommentEditingTests
{
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine0()
{
var code = @"
/*$$
";
var expected = @"
/*
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine1()
{
var code = @"
/*$$*/
";
var expected = @"
/*
$$*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine2()
{
var code = @"
/*$$ */
";
var expected = @"
/*
*$$ */
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine3()
{
var code = @"
/* $$ 1.
*/
";
var expected = @"
/*
* $$ 1.
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine4()
{
var code = @"
/* 1.$$
*/
";
var expected = @"
/* 1.
* $$
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine5()
{
var code = @"
/********$$
";
var expected = @"
/********
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine6()
{
var code = @"
/**$$
";
var expected = @"
/**
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine7()
{
var code = @"
/* $$
";
var expected = @"
/*
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task NotInsertOnStartLine0()
{
var code = @"
/$$*
*/
";
var expected = @"
/
$$*
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine0()
{
var code = @"
/*
*$$
";
var expected = @"
/*
*
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine1()
{
var code = @"
/*
*$$*/
";
var expected = @"
/*
*
$$*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine2()
{
var code = @"
/*
*$$ */
";
var expected = @"
/*
*
*$$ */
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine3()
{
var code = @"
/*
* $$ 1.
*/
";
var expected = @"
/*
*
* $$ 1.
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine4()
{
var code = @"
/*
* 1.$$
*/
";
var expected = @"
/*
* 1.
* $$
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine5()
{
var code = @"
/*
* 1.
* $$
*/
";
var expected = @"
/*
* 1.
*
* $$
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine6()
{
var code = @"
/*
$$ *
*/
";
var expected = @"
/*
* $$ *
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine7()
{
var code = @"
/*
*************$$
*/
";
var expected = @"
/*
*************
* $$
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine8()
{
var code = @"
/**
*$$
*/
";
var expected = @"
/**
*
* $$
*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine9()
{
var code = @"
/**
*$$
";
var expected = @"
/**
*
* $$
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnEndLine0()
{
var code = @"
/*
*$$/
";
var expected = @"
/*
*
*$$/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnEndLine1()
{
var code = @"
/**
*$$/
";
var expected = @"
/**
*
*$$/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnEndLine2()
{
var code = @"
/**
*
*$$/
";
var expected = @"
/**
*
*
*$$/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnEndLine3()
{
var code = @"
/*
$$ */
";
var expected = @"
/*
* $$ */
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnEndLine4()
{
var code = @"
/*
$$*/
";
var expected = @"
/*
$$*/
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task NotInsertInVerbatimString0()
{
var code = @"
var code = @""
/*$$
"";
";
var expected = @"
var code = @""
/*
$$
"";
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task NotInsertInVerbatimString1()
{
var code = @"
var code = @""
/*
*$$
"";
";
var expected = @"
var code = @""
/*
*
$$
"";
";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task BoundCheckInsertOnStartLine0()
{
var code = @"
/$$*";
var expected = @"
/
$$*";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task BoundCheckInsertOnStartLine1()
{
var code = @"
/*$$ ";
var expected = @"
/*
*$$ ";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task BoundCheckInsertOnMiddleLine()
{
var code = @"
/*
*$$ ";
var expected = @"
/*
*
*$$ ";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task BoundCheckInsertOnEndLine()
{
var code = @"
/*
*$$/";
var expected = @"
/*
*
*$$/";
await VerifyAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine2_Tab()
{
var code = @"
/*$$<tab>*/
";
var expected = @"
/*
*$$<tab>*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine3_Tab()
{
var code = @"
/*<tab>$$<tab>1.
*/
";
var expected = @"
/*<tab>
*<tab>$$<tab>1.
*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine4_Tab()
{
var code = @"
/* <tab>1.$$
*/
";
var expected = @"
/* <tab>1.
* <tab>$$
*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnStartLine6_Tab()
{
var code = @"
/*<tab>$$
";
var expected = @"
/*<tab>
*<tab>$$
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine2_Tab()
{
var code = @"
/*
*$$<tab>*/
";
var expected = @"
/*
*
*$$<tab>*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine3_Tab()
{
var code = @"
/*
* $$<tab>1.
*/
";
var expected = @"
/*
*
* $$<tab>1.
*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine4_Tab()
{
var code = @"
/*
* <tab>1.$$
*/
";
var expected = @"
/*
* <tab>1.
* <tab>$$
*/
";
await VerifyTabsAsync(code, expected);
}
[WpfFact, Trait(Traits.Feature, Traits.Features.BlockCommentEditing)]
public async Task InsertOnMiddleLine5_Tab()
{
var code = @"
/*
*<tab> 1.
*<tab> $$
*/
";
var expected = @"
/*
*<tab> 1.
*<tab>
*<tab> $$
*/
";
await VerifyTabsAsync(code, expected);
}
protected override Task<TestWorkspace> CreateTestWorkspaceAsync(string initialMarkup) => TestWorkspace.CreateCSharpAsync(initialMarkup);
internal override ICommandHandler<ReturnKeyCommandArgs> CreateCommandHandler(ITextUndoHistoryRegistry undoHistoryRegistry, IEditorOperationsFactoryService editorOperationsFactoryService)
=> new BlockCommentEditingCommandHandler(undoHistoryRegistry, editorOperationsFactoryService);
}
}
......@@ -150,6 +150,7 @@
<Compile Include="AutomaticCompletion\AutomaticLineEnderTests.cs" />
<Compile Include="AutomaticCompletion\AutomaticLiteralCompletionTests.cs" />
<Compile Include="AutomaticCompletion\AutomaticParenthesisCompletionTests.cs" />
<Compile Include="BlockCommentEditing\BlockCommentEditingTests.cs" />
<Compile Include="BraceHighlighting\BraceHighlightingTests.cs" />
<Compile Include="BraceMatching\CSharpBraceMatcherTests.cs" />
<Compile Include="CallHierarchy\CallHierarchyTests.cs" />
......
......@@ -321,6 +321,7 @@
<Compile Include="Implementation\AutomaticCompletion\BraceCompletionSessionProvider.BraceCompletionSession.cs" />
<Compile Include="Implementation\AutomaticCompletion\IEditorBraceCompletionSession.cs" />
<Compile Include="Implementation\AutomaticCompletion\Sessions\AbstractTokenBraceCompletionSession.cs" />
<Compile Include="Implementation\BlockCommentEditing\AbstractBlockCommentEditingCommandHandler.cs" />
<Compile Include="Implementation\BraceMatching\AbstractBraceMatcher.cs" />
<Compile Include="Implementation\BraceMatching\BraceCharacterAndKind.cs" />
<Compile Include="Implementation\BraceMatching\BraceHighlightingViewTaggerProvider.cs" />
......
// 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.Editor.Commands;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.BlockCommentEditing
{
internal abstract class AbstractBlockCommentEditingCommandHandler : ICommandHandler<ReturnKeyCommandArgs>
{
private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
private readonly IEditorOperationsFactoryService _editorOperationsFactoryService;
protected AbstractBlockCommentEditingCommandHandler(
ITextUndoHistoryRegistry undoHistoryRegistry,
IEditorOperationsFactoryService editorOperationsFactoryService)
{
Contract.ThrowIfNull(undoHistoryRegistry);
Contract.ThrowIfNull(editorOperationsFactoryService);
_undoHistoryRegistry = undoHistoryRegistry;
_editorOperationsFactoryService = editorOperationsFactoryService;
}
public CommandState GetCommandState(ReturnKeyCommandArgs args, Func<CommandState> nextHandler) => nextHandler();
public void ExecuteCommand(ReturnKeyCommandArgs args, Action nextHandler)
{
if (TryHandleReturnKey(args))
{
return;
}
nextHandler();
}
private bool TryHandleReturnKey(ReturnKeyCommandArgs args)
{
var subjectBuffer = args.SubjectBuffer;
var textView = args.TextView;
if (!subjectBuffer.GetOption(FeatureOnOffOptions.AutoInsertBlockCommentStartString))
{
return false;
}
var caretPosition = textView.GetCaretPoint(subjectBuffer);
if (caretPosition == null)
{
return false;
}
var exteriorText = GetExteriorTextForNextLine(caretPosition.Value);
if (exteriorText == null)
{
return false;
}
using (var transaction = _undoHistoryRegistry.GetHistory(args.TextView.TextBuffer).CreateTransaction(EditorFeaturesResources.InsertNewLine))
{
var editorOperations = _editorOperationsFactoryService.GetEditorOperations(args.TextView);
editorOperations.InsertNewLine();
editorOperations.InsertText(exteriorText);
transaction.Complete();
return true;
}
}
protected abstract string GetExteriorTextForNextLine(SnapshotPoint caretPosition);
}
}
......@@ -32,6 +32,9 @@ internal static class FeatureOnOffOptions
[ExportOption]
public static readonly PerLanguageOption<bool> AutoXmlDocCommentGeneration = new PerLanguageOption<bool>(OptionName, "Automatic XML Doc Comment Generation", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> AutoInsertBlockCommentStartString = new PerLanguageOption<bool>(OptionName, "Auto Insert Block Comment Start String", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> PrettyListing = new PerLanguageOption<bool>(OptionName, "Pretty List On Line Commit", defaultValue: 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.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Commands;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.BlockCommentEditing
{
public abstract class AbstractBlockCommentEditingTests
{
internal abstract ICommandHandler<ReturnKeyCommandArgs> CreateCommandHandler(
ITextUndoHistoryRegistry undoHistoryRegistry,
IEditorOperationsFactoryService editorOperationsFactoryService);
protected abstract Task<TestWorkspace> CreateTestWorkspaceAsync(string initialMarkup);
protected async Task VerifyAsync(string initialMarkup, string expectedMarkup)
{
using (var workspace = await CreateTestWorkspaceAsync(initialMarkup))
{
var testDocument = workspace.Documents.Single();
var view = testDocument.GetTextView();
view.Caret.MoveTo(new SnapshotPoint(view.TextSnapshot, testDocument.CursorPosition.Value));
var commandHandler = CreateCommandHandler(workspace.GetService<ITextUndoHistoryRegistry>(), workspace.GetService<IEditorOperationsFactoryService>());
var args = new ReturnKeyCommandArgs(view, view.TextBuffer);
var nextHandler = CreateInsertTextHandler(view, "\r\n");
commandHandler.ExecuteCommand(args, nextHandler);
string expectedCode;
int expectedPosition;
MarkupTestFile.GetPosition(expectedMarkup, out expectedCode, out expectedPosition);
Assert.Equal(expectedCode, view.TextSnapshot.GetText());
var caretPosition = view.Caret.Position.BufferPosition.Position;
Assert.True(expectedPosition == caretPosition,
string.Format("Caret positioned incorrectly. Should have been {0}, but was {1}.", expectedPosition, caretPosition));
}
}
protected Task VerifyTabsAsync(string initialMarkup, string expectedMarkup) => VerifyAsync(ReplaceTabTags(initialMarkup), ReplaceTabTags(expectedMarkup));
private string ReplaceTabTags(string markup) => markup.Replace("<tab>", "\t");
private Action CreateInsertTextHandler(ITextView textView, string text)
{
return () =>
{
var caretPosition = textView.Caret.Position.BufferPosition;
var newSpanshot = textView.TextBuffer.Insert(caretPosition, text);
textView.Caret.MoveTo(new SnapshotPoint(newSpanshot, (int)caretPosition + text.Length));
};
}
}
}
......@@ -191,6 +191,7 @@
<Compile Include="Attributes\AttributeTests.cs" />
<Compile Include="AutomaticCompletion\AbstractAutomaticBraceCompletionTests.cs" />
<Compile Include="AutomaticCompletion\AbstractAutomaticLineEnderTests.cs" />
<Compile Include="BlockCommentEditing\AbstractBlockCommentEditingTests.cs" />
<Compile Include="BraceHighlighting\AbstractBraceHighlightingTests.cs" />
<Compile Include="BraceMatching\AbstractBraceMatcherTests.cs" />
<Compile Include="CallHierarchy\CallHierarchyTestState.cs" />
......
......@@ -19,6 +19,7 @@ public static class Features
public const string AsyncLazy = nameof(AsyncLazy);
public const string AutomaticEndConstructCorrection = nameof(AutomaticEndConstructCorrection);
public const string AutomaticCompletion = nameof(AutomaticCompletion);
public const string BlockCommentEditing = nameof(BlockCommentEditing);
public const string BraceHighlighting = nameof(BraceHighlighting);
public const string BraceMatching = nameof(BraceMatching);
public const string CallHierarchy = nameof(CallHierarchy);
......
......@@ -148,7 +148,7 @@ public static int GetLineOffsetFromColumn(this ITextSnapshotLine line, int colum
public static bool StartsWith(this ITextSnapshotLine line, int index, string value, bool ignoreCase)
{
var snapshot = line.Snapshot;
if (index + value.Length >= snapshot.Length)
if (index + value.Length > snapshot.Length)
{
return false;
}
......
......@@ -483,6 +483,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to _Insert * at the start of new lines when writing /* */ comments.
/// </summary>
internal static string Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments {
get {
return ResourceManager.GetString("Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Add new line on enter after end of fully typed word.
/// </summary>
......
......@@ -354,6 +354,9 @@
<data name="Option_Highlighting" xml:space="preserve">
<value>Highlighting</value>
</data>
<data name="Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments" xml:space="preserve">
<value>_Insert * at the start of new lines when writing /* */ comments</value>
</data>
<data name="Option_OptimizeForSolutionSize" xml:space="preserve">
<value>Optimize for solution size</value>
</data>
......
......@@ -34,6 +34,8 @@
<StackPanel>
<CheckBox x:Name="GenerateXmlDocCommentsForTripleSlash"
Content="{x:Static local:AdvancedOptionPageStrings.Option_GenerateXmlDocCommentsForTripleSlash}" />
<CheckBox x:Name="InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments"
Content="{x:Static local:AdvancedOptionPageStrings.Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments}"/>
<CheckBox x:Name="ClosedFileDiagnostics"
Content="{x:Static local:AdvancedOptionPageStrings.Option_ClosedFileDiagnostics}" />
<CheckBox x:Name="RenameTrackingPreview"
......
......@@ -17,6 +17,7 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(EnterOutliningMode, FeatureOnOffOptions.Outlining, LanguageNames.CSharp);
BindToOption(GenerateXmlDocCommentsForTripleSlash, FeatureOnOffOptions.AutoXmlDocCommentGeneration, LanguageNames.CSharp);
BindToOption(InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments, FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp);
BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.CSharp);
BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp);
BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp);
......
......@@ -59,6 +59,11 @@ public static string Option_GenerateXmlDocCommentsForTripleSlash
get { return CSharpVSResources.Option_GenerateXmlDocCommentsForTripleSlash; }
}
public static string Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments
{
get { return CSharpVSResources.Option_InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments; }
}
public static string Option_Highlighting
{
get { return CSharpVSResources.Option_Highlighting; }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册