Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
bf51da3
Update samples for VS 17.9 GA
matteo-prosperi Jan 26, 2024
945c9dd
Update samples for VS 17.10
matteo-prosperi Jan 26, 2024
3bd5960
Update packages
matteo-prosperi Feb 7, 2024
78c6695
Merge branch 'main' into preview_17.10
matteo-prosperi Feb 7, 2024
8b0f186
Update package versions
matteo-prosperi Feb 23, 2024
0e17757
Update packages
matteo-prosperi Feb 28, 2024
798a5dc
Update packages
matteo-prosperi Mar 19, 2024
3ebe89d
Update packages
matteo-prosperi Mar 26, 2024
46ee9e1
Add testing of xaml resources
matteo-prosperi Mar 29, 2024
efe9682
Update packages for 17.11
matteo-prosperi May 9, 2024
16b89f9
Merge remote-tracking branch 'remotes/origin/main' into preview_17.11
matteo-prosperi May 22, 2024
50be2b5
Update packages
matteo-prosperi May 22, 2024
4b8ea58
Update packages to 17.11.232 to remove dependency on ServiceHub.Exten…
BertanAygun Jun 3, 2024
98193af
Add samples for tool window toolbar and context menu
matteo-prosperi Jun 4, 2024
5a55300
Fix
matteo-prosperi Jun 5, 2024
0b648b4
Update usage of Image control
matteo-prosperi Jun 11, 2024
49f6e9c
Updating packages
matteo-prosperi Jun 14, 2024
be0aa2d
Unified getting querySpace and fixed wording
Jxwoon Jun 26, 2024
754e045
Merge pull request #399 from microsoft/dev/jasminewoon/17.11_Updates
Jxwoon Jul 2, 2024
2d1a43b
Update packages
matteo-prosperi Jul 8, 2024
d35d73d
Update packages
matteo-prosperi Jul 9, 2024
ed16717
Avoid warnings
matteo-prosperi Jul 9, 2024
481a824
Fix warnings
matteo-prosperi Jul 9, 2024
7e0956b
Adding a test for settings
matteo-prosperi Jul 9, 2024
d705a3f
Adding a test for the new Image control
matteo-prosperi Jul 9, 2024
0a2e66a
Merge branch 'preview_17.11' into preview_17.12
matteo-prosperi Jul 10, 2024
48ee411
Update packages
matteo-prosperi Jul 10, 2024
e268bc6
Update packages
matteo-prosperi Aug 8, 2024
4232f23
Merge remote-tracking branch 'remotes/origin/main' into preview_17.12
matteo-prosperi Aug 13, 2024
d0f83ee
Update packages
matteo-prosperi Sep 6, 2024
8d87089
Update packages
matteo-prosperi Sep 25, 2024
c66d69f
Merge remote-tracking branch 'remotes/origin/main' into preview_17.12
matteo-prosperi Sep 25, 2024
2b4d75f
Add missing project to solution
matteo-prosperi Sep 25, 2024
6a8cc52
Updating packages
matteo-prosperi Oct 4, 2024
e5a5874
Update packages
matteo-prosperi Oct 11, 2024
a870cfb
CodeLens sample
olegtk Oct 15, 2024
a5b101a
fix typos
olegtk Oct 15, 2024
9a599b8
make custom UI a bit prettier
olegtk Oct 15, 2024
2019c8e
Merge pull request #432 from olegtk/dev/olegtk/CodeLensSample
olegtk Oct 15, 2024
cdec415
Update known issues and experimental changes
Oct 25, 2024
c05f869
Merge pull request #437 from microsoft/dev/tinali/17.12-impactfulchange
tinaschrepfer Oct 25, 2024
66a8769
make CodeLens sample more interactive
olegtk Oct 26, 2024
5895367
Merge pull request #438 from olegtk/dev/olegtk/CodeLensSample3
olegtk Oct 28, 2024
d4c44ba
Update packages
matteo-prosperi Nov 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace CodeLensSample;

