CodeBlockEndTag is a Visual Studio extension (VSIX) that enhances code readability by adding visual end tags to code blocks enclosed in curly braces { }. These tags display the header or condition of the code block and allow quick navigation by clicking.
- Extension Type: Visual Studio 2017, 2019, and 2022 Extension
- Target Framework: .NET Framework 4.8
- C# Language Version: 14.0
- License: GNU GPL v3
- Author: Khaos66
- Repository: https://github.com/KhaosCoders/VSCodeBlockEndTag
- Marketplace: https://marketplace.visualstudio.com/items?itemName=KhaosPrinz.CodeBlockEndTag
The extension uses a freemium licensing model:
- FREE: C# language support is completely free to use, no restrictions
- PRO: All other languages require a PRO license (yearly subscription)
PRO License Features:
- Unlocks support for all languages (Visual Basic, F#, TypeScript, JavaScript, C++, Python, PowerShell, etc.)
- One-year subscription model
- License activation tied to user's Visual Studio email address
- JWT-based license token stored in user settings
- Automatic expiration date tracking
Purchase & Activation:
- PRO licenses available at:
https://khaoscoders.onfastspring.com/cbe-1y - License key required for activation
- Email address automatically retrieved from Visual Studio settings
- License binding confirmation required before first-time activation
- Activation status displayed in options page with expiration date
The extension includes a Services.LicenseService that manages license validation:
Key Methods:
HasValidProLicense(): Returns whether user has a valid, active PRO licenseGetLicenseExpirationDate(): Returns license expiration date (if available)GetVisualStudioEmail(): Retrieves the user's email from Visual Studio settingsRequireActivatedTokenAsync(key, email): Attempts to re-acquire an already activated license tokenActivateLicenseAsync(key, email): Activates a new license key and binds it to the user's email
License Storage:
- JWT token stored in
CBEOptionPage.LicenseTokenproperty - Persisted to Visual Studio settings via
SaveSettingsToStorage() - Token validated on extension startup and when checking language support
Language support restrictions are enforced at multiple levels:
- Languages without PRO license display with 🔒 [PRO] indicator
- Attempting to enable non-C# languages without PRO shows a modal dialog:
- Message: "This language requires a PRO license.\n\nC# is free to use, but all other languages require a PRO license.\n\nClick 'Buy Pro' to unlock all languages!"
- Checkbox change is prevented (
e.NewValue = CheckState.Unchecked)
- License status displayed with color coding:
- Green: "✓ PRO License Active (Expires: [date])"
- Gray: "No PRO License - C# only"
// In LviLanguages_ItemCheck event handler
var supportedLangs = optionsPage.GetSupportedLanguages();
string langName = supportedLangs[e.Index].Name;
bool isCSharp = langName.Equals(Languages.CSharp, StringComparison.OrdinalIgnoreCase);
// Prevent enabling non-C# languages without PRO license
if (!isCSharp && !Services.LicenseService.HasValidProLicense() && e.NewValue == CheckState.Checked)
{
e.NewValue = CheckState.Unchecked;
// Show dialog...
}The Languages.CSharp constant is used to identify the free language:
- Comparison is case-insensitive
- Always allowed regardless of license status
User Experience:
-
Pre-Purchase Check
- User clicks "Buy Pro" link in options page
- Extension attempts to retrieve Visual Studio email
- If email not found, warns user: "Couldn't read your Microsoft email address from Visual Studio settings. This is required for license activation after you bought a key."
- Browser opens to store URL
-
Activation Process
- User enters license key in text box
- "Activate" button enabled only when key is non-empty
- User clicks "Activate" button
- Button disabled and text changes to "Activating..."
- Email validation performed
- Attempt to re-acquire token if already activated (
RequireActivatedTokenAsync) - If not already activated:
- Confirmation dialog: "This will bind the license key to your email address:\n\n{email}\n\nDo you want to continue?"
- If confirmed, calls
ActivateLicenseAsync(key, email)
- JWT token saved to settings
- Success message shown
- UI refreshed to show active license status
- Language list updated to remove 🔒 indicators
- License key input cleared
-
Error Handling
- Missing email: "Email address is required for license activation."
- Empty key: "Please enter a license key."
- Activation failure: "Activation failed: {exception message}"
- All errors shown as modal dialogs with appropriate icons
Technical Implementation:
private async void BtnActivateLicense_Click(object sender, EventArgs e)
{
// Validate input
// Retrieve email
// Try re-acquiring token first
// If needed, confirm and activate
// Save token to settings
// Refresh UI
// Handle errors
}Options Page UI Elements:
-
lblLicenseStatus: Shows current license state
- With PRO: Green text, checkmark, expiration date
- Without PRO: Gray text, limitation notice
-
lblProInfo: Contextual message
- With PRO: "All features unlocked!"
- Without PRO: "Unlock all features with PRO!"
-
lviLanguages: CheckedListBox with language toggles
- C# always available (no lock icon)
- Other languages show "🔒 [PRO]" suffix when no license
-
txtLicenseKey: TextBox for entering activation key
- TextChanged event enables/disables activation button
-
btnActivateLicense: Button to perform activation
- Async handler for activation process
- UI feedback during activation
-
lnkBuyPro: LinkLabel to store URL
- Pre-validates email before opening browser
The extension automatically:
- Detects closing braces
}in code files - Extracts the corresponding code block header (e.g.,
if (condition),class MyClass,public void Method()) - Displays an inline adornment tag after the closing brace with an appropriate icon and text
- Allows users to click the tag to jump to the block's header
- Intelligently shows/hides tags based on visibility settings and caret position
- Supports customization through Visual Studio options
- Works with all Visual Studio content types that support outlining
The extension now integrates license checking into language support:
-
On Options Page Load:
- Checks
Services.LicenseService.HasValidProLicense() - Adds lock indicators to non-C# languages if no license
- Displays license status and expiration
- Checks
-
On Language Toggle:
- Validates license before allowing non-C# activation
- Shows informative dialog if PRO required
- Prevents checkbox state change for locked languages
-
On License Activation:
- Immediately refreshes language list
- Removes lock indicators
- Updates license status display
- Persists JWT token to settings
-
On Extension Startup (handled in other components):
- Validates stored JWT token
- Applies language restrictions based on license
- May prompt for re-activation if expired
The heart of the extension. Implements ITagger<IntraTextAdornmentTag> to provide inline adornments.
Key responsibilities:
- Uses Visual Studio's outlining/folding regions to identify code blocks
- Extracts headers from collapsible regions
- Manages tag visibility based on caret position and viewport
- Caches adornment tags for performance
- Responds to outlining changes, text buffer changes, and layout changes
Important methods:
GetTagsCore(): Main logic that queries outlining manager for collapsible regions and creates tagsGetHeaderFromRegion(): Extracts the header text from a collapsible region (supports braces, #region, etc.)IsTagVisible(): Determines if a tag should be shown based on visibility mode and caret positionOnTextChanged(): Updates cache when text is editedOnOutliningRegionsChanged(): Responds to folding region changesCaret_PositionChanged(): Hides/shows tags based on caret location
Factory class that creates CBETagger instances. Uses MEF (Managed Extensibility Framework) attributes:
[Export(typeof(IViewTaggerProvider))][ContentType("code")]- Works with all code files[TextViewRole(PredefinedTextViewRoles.Interactive)][TagType(typeof(IntraTextAdornmentTag))]
The main VS Package that manages extension lifecycle and settings.
Key responsibilities:
- Implements
AsyncPackagefor background loading - Provides options page integration
- Manages font and color settings
- Exposes static properties for settings (visibility mode, display mode, click mode, etc.)
- Implements
IVsFontAndColorDefaultsProviderfor custom color categories - Dynamically discovers supported content types from Visual Studio's content type registry
Content Type Discovery:
- Uses
IContentTypeRegistryServiceto enumerate all code-related content types - Filters for types inheriting from "code" base content type
- Builds list of supported languages dynamically at runtime
- Allows enabling/disabling extension per language/content type
WPF control that renders the visual tag. Inherits from ButtonBase.
Features:
- Displays icon, text, or both based on settings
- Handles single-click, double-click, and Ctrl+Click interactions
- Uses dependency properties for data binding
- Fires
TagClickedevent with navigation information
Intelligent icon selection based on code construct type.
Capabilities:
- Parses code headers to identify constructs (class, method, if, for, etc.)
- Detects access modifiers (public, private, protected, internal)
- Maps keywords to appropriate Visual Studio
KnownMonikers - Supports C#, C/C++, and PowerShell keywords
Manages PRO license validation and activation.
Key responsibilities:
- Validates JWT tokens for expiration and authenticity
- Retrieves Visual Studio user email from settings
- Activates new license keys via API call
- Re-acquires tokens for previously activated keys
- Provides license status for UI and enforcement logic
Integration points:
- Called by
CBEOptionPageControlfor UI decisions - Called by language support validation logic
- Token stored in
CBEOptionPage.LicenseToken - Email retrieved from Visual Studio's
IVsShellservice
Struct storing metadata about a code block:
StartPosition: Opening brace positionEndPosition: Closing brace positionHeaderStartPosition: Where the header text beginsAdornment: Reference to the UI element
Struct representing a supported language/content type:
Name: Internal content type name (e.g., "CSharp", "TypeScript")DisplayName: User-friendly display name (e.g., "C#", "TypeScript")
Contains constant for free language identification:
Languages.CSharp: The only language available without PRO license- Used for case-insensitive comparison in license checks
- DisplayModes: Text, Icon, IconAndText
- VisibilityModes: Always, HeaderNotVisible
- ClickMode: SingleClick, DoubleClick, CtrlClick
Dialog page for extension settings with advanced language management:
Settings:
- Enable/disable tagger globally
- Display mode (icon/text/both)
- Visibility mode (always/when header not visible)
- Click mode (single/double/Ctrl+click)
- Margin spacing (pixels between brace and tag)
- Telemetry opt-in/opt-out
- Per-language enable/disable toggles
- LicenseToken: JWT token for PRO license (stored as string)
Language Support Features:
- Dynamic language discovery from VS content type registry
- Persists language settings by name (not position) for better compatibility
- Supports backward compatibility with legacy settings format
- Initializes languages on-demand to avoid startup delays
- Preserves user settings when language list changes between VS versions
Supported Languages (dynamically discovered): C#, Visual Basic, F#, C/C++, JavaScript, TypeScript, Python, PowerShell, XAML, JSON, XML, YAML, HTML, CSS, SCSS, LESS, Razor, T-SQL, and many more—any language with VS outlining support.
License Enforcement:
- C# is always available (free tier)
- All other languages require valid PRO license
- License validation occurs on language toggle attempt
- Settings persist even without license (re-enabled when license activated)
NEW in latest version: Centralized mapping of content type names to user-friendly display names.
Features:
- Static dictionary-based mapping with case-insensitive lookups
- Comprehensive mappings for 50+ content types
- Intelligent fallback for unmapped types (capitalizes, replaces separators)
- Single source of truth for display name logic
- Easily extensible for new content types
Example mappings:
CSharp→C#VisualBasic→Visual BasicFSharpInteractive→F# InteractiveLegacyRazorCoreCSharp→Razor (Legacy C#)html-delegation→HTML (delegation)code-languagesserver-preview→Code Language Server (Preview)
Benefits:
- Consistent display names across the extension
- Easier maintenance and updates
- Better user experience with clear, recognizable language names
- Supports special characters and formatting (e.g., "C#" instead of "CSharp")
- Manages color resource keys per language
- Provides dynamic color lookup for tags
- Registers custom font and color category for tags
- Integrates with VS's Font and Colors settings
- Singleton pattern for color management
- Text Editor Extensibility:
ITextBuffer,ITextSnapshot,ITextView,IWpfTextView - Tagging System:
ITagger<T>,ITagSpan<T>,IntraTextAdornmentTag - Text Structure:
ITextStructureNavigatorfor code navigation - Content Types:
IContentTypeRegistryServicefor dynamic language discovery - MEF: Dependency injection via
[Import]and[Export]attributes - Packages:
AsyncPackage,DialogPagefor options - Font/Color Services:
IVsFontAndColorDefaultsProvider,IVsUIShell2,IVsUIShell5 - Settings:
ShellSettingsManager,WritableSettingsStorefor persistent settings
- CommunityToolkit.HighPerformance: For
PooledStringBuilder(efficient string building) - Microsoft.VisualStudio.SDK: VS extensibility framework
- Community.VisualStudio.Toolkit.17: Helper utilities for VS extensions
- Adornment caching with
Dictionary<AdornmentDataKey, CBAdornmentData> ReadOnlySpan<char>for zero-allocation string parsingPooledStringBuilderfor reduced GC pressure- Visible span tracking to only process visible code
- Incremental cache updates on text changes
- Lazy language initialization (only when options page opened)
- User opens a code file → VS creates an
IWpfTextView - CBETaggerProvider.CreateTagger() is called → Creates a
CBETaggerinstance - CBETagger initializes → Gets
IOutliningManagerfromIOutliningManagerService - VS calls GetTags() with snapshot spans to render
- CBETagger.GetTagsCore() executes:
- Queries
IOutliningManager.GetAllRegions()for collapsible regions - For each
ICollapsibleregion:- Gets region extent (start/end positions)
- Checks if region is multi-line
- Calls
GetHeaderFromRegion()to extract header text - Checks visibility with
IsTagVisible() - Either reuses cached adornment or creates new
CBETagControl - Selects icon via
IconMonikerSelector.SelectMoniker()
- Calls
- Queries
- Returns
TagSpan<IntraTextAdornmentTag>positioned at region end
- VS renders the tags in the editor
- User clicks tag →
TagClickedevent →Adornment_TagClicked()→ Caret jumps to header
Language settings stored as name:value pairs for compatibility across VS versions:
"SupportedLanguages": "CSharp:1,VisualBasic:1,TypeScript:0,..."
Where 1 = enabled, 0 = disabled.
Advantages:
- Resilient to language list reordering
- Compatible when new languages added
- Preserves user preferences across extension updates
- Works across different VS versions with different content types
Original format stored boolean array by position:
"SupportedLangActive": "1,1,0,1,..."
Limitations:
- Breaks when language order changes
- Loses settings when languages added/removed
- Not portable across VS versions
The extension supports both formats, preferring name-based when available.
The extension uses Visual Studio's built-in outlining/folding system to identify code blocks. This approach:
- Works with any language that has outlining support (C#, JavaScript, TypeScript, C++, etc.)
- Automatically handles comments, strings, and language syntax
- Supports not just braces but also
#region, XML comments, and other collapsible constructs - Leverages VS's existing, well-tested code structure analysis
- Brace-based blocks:
if,for,while,class,method, etc. - #region directives: C# regions with custom names
- XML documentation: Collapsible doc comments
- Language-specific: Any construct that VS can fold
When visibility mode is "HeaderNotVisible":
- Tags are hidden if the caret is on the same line as the region end
- Tags are hidden if caret is at the exact end position
- This prevents visual clutter while editing
- Cache key:
(StartPosition, EndPosition)tuple - Cache invalidated on text changes affecting block positions
- Adornments adjusted by delta when text inserted/deleted after them
- Event handlers unsubscribed when adornments removed from cache
On first load of options page:
- Extension queries
IContentTypeRegistryServicefor all registered content types - Filters for types that inherit from "code" base type
- Maps content type names to friendly display names via
ContentTypeDisplayNameMapper - Sorts alphabetically by display name
- Loads user's previous settings (if any)
- Presents unified language list with checkboxes
This approach:
- Adapts to user's installed VS extensions that add new languages
- Doesn't hardcode language list
- Scales automatically with VS updates
- Supports community languages and custom content types
Defines extension metadata:
- Display name, description, version
- Supported VS versions
- Assets (VsPackage)
- Icon and preview image
Auto-generated class with extension constants (ID, name, version, etc.)
The project builds to a .vsix file that can be:
- Installed locally by double-clicking
- Published to Visual Studio Marketplace
- Distributed directly to users
- Basic functionality: Open C# file with nested code blocks, verify tags appear
- Comment handling: Add
}inside comments, verify no tags - Caret interaction: Move caret to closing brace line, verify tag hides (if mode set)
- Click navigation: Click tag, verify jump to header
- Options: Change display mode, visibility mode, click mode in options
- Language toggling: Disable language, verify tags disappear; re-enable, verify tags return
- Settings persistence: Change settings, close VS, reopen, verify settings retained
- New content types: Install extension with new language, verify it appears in options
- Performance: Open large files (>1000 lines), verify smooth scrolling
- Text editing: Add/remove code blocks, verify tags update correctly
License-Related Testing:
-
No License State:
- Verify C# is available and toggleable
- Verify other languages show 🔒 [PRO] indicator
- Attempt to enable non-C# language, verify dialog and prevention
- Verify license status shows "No PRO License - C# only"
-
License Activation:
- Click "Buy Pro", verify email check and browser launch
- Enter invalid key, verify error handling
- Enter valid key, verify activation confirmation dialog
- Cancel confirmation, verify no activation
- Confirm activation, verify success message
- Verify license status updates to show expiration date
- Verify lock indicators removed from language list
- Verify non-C# languages now toggleable
-
Active License State:
- Verify license status shows green with expiration date
- Verify all languages available without restrictions
- Toggle non-C# languages, verify no prompts
-
License Expiration:
- Test with expired JWT token
- Verify falls back to free tier (C# only)
- Verify lock indicators return for non-C# languages
-
Email Handling:
- Test when VS email not available
- Verify warning message before opening store
- Verify activation prevented if email unavailable
-
Settings Persistence:
- Activate license, close VS, reopen
- Verify license token persisted
- Verify language restrictions still apply correctly
The code includes extensive #if DEBUG logging:
- Position tracking
- Visibility decisions
- Tag creation
- Performance timing
License Debugging:
- Log license validation attempts
- Log JWT token parsing (sanitize sensitive data)
- Log email retrieval from VS settings
- Log API calls for activation/re-acquisition
- Additional language support: Automatically supports new languages as VS adds them
- Customizable templates: Allow users to define tag text format
- Color themes: More color customization options per language
- Collapse/expand integration: Sync with folding state
- Annotation support: Allow adding custom notes to tags
- Region naming: Special handling for named #regions
- Localization: Translate display names and UI for international users
- Import/export settings: Share language preferences between machines
License System Enhancements:
- License management UI: View license details, deactivate, transfer
- Offline grace period: Allow temporary use after expiration
- Team licenses: Multi-user license management
- License recovery: Retrieve lost license keys via email
- Trial period: Time-limited full feature access
- Notification system: Warn before expiration, prompt for renewal
- License usage analytics: Track activation success rates (anonymized)
- ContentTypeDisplayNameMapper: Centralized, maintainable display name mapping
- Name-based settings: Robust settings persistence across versions
- Dynamic language discovery: No hardcoded language lists
- Telemetry opt-in: Privacy-respecting usage analytics
- Improved fallback logic: Better display names for unknown content types
- PRO licensing model: Freemium approach with C# free forever
- JWT-based validation: Secure, stateless license verification
- Email binding: Ties licenses to VS user identity
- Re-acquisition support: Seamless license recovery on new machines
- UI integration: Clear status display and restriction enforcement
- Graceful degradation: Falls back to C#-only on license issues
- Requires outlining support for the language (most major languages supported)
- No support for files without outlining enabled
- Performance degrades on extremely large files (>10,000 lines)
- Tag placement depends on VS's outlining region boundaries
- Activation requires internet access (initially)
- Email must be set up in Visual Studio for license binding
- No offline activation or grace period after expiration
- Single-device activation per license key
- Naming: Private fields use
_PascalCase(unusual but consistent in codebase) - Regions: Code organized into
#regionblocks by functionality - Null handling: Uses nullable types (
Span?,int?) and null-conditional operators - Threading: Requires UI thread for VS APIs, uses
ThreadHelper.ThrowIfNotOnUIThread() - Disposal: Proper
IDisposableimplementation with event unsubscription - Static helpers: Utility classes like
ContentTypeDisplayNameMapperare static for performance
License Code Patterns:
- Async/await for activation API calls
- Try-catch-finally for robust error handling
- User confirmation dialogs for binding operations
- Immediate UI feedback during long operations (button text changes)
- Modal dialogs for important notifications
- Color coding for status (green = active, gray = inactive)
Microsoft.VisualStudio.Text.UI.WpfMicrosoft.VisualStudio.Text.LogicMicrosoft.VisualStudio.CoreUtilityMicrosoft.VisualStudio.ImagingMicrosoft.VisualStudio.Shell.15.0
- HTTP client for API communication (if not using built-in)
- JWT parsing library (System.IdentityModel.Tokens.Jwt or similar)
- Visual Studio Shell services for email retrieval
When working on this project:
- Maintain compatibility: Don't break existing user settings
- Performance first: Always profile changes with large files
- Test thoroughly: VS extension bugs are hard to debug in production
- Document complex logic: Especially in
GetTagsCore()andGetCodeBlockHeader() - Preserve cache behavior: Cache invalidation bugs cause major issues
- Follow UI thread rules: Always check thread requirements for VS APIs
- Update version: Increment version in
source.extension.csand manifest - Update display names: Add new languages to
ContentTypeDisplayNameMapper - Test settings migration: Ensure old settings load correctly with new code
License System:
- Never bypass license checks: All language restrictions must be enforced
- Secure token handling: Don't log full JWT tokens, sanitize in debug output
- Clear user messaging: License prompts should be helpful, not annoying
- Graceful failures: License issues shouldn't crash extension
- Privacy conscious: Only collect email with user consent, explain usage
- Test thoroughly: License edge cases (expired, invalid, missing email)
- Store consistency: Keep store URL and messaging aligned
- Update documentation: Document any license flow changes
- Test with nested blocks, empty blocks
{}, and blocks with comments - Verify comment detection doesn't break on edge cases like
*/in strings - Check performance impact—avoid allocations in hot paths
- Maintain cache consistency—ensure positions update correctly
- Check if
CBETagPackageneeds new option properties - Update
CBEOptionPageandCBEOptionPageControlfor UI - Fire
PackageOptionChangedevent when settings change - Test with different Visual Studio themes (Light/Dark/Blue)
- Add telemetry events if appropriate (with user consent)
- Add mapping to
ContentTypeDisplayNameMapper._displayNameMap - Use clear, recognizable display names (e.g., "C#" not "csharp")
- Follow existing naming conventions (e.g., "Language (variant)" for variants)
- Test that the mapping appears correctly in options UI
- Verify fallback logic handles edge cases gracefully
- Enable DEBUG mode to see detailed logging in VS Output window
- Use Activity Log:
%AppData%\Microsoft\VisualStudio\<version>\ActivityLog.xml - Test in VS Experimental Instance (automatically launched during debugging)
- Check for
NullReferenceExceptioninGetTagsCore()(expected when closing editor) - Verify settings persistence in registry:
HKCU\Software\Microsoft\VisualStudio\<version>\CodeBlockEndTag
- Extract reusable logic into static helper classes (like
ContentTypeDisplayNameMapper) - Maintain single responsibility principle
- Keep UI logic separate from business logic
- Use dependency injection (MEF) for testability
- Document public APIs with XML comments
- Always check
Services.LicenseService.HasValidProLicense()before allowing non-C# features - Use
Languages.CSharpconstant for free language identification - Maintain case-insensitive language name comparisons
- Update UI immediately after license state changes
- Handle network failures gracefully during activation
- Never hardcode license keys or bypass checks
- Test with expired tokens to verify fallback behavior
- Ensure email retrieval fails gracefully
- Check license status before enabling for non-C# languages
- Show informative PRO-required messages
- Add visual indicators (🔒 or [PRO] tags) in UI
- Allow feature configuration but prevent execution without license
- Document that feature requires PRO license
- Consider free tier alternatives or limited functionality
- Check Activity Log for license validation failures
- Verify JWT token format and expiration in settings
- Test email retrieval from Visual Studio settings
- Confirm API endpoint availability
- Check for network connectivity issues
- Verify license key format matches expected pattern
- Test activation flow end-to-end with test keys
Solution: Centralized static class with dictionary-based mapping.
Benefits:
- Single source of truth for all display names
- Easy to add new languages (just add dictionary entry)
- Consistent naming across extension
- Testable and maintainable
- Intelligent fallback for unknown types
Problem: Positional array settings broke when language order changed.
Solution: Store settings as "LanguageName:Value" pairs.
Benefits:
- Resilient to language list changes
- Portable across VS versions
- Preserves user intent even when languages added/removed
- Backward compatible with legacy format
Problem: Hardcoded language lists became outdated and didn't support user-installed extensions.
Solution: Query VS content type registry at runtime.
Benefits:
- Automatically supports new languages
- Works with third-party extensions
- No code changes needed for new languages
- Scales with VS ecosystem
- VS SDK Documentation: https://docs.microsoft.com/en-us/visualstudio/extensibility/
- Known Monikers: http://glyphlist.azurewebsites.net/knownmonikers/
- Text Editor Extensibility: https://docs.microsoft.com/en-us/visualstudio/extensibility/inside-the-editor
- Marketplace Publishing: https://marketplace.visualstudio.com/manage
- Content Types: https://docs.microsoft.com/en-us/visualstudio/extensibility/language-service-and-editor-extension-points
This project demonstrates advanced VS extensibility concepts including real-time text parsing, adornment rendering, MEF composition, dynamic content type discovery, and seamless IDE integration.