using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Editor;

/// <summary>
/// A sample CodeLens provider that provides invokable CodeLens and shows the number of times it has been clicked.
/// </summary>
#pragma warning disable VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
[VisualStudioContribution]
internal class ClickCountCodeLensProvider : ExtensionPart, ICodeLensProvider
{
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(DocumentType.KnownValues.Code),
},
};

#pragma warning disable CEE0027 // String not localized
public CodeLensProviderConfiguration CodeLensProviderConfiguration =>
new("Invokable CodeLens Sample Provider")
{
Priority = 500,
};
#pragma warning restore CEE0027 // String not localized

public Task<CodeLens?> TryCreateCodeLensAsync(CodeElement codeElement, CodeElementContext codeElementContext, CancellationToken token)
{
if (codeElement.Kind == CodeElementKind.KnownValues.Method)
{
return Task.FromResult<CodeLens?>(new ClickableCodeLens(codeElement, this.Extensibility));
}

return Task.FromResult<CodeLens?>(null);
}
}
#pragma warning restore VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace CodeLensSample;

using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Editor;

#pragma warning disable VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
internal class ClickableCodeLens : InvokableCodeLens
{
private readonly CodeElement codeElement;
private readonly VisualStudioExtensibility extensibility;
private int clickCount;

public ClickableCodeLens(CodeElement codeElement, VisualStudioExtensibility extensibility)
{
this.codeElement = codeElement;
this.extensibility = extensibility;
}

public override void Dispose()
{
}

public override Task ExecuteAsync(CodeElementContext codeElementContext, IClientContext clientContext, CancellationToken cancelToken)
{
this.clickCount++;
this.Invalidate();
return Task.CompletedTask;
}

public override Task<CodeLensLabel> GetLabelAsync(CodeElementContext codeElementContext, CancellationToken token)
{
return Task.FromResult(new CodeLensLabel()
{
Text = this.clickCount == 0 ? "Click me" : $"Clicked {this.clickCount} times",
Tooltip = "Invokable CodeLens Sample Tooltip",
});
}
}
#pragma warning restore VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows8.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>12</LangVersion>
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.12.40390" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.12.40390" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="WordCountCodeLensVisual.xaml" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace CodeLensSample;

using Microsoft.VisualStudio.Extensibility;

/// <summary>
/// A sample demonstrating how to extend CodeLens.
/// </summary>
[VisualStudioContribution]
internal class ExtensionEntrypoint : Extension
{
/// <inheritdoc/>
public override ExtensionConfiguration ExtensionConfiguration => new()
{
Metadata = new(
"C43CCA96-C391-42B0-95A5-5B1090909605.CodeLensSample",
this.ExtensionAssemblyVersion,
"Microsoft",
"Codelens Sample",
"Sample extension demonstrating the CodeLens capabilities."),
};
}
137 changes: 137 additions & 0 deletions New_Extensibility_Model/Samples/CodeLensSample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: Code Lens Sample Reference
description: A reference for Code Lens Sample
date: 2023-10-14
---

# Walkthrough: Code Lens Sample

This extension is a sample extension which contributes two Code Lens providers - one that provides clickable Code Lens displaying number of times user clicked on it and another that provides Code Lens displaying the number of words in a method and custom UI displayed when user clicks on the Code Lens. It is a good starting point for learning how to create a Code Lens provider.

## ClickCountCodeLensProvider and ClickableCodeLens

`ClickCountCodeLensProvider` is a part of the extension that provides an invokable Code Lens that allows execution by user clicking on it and indicating number of times it was executed.

`ClickCountCodeLensProvider` utilizes the `AppliesTo` configuration to indicate that it is interested in events from text views whose documents are of `DocumentType.KnownValues.Code`, which are all text based documents containing code.

```csharp
/// <inheritdoc />
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(DocumentType.KnownValues.Code),
},
};
```

`ClickCountCodeLensProvider` utilizes the `CodeLensProviderConfiguration` to declare its display name and that the Code Lens it provides should be placed after other existing Code Lenses with a priority of 500.

```csharp
public CodeLensProviderConfiguration CodeLensProviderConfiguration =>
new("Invokable CodeLens Sample Provider")
{
Priority = 500,
};
```

When requested, `ClickCountCodeLensProvider` provides a `ClickableCodeLens` instance:

```csharp
public Task<CodeLens?> TryCreateCodeLensAsync(CodeElement codeElement, CodeElementContext codeElementContext, CancellationToken token)
{
if (codeElement.Kind == CodeElementKind.KnownValues.Method)
{
return Task.FromResult<CodeLens?>(new ClickableCodeLens(codeElement, this.Extensibility));
}

return Task.FromResult<CodeLens?>(null);
}
```

`ClickableCodeLens` provides `CodeLensLabel` that is being displayed above methods and implements `InvokableCodeLens` abstract class to increment click count on each invocation.
```csharp
public override Task ExecuteAsync(CodeElementContext codeElementContext, IClientContext clientContext, CancellationToken cancelToken)
{
this.clickCount++;
this.Invalidate();
return Task.CompletedTask;
}

public override Task<CodeLensLabel> GetLabelAsync(CodeElementContext codeElementContext, CancellationToken token)
{
return Task.FromResult(new CodeLensLabel()
{
Text = this.clickCount == 0 ? "Click me" : $"Clicked {this.clickCount} times",
Tooltip = "Invokable CodeLens Sample Tooltip",
});
}
```

## WordCountCodeLensProvider and WordCountCodeLens

`WordCountCodeLensProvider` is a part of the extension that provides a visual Code Lens indicating number of words in a method body and that listens for new editor text view creation and changes to open text views to update the word count.

`WordCountCodeLensProvider` utilizes the `AppliesTo` configuration to indicate that it is interested in events from text views whose documents are of `DocumentType.KnownValues.Code`, which are all text based documents containing code.

```csharp
/// <inheritdoc />
public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(DocumentType.KnownValues.Code),
},
};
```

`WordCountCodeLensProvider` utilizes the `CodeLensProviderConfiguration` to declare its display name and that the Code Lens it provides should be placed after other existing Code Lenses with a priority of 500.

```csharp
public CodeLensProviderConfiguration CodeLensProviderConfiguration =>
new("Invokable CodeLens Sample Provider")
{
Priority = 500,
};
```

When requested, `WordCountCodeLensProvider` provides `WordCountCodeLens` instance:

```csharp
public Task<CodeLens?> TryCreateCodeLensAsync(CodeElement codeElement, CodeElementContext codeElementContext, CancellationToken token)
{
if (codeElement.Kind == CodeElementKind.KnownValues.Method || codeElement.Kind.IsOfKind(CodeElementKind.KnownValues.Type))
{
return Task.FromResult<CodeLens?>(new WordCountCodeLens(codeElement, codeElementContext, this.Extensibility, this));
}

return Task.FromResult<CodeLens?>(null);
}
```

`WordCountCodeLens` provides `CodeLensLabel` that is being displayed above methods and implements `VisualCodeLens` to provide custom UI displayed when user clicks on the Code Lens.

```csharp
public override Task<CodeLensLabel> GetLabelAsync(CodeElementContext codeElementContext, CancellationToken token)
{
this.wordCountData.WordCount = CountWords(codeElementContext.Range);
return Task.FromResult(new CodeLensLabel()
{
Text = $"Words: {this.wordCountData.WordCount}",
Tooltip = "Number of words in this code element",
});
}

public override Task<IRemoteUserControl> GetVisualizationAsync(CodeElementContext codeElementContext, IClientContext clientContext, CancellationToken token)
{
return Task.FromResult<IRemoteUserControl>(new WordCountCodeLensVisual(this.wordCountData));
}
```

## Usage

Once deployed, the Code Lens Sample will add two Code Lenses displayed above each method, one that can be clicked and displays the number of times it was clicked and another that displays the number of words in the method and provides custom UI displayed when user clicks on the Code Lens.

## See also

- [Use Editor extensibility](https://learn.microsoft.com/visualstudio/extensibility/visualstudio.extensibility/editor/editor)
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace CodeLensSample;

using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Editor;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;

#pragma warning disable VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
internal class WordCountCodeLens : VisualCodeLens
{
private readonly WordCountData wordCountData;

public WordCountCodeLens(CodeElement codeElement, CodeElementContext codeElementContext, VisualStudioExtensibility extensibility, WordCountCodeLensProvider wordCountCodeLensProvider)
{
this.wordCountData = new WordCountData(this);
this.wordCountData.WordCount = this.CountWords(codeElementContext.Range);
wordCountCodeLensProvider.TextViewChanged += this.OnTextViewChanged;
}

public override void Dispose()
{
}

public override Task<CodeLensLabel> GetLabelAsync(CodeElementContext codeElementContext, CancellationToken token)
{
this.wordCountData.WordCount = this.CountWords(codeElementContext.Range);
return Task.FromResult(new CodeLensLabel()
{
Text = $"Occurrences of \"{this.wordCountData.WordToMatch}\": {this.wordCountData.WordCount}",
Tooltip = "Number of occurrences of a word in the text",
});
}

public override Task<IRemoteUserControl> GetVisualizationAsync(CodeElementContext codeElementContext, IClientContext clientContext, CancellationToken token)
{
return Task.FromResult<IRemoteUserControl>(new WordCountCodeLensVisual(this.wordCountData, this));
}

internal void UpdateWordCount()
{
this.Invalidate();
}

private int CountWords(TextRange range)
{
var rangeText = range.CopyToString();
var wordToMatch = this.wordCountData.WordToMatch;

// Use Regex to find all matches of wordToMatch in rangeText
var matches = Regex.Matches(rangeText, $@"\b{Regex.Escape(wordToMatch)}\b", RegexOptions.IgnoreCase);
return matches.Count;
}

private void OnTextViewChanged(object? sender, TextViewChangedArgs e)
{
this.Invalidate();
}
}
#pragma warning restore VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace CodeLensSample;

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Editor;

/// <summary>
/// A sample CodeLens provider that shows the number of words in a method or type and provides custom UI when clicked.
/// </summary>
#pragma warning disable VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
[VisualStudioContribution]
internal class WordCountCodeLensProvider : ExtensionPart, ICodeLensProvider, ITextViewChangedListener
{
public event EventHandler<TextViewChangedArgs>? TextViewChanged;

public TextViewExtensionConfiguration TextViewExtensionConfiguration => new()
{
AppliesTo = new[]
{
DocumentFilter.FromDocumentType(DocumentType.KnownValues.Code),
},
};

#pragma warning disable CEE0027 // String not localized
public CodeLensProviderConfiguration CodeLensProviderConfiguration =>
new("Remote UI CodeLens Sample Provider")
{
Priority = 600,
};
#pragma warning restore CEE0027 // String not localized

public Task<CodeLens?> TryCreateCodeLensAsync(CodeElement codeElement, CodeElementContext codeElementContext, CancellationToken token)
{
if (codeElement.Kind == CodeElementKind.KnownValues.Method)
{
return Task.FromResult<CodeLens?>(new WordCountCodeLens(codeElement, codeElementContext, this.Extensibility, this));
}

return Task.FromResult<CodeLens?>(null);
}

public Task TextViewChangedAsync(TextViewChangedArgs args, CancellationToken cancellationToken)
{
this.TextViewChanged?.Invoke(this, args);
return Task.CompletedTask;
}
}
#pragma warning restore VSEXTPREVIEW_CODELENS // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Loading