SixPairs

July 20, 2014

SmartTag: UpperCase

Filed under: VS Editor — Ceyhun Ciper @ 11:49

From MSDN:

namespace Ciper
{
  using Microsoft.VisualStudio.Language.Intellisense;
  using Microsoft.VisualStudio.Text;
  using Microsoft.VisualStudio.Text.Editor;
  using Microsoft.VisualStudio.Text.Operations;
  using Microsoft.VisualStudio.Text.Tagging;
  using Microsoft.VisualStudio.Utilities;
  using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.ComponentModel.Composition;
  using System.Windows.Media;
 
  class TestSmartTag : SmartTag
  {
    public TestSmartTag(ReadOnlyCollection<SmartTagActionSet> actionSets) :
      base(SmartTagType.Factoid, actionSets) { }
  }
 
  class TestSmartTagger : ITagger<TestSmartTag>, IDisposable
  {
    private ITextBuffer m_buffer;
    private ITextView m_view;
    private TestSmartTaggerProvider m_provider;
    private bool m_disposed;
 
    public TestSmartTagger(ITextBuffer buffer, ITextView view, TestSmartTaggerProvider provider)
    {
      m_buffer = buffer;
      m_view = view;
      m_provider = provider;
      m_view.LayoutChanged += OnLayoutChanged;
    }
 
    public IEnumerable<ITagSpan<TestSmartTag>> GetTags(NormalizedSnapshotSpanCollection spans)
    {
      ITextSnapshot snapshot = m_buffer.CurrentSnapshot;
      if (snapshot.Length == 0)
        yield break//don't do anything if the buffer is empty 
 
      //set up the navigator
      ITextStructureNavigator navigator = m_provider.NavigatorService.GetTextStructureNavigator(m_buffer);
 
      foreach (var span in spans)
      {
        ITextCaret caret = m_view.Caret;
        SnapshotPoint point;
 
        if (caret.Position.BufferPosition > 0)
          point = caret.Position.BufferPosition - 1;
        else
          yield break;
 
        TextExtent extent = navigator.GetExtentOfWord(point);
        //don't display the tag if the extent has whitespace 
        if (extent.IsSignificant)
          yield return new TagSpan<TestSmartTag>(extent.Span, new TestSmartTag(GetSmartTagActions(extent.Span)));
        else yield break;
      }
    }
 
    private ReadOnlyCollection<SmartTagActionSet> GetSmartTagActions(SnapshotSpan span)
    {
      List<SmartTagActionSet> actionSetList = new List<SmartTagActionSet>();
      List<ISmartTagAction> actionList = new List<ISmartTagAction>();
 
      ITrackingSpan trackingSpan = span.Snapshot.CreateTrackingSpan(span, SpanTrackingMode.EdgeInclusive);
      actionList.Add(new UpperCaseSmartTagAction(trackingSpan));
      SmartTagActionSet actionSet = new SmartTagActionSet(actionList.AsReadOnly());
      actionSetList.Add(actionSet);
      return actionSetList.AsReadOnly();
    }
 
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
 
    private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
      ITextSnapshot snapshot = e.NewSnapshot;
      //don't do anything if this is just a change in case 
      if (!snapshot.GetText().ToLower().Equals(e.OldSnapshot.GetText().ToLower()))
      {
        SnapshotSpan span = new SnapshotSpan(snapshot, new Span(0, snapshot.Length));
        EventHandler<SnapshotSpanEventArgs> handler = this.TagsChanged;
        if (handler != null)
        {
          handler(thisnew SnapshotSpanEventArgs(span));
        }
      }
    }
 
    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }
 
    private void Dispose(bool disposing)
    {
      if (!this.m_disposed)
      {
        if (disposing)
        {
          m_view.LayoutChanged -= OnLayoutChanged;
          m_view = null;
        }
 
        m_disposed = true;
      }
    }
 
  }
 
  [Export(typeof(IViewTaggerProvider))]
  [ContentType("text")]
  [Order(Before = "default")]
  [TagType(typeof(SmartTag))]
  class TestSmartTaggerProvider : IViewTaggerProvider
  {
    [Import(typeof(ITextStructureNavigatorSelectorService))]
    internal ITextStructureNavigatorSelectorService NavigatorService { getset; }
 
    public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
    {
      if (buffer == null || textView == null)
      {
        return null;
      }
 
      //make sure we are tagging only the top buffer 
      if (buffer == textView.TextBuffer)
      {
        return new TestSmartTagger(buffer, textView, thisas ITagger<T>;
      }
      else return null;
    }
  }
 
  class UpperCaseSmartTagAction : ISmartTagAction
  {
    private ITrackingSpan m_span;
    private string m_upper;
    private string m_display;
    private ITextSnapshot m_snapshot;
 
    public UpperCaseSmartTagAction(ITrackingSpan span)
    {
      m_span = span;
      m_snapshot = span.TextBuffer.CurrentSnapshot;
      m_upper = span.GetText(m_snapshot).ToUpper();
      m_display = "Convert to upper case";
    }
 
    public string DisplayText
    {
      get { return m_display; }
    }
    public ImageSource Icon
    {
      get { return null; }
    }
    public bool IsEnabled
    {
      get { return true; }
    }
 
    public ISmartTagSource Source
    {
      get;
      private set;
    }
 
    public ReadOnlyCollection<SmartTagActionSet> ActionSets
    {
      get { return null; }
    }
 
    public void Invoke()
    {
      m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper);
    }
  }
 
}

July 15, 2014

Simpler VS Editor Classifier

Filed under: VS Editor — Ceyhun Ciper @ 20:18
namespace Ciper
{
  using EnvDTE;
  using EnvDTE80;
  using Microsoft.VisualStudio.Language.StandardClassification;
  using Microsoft.VisualStudio.Shell;
  using Microsoft.VisualStudio.Text;
  using Microsoft.VisualStudio.Text.Classification;
  using System;
  using System.ComponentModel.Composition;
 
  [Export(typeof(IClassifierProvider))]
  partial class SimpleClassifier : IClassifierProviderIClassifier
  {
    [Import]
    IClassificationTypeRegistryService classificationTypeRegistry = null;
 
    [Import]
    IStandardClassificationService standardClassifications = null;
 
    [Import]
    SVsServiceProvider serviceProvider = null;
 
    DTE2 dte { get { return (DTE2)serviceProvider.GetService(typeof(DTE)); } }
    OutputWindowPane outputWindowPane { get { return dte.ToolWindows.OutputWindow.ActivePane; } }
 
    public IClassifier GetClassifier(ITextBuffer textBuffer)
    {
      return this;
    }
 
    public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;
  }
}
 
namespace Ciper
{
  using Microsoft.VisualStudio.Text;
  using Microsoft.VisualStudio.Text.Classification;
  using Microsoft.VisualStudio.Utilities;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
  using System.Text.RegularExpressions;
 
  [ContentType("csharp")]
  partial class SimpleClassifier
  {
    [ExportName("kelime")]
    ClassificationTypeDefinition kelime;
 
    public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
    {
      var l = new List<ClassificationSpan>();
      var text = span.GetText();
      foreach (Match m in Regex.Matches(text, @"\w+"))
      {
        var wordSpan = new SnapshotSpan(span.Start + m.Index, m.Length);
        l.Add(new ClassificationSpan(wordSpan, classificationTypeRegistry.GetClassificationType("kelime")));
      }
      return l;
    }
  }
}

Exercises

  1. “// re: ” ile baslayan her comment’in sag tarafini “re sample” olarak classify et.
    namespace Ciper
    {
      using Microsoft.VisualStudio.Text;
      using Microsoft.VisualStudio.Text.Classification;
      using Microsoft.VisualStudio.Utilities;
      using System.Collections.Generic;
      using System.ComponentModel.Composition;
      using System.Text.RegularExpressions;
     
      [ContentType("csharp")]
      partial class SimpleClassifier
      {
        [ExportName("re sample")]
        ClassificationTypeDefinition reSample;
     
        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
        {
          var l = new List<ClassificationSpan>();
          var text = span.GetText();
          foreach (Match m in Regex.Matches(text, @"//\s*re\:?\s*(.+)")) // Dikkat, burada re'yi $ ile bitirme!
          {
            var sampleSpan = new SnapshotSpan(span.Start + m.Groups[1].Index, m.Groups[1].Length);
            l.Add(new ClassificationSpan(sampleSpan, classificationTypeRegistry.GetClassificationType("re sample")));
          }
          return l;
        }
      }
    }
    
  2. IP ve email’leri classify et.
    namespace Ciper
    {
      using Microsoft.VisualStudio.Text;
      using Microsoft.VisualStudio.Text.Classification;
      using Microsoft.VisualStudio.Utilities;
      using System.Collections.Generic;
      using System.ComponentModel.Composition;
      using System.Text.RegularExpressions;
     
      [ContentType("csharp")]
      partial class SimpleClassifier
      {
        [ExportName("ip")]
        ClassificationTypeDefinition ip;
        [ExportName("email")]
        ClassificationTypeDefinition email;
     
        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
        {
          var l = new List<ClassificationSpan>();
          var text = span.GetText();
          foreach (Match m in Regex.Matches(text, @"\d+\.\d+\.\d+\.\d+"))
          {
            var ipSpan = new SnapshotSpan(span.Start + m.Index, m.Length);
            l.Add(new ClassificationSpan(ipSpan, classificationTypeRegistry.GetClassificationType("ip")));
          }
          foreach (Match m in Regex.Matches(text, @"\w+\@\w+\.\w+"))
          {
            var emailSpan = new SnapshotSpan(span.Start + m.Index, m.Length);
            l.Add(new ClassificationSpan(emailSpan, classificationTypeRegistry.GetClassificationType("email")));
          }
          return l;
        }
      }
    }
    

July 10, 2014

Simplest Margin Glyph

Filed under: VS Editor — Ceyhun Ciper @ 05:59
namespace Microsoft.VisualStudio.Text.Editor
{
  using Microsoft.VisualStudio.Text.Formatting;
  using Microsoft.VisualStudio.Text.Tagging;
  using Microsoft.VisualStudio.Utilities;
  using System;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
  using System.Linq;
  using System.Windows;
  using System.Windows.Media;
  using System.Windows.Shapes;
 
  [Export(typeof(IGlyphFactoryProvider))]
  [Name("AGlyph")]
  [Order(After = "VsTextMarker")]
  [ContentType("code")]
  [TagType(typeof(ATag))]
  internal sealed class AGlyphFactory : IGlyphFactoryProviderIGlyphFactory
  {
    public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin)
    {
      return this;
    }
 
    public UIElement GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag)
    {
      if (tag == null || !(tag is ATag)) return null;
      return new Ellipse { Fill = Brushes.Blue, Height = 16, Width = 16 };
    }
  }
 
  internal class ATag : IGlyphTag { }
 
  [Export(typeof(ITaggerProvider))]
  [ContentType("code")]
  [TagType(typeof(ATag))]
  class ATagger : ITaggerProviderITagger<ATag>
  {
    public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
    {
      return this as ITagger<T>;
    }
 
    IEnumerable<ITagSpan<ATag>> ITagger<ATag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
      return
        from span in spans
        where span.GetText().Contains("a")
        select new TagSpan<ATag>(span, new ATag());
    }
 
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
  }
}

ToDo Margin Glyph

Filed under: VS Editor — Ceyhun Ciper @ 02:16

From MSDN…

namespace Microsoft.VisualStudio.Text.Editor
{
  using Microsoft.VisualStudio.Text.Classification;
  using Microsoft.VisualStudio.Text.Formatting;
  using Microsoft.VisualStudio.Text.Tagging;
  using Microsoft.VisualStudio.Utilities;
  using System;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
  using System.Windows;
  using System.Windows.Media;
  using System.Windows.Shapes;
 
  [Export(typeof(IGlyphFactoryProvider))]
  [Name("TodoGlyph")]
  [Order(After = "VsTextMarker")]
  [ContentType("code")]
  [TagType(typeof(TodoTag))]
  internal sealed class TodoGlyphFactoryProvider : IGlyphFactoryProvider
  {
    public IGlyphFactory GetGlyphFactory(IWpfTextView view, IWpfTextViewMargin margin)
    {
      return new TodoGlyphFactory();
    }
  }
 
  internal class TodoGlyphFactory : IGlyphFactory
  {
    public UIElement GenerateGlyph(IWpfTextViewLine line, IGlyphTag tag)
    {
      if (tag == null || !(tag is TodoTag)) return null;
      return new Ellipse { Fill = Brushes.Blue, Height = 16, Width = 16 };
    }
  }
 
  internal class TodoTag : IGlyphTag { }
 
  internal class TodoTagger : ITagger<TodoTag>
  {
    private IClassifier m_classifier;
    private const string m_searchText = "todo";
    internal TodoTagger(IClassifier classifier)
    {
      m_classifier = classifier;
    }
 
    IEnumerable<ITagSpan<TodoTag>> ITagger<TodoTag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
      foreach (SnapshotSpan span in spans)
      {
        //look at each classification span 
        foreach (ClassificationSpan classification in m_classifier.GetClassificationSpans(span))
        {
          //if the classification is a comment 
          if (classification.ClassificationType.Classification.ToLower().Contains("comment"))
          {
            //if the word "todo" is in the comment, create a new TodoTag TagSpan 
            int index = classification.Span.GetText().ToLower().IndexOf(m_searchText);
            if (index != -1)
            {
              yield return new TagSpan<TodoTag>(new SnapshotSpan(classification.Span.Start + index, m_searchText.Length), new TodoTag());
            }
          }
        }
      }
    }
 
    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
  }
 
  [Export(typeof(ITaggerProvider))]
  [ContentType("code")]
  [TagType(typeof(TodoTag))]
  class TodoTaggerProvider : ITaggerProvider
  {
    [Import]
    internal IClassifierAggregatorService AggregatorService { getset; }
 
    public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
    {
      return new TodoTagger(AggregatorService.GetClassifier(buffer)) as ITagger<T>;
    }
  }
}

July 9, 2014

Simplest WpfTextViewCreationListener

Filed under: VS Editor — Ceyhun Ciper @ 17:32
namespace Ciper
{
  using Microsoft.VisualStudio.Text;
  using Microsoft.VisualStudio.Text.Classification;
  using Microsoft.VisualStudio.Text.Editor;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
  using System.Linq;
 
  [Export(typeof(IWpfTextViewCreationListener)), TextViewRole(PredefinedTextViewRoles.Interactive)]
  public partial class WpfTextViewCreationListener : IWpfTextViewCreationListener
  {
    IWpfTextView view;
    IClassifier classifier;
    ITextSnapshot snapshot { get { return view.TextSnapshot; } }
 
    [Import]
    IViewClassifierAggregatorService classifierAggregator { getset; }
 
    SnapshotSpan GetSnapshotSpan()
    {
      return new SnapshotSpan(snapshot, Span.FromBounds(0, snapshot.Length));
    }
 
    IEnumerable<ClassificationSpan> GetClassificationSpans()
    {
      return classifier.GetClassificationSpans(GetSnapshotSpan());
    }
 
    IEnumerable<ClassificationSpan> GetClassificationSpans(string type)
    {
      return GetClassificationSpans().Where(s => s.ClassificationType.IsOfType(type));
    }
 
    public void TextViewCreated(IWpfTextView textView)
    {
      view = textView;
      classifier = classifierAggregator.GetClassifier(view);
    }
  }
}
 
namespace Ciper
{
  using Microsoft.VisualStudio.Utilities;
 
  [ContentType("csharp")]
  partial class WpfTextViewCreationListener
  {
  }
}

July 6, 2014

Simplest Editor TextAdornment

Filed under: VS Editor — Ceyhun Ciper @ 10:31

Add a border around each line.

namespace Microsoft.VisualStudio.Text.Editor
{
  using Microsoft.VisualStudio.Text.Formatting;
  using Microsoft.VisualStudio.Utilities;
  using System.ComponentModel.Composition;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Media;

  [Export(typeof(IWpfTextViewCreationListener))]
  [ContentType("text")]
  [TextViewRole(PredefinedTextViewRoles.Document)]
  internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener
  {
    [Export(typeof(AdornmentLayerDefinition))]
    [Name("TextAdornment1")]
    [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
    public AdornmentLayerDefinition editorAdornmentLayer = null;

    public void TextViewCreated(IWpfTextView textView)
    {
      new TextAdornment1(textView);
    }
  }

  public class TextAdornment1
  {
    IAdornmentLayer layer;
    IWpfTextView view;

    public TextAdornment1(IWpfTextView view)
    {
      this.view = view;
      layer = view.GetAdornmentLayer("TextAdornment1");

      this.view.LayoutChanged += OnLayoutChanged;
    }

    private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
      foreach (ITextViewLine line in e.NewOrReformattedLines)
      {
        this.CreateVisuals(line);
      }
    }

    private void CreateVisuals(ITextViewLine line)
    {
      IWpfTextViewLineCollection textViewLines = view.TextViewLines;

      Geometry g = textViewLines.GetMarkerGeometry(line.Extent);
      if (g != null)
      {
        var border = new Border
        {
          Width = g.Bounds.Width,
          Height = g.Bounds.Height,
          BorderBrush = Brushes.Violet,
          BorderThickness = new Thickness(0.8),
        };

        Canvas.SetLeft(border, g.Bounds.Left);
        Canvas.SetTop(border, g.Bounds.Top);

        layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, line.Extent, null, border, null);
      }
    }
  }
}

Exercises

  1. Add a border around each line, bypassing initial spaces.

    namespace Microsoft.VisualStudio.Text.Editor
    {
      using Microsoft.VisualStudio.Text.Formatting;
      using Microsoft.VisualStudio.Utilities;
      using System.ComponentModel.Composition;
      using System.Text.RegularExpressions;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Media;
    
      [Export(typeof(IWpfTextViewCreationListener))]
      [ContentType("text")]
      [TextViewRole(PredefinedTextViewRoles.Document)]
      internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener
      {
        [Export(typeof(AdornmentLayerDefinition))]
        [Name("TextAdornment1")]
        [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
        public AdornmentLayerDefinition editorAdornmentLayer = null;
    
        public void TextViewCreated(IWpfTextView textView)
        {
          new TextAdornment1(textView);
        }
      }
    
      public class TextAdornment1
      {
        IAdornmentLayer layer;
        IWpfTextView view;
    
        public TextAdornment1(IWpfTextView view)
        {
          this.view = view;
          layer = view.GetAdornmentLayer("TextAdornment1");
    
          this.view.LayoutChanged += OnLayoutChanged;
        }
    
        private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
          foreach (ITextViewLine line in e.NewOrReformattedLines)
          {
            this.CreateVisuals(line);
          }
        }
    
        private void CreateVisuals(ITextViewLine line)
        {
          IWpfTextViewLineCollection textViewLines = view.TextViewLines;
          int start = line.Start;
    
          var m = new Regex(@"\S").Match(line.Extent.GetText());
          if (m.Success) start += m.Index;
          
          var span = new SnapshotSpan(line.Snapshot, Span.FromBounds(start, line.End));
    
          Geometry g = textViewLines.GetMarkerGeometry(span);
          if (g != null)
          {
            var border = new Border
            {
              Width = g.Bounds.Width,
              Height = g.Bounds.Height,
              BorderBrush = Brushes.Violet,
              BorderThickness = new Thickness(0.8),
            };
    
            Canvas.SetLeft(border, g.Bounds.Left);
            Canvas.SetTop(border, g.Bounds.Top);
    
            layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, border, null);
          }
        }
      }
    }
        
  2. Highlight spaces.

    namespace Microsoft.VisualStudio.Text.Editor
    {
      using Microsoft.VisualStudio.Text.Formatting;
      using Microsoft.VisualStudio.Utilities;
      using System.ComponentModel.Composition;
      using System.Text.RegularExpressions;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Media;
    
      [Export(typeof(IWpfTextViewCreationListener))]
      [ContentType("text")]
      [TextViewRole(PredefinedTextViewRoles.Document)]
      internal sealed class TextAdornment1Factory : IWpfTextViewCreationListener
      {
        [Export(typeof(AdornmentLayerDefinition))]
        [Name("TextAdornment1")]
        [Order(After = PredefinedAdornmentLayers.Selection, Before = PredefinedAdornmentLayers.Text)]
        public AdornmentLayerDefinition editorAdornmentLayer = null;
    
        public void TextViewCreated(IWpfTextView textView)
        {
          new TextAdornment1(textView);
        }
      }
    
      public class TextAdornment1
      {
        IAdornmentLayer layer;
        IWpfTextView view;
    
        public TextAdornment1(IWpfTextView view)
        {
          this.view = view;
          layer = view.GetAdornmentLayer("TextAdornment1");
    
          this.view.LayoutChanged += OnLayoutChanged;
        }
    
        private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
          foreach (ITextViewLine line in e.NewOrReformattedLines)
          {
            this.CreateVisuals(line);
          }
        }
    
        private void CreateVisuals(ITextViewLine line)
        {
          IWpfTextViewLineCollection textViewLines = view.TextViewLines;
          int start = line.Start;
          int end = line.End;
    
          for (int i = start; i < end; i++)
          {
            if (line.Snapshot[i] == ' ')
            {
              var span = new SnapshotSpan(line.Snapshot, Span.FromBounds(i, i + 1));
    
              Geometry g = textViewLines.GetMarkerGeometry(span);
              if (g != null)
              {
                var border = new Border
                {
                  Width = g.Bounds.Width,
                  Height = g.Bounds.Height / 8,
                  BorderBrush = Brushes.Black,
                  BorderThickness = new Thickness(0.8, 0, 0.8, 0.8),
                };
    
                Canvas.SetLeft(border, g.Bounds.Left);
                Canvas.SetTop(border, g.Bounds.Bottom - g.Bounds.Height / 8);
    
                layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, border, null);
              }
            }
          }
        }
      }
    }
        
  3. TBD

        
  4. TBD

        

June 30, 2014

Simplest LineTransformSource

Filed under: VS Editor — Ceyhun Ciper @ 17:44
namespace Microsoft.VisualStudio.Text.Formatting
{
  using Microsoft.VisualStudio.Text.Editor;
  using Microsoft.VisualStudio.Utilities;
  using System.ComponentModel.Composition;

  [Export(typeof(ILineTransformSourceProvider))]
  [ContentType("text")]
  [TextViewRole(PredefinedTextViewRoles.Interactive)]
  public partial class LineTransformSource : ILineTransformSourceProvider, ILineTransformSource
  {
    IWpfTextView view;
    public ILineTransformSource Create(IWpfTextView textView)
    {
      this.view = textView;
      return this;
    }

    public LineTransform GetLineTransform(ITextViewLine line, double yPosition, Microsoft.VisualStudio.Text.Editor.ViewRelativePosition placement)
    {
      return GetLineTransform(line);
    }
  }
}

namespace Microsoft.VisualStudio.Text.Formatting
{
  public partial class LineTransformSource
  {
    public LineTransform GetLineTransform(ITextViewLine line)
    {
      return line.DefaultLineTransform;
    }
  }
}

Exercises

  1. Make all lines double-spaced.
    namespace Microsoft.VisualStudio.Text.Formatting
    {
      public partial class LineTransformSource
      {
        public LineTransform GetLineTransform(ITextViewLine line)
        {
          var currentTransform = line.LineTransform;
    
          // line.Height would not work here!
          var transform = new LineTransform(currentTransform.TopSpace, line.TextHeight,
            currentTransform.VerticalScale, currentTransform.Right);
    
          return transform;
        }
      }
    }
    

    Another version:

    namespace Microsoft.VisualStudio.Text.Formatting
    {
      public partial class LineTransformSource
      {
        public LineTransform GetLineTransform(ITextViewLine line)
        {
          var currentTransform = line.LineTransform;
    
          if (line.Change == TextViewLineChange.NewOrReformatted)
            return new LineTransform(currentTransform.TopSpace, line.TextHeight,
              currentTransform.VerticalScale, currentTransform.Right);
          else
            return line.DefaultLineTransform;
        }
      }
    }
    
  2. Sadece brace olan satirlari kucult.
    namespace Microsoft.VisualStudio.Text.Formatting
    {
      public partial class LineTransformSource
      {
        public LineTransform GetLineTransform(ITextViewLine line)
        {
          var s = line.Extent.GetText().Trim();
    
          if (line.Change == TextViewLineChange.NewOrReformatted &&
            (s == "{" || s == "}" || s == "};"))
          {
            return new LineTransform(0.5);
          }
    
          return line.DefaultLineTransform;
        }
      }
    }
    
  3. Collapse empty lines.
    namespace Microsoft.VisualStudio.Text.Formatting
    {
      public partial class LineTransformSource
      {
        public LineTransform GetLineTransform(ITextViewLine line)
        {
          if (string.IsNullOrWhiteSpace(line.Extent.GetText()))
            return new LineTransform(0.001);
          else
            return line.DefaultLineTransform;
        }
      }
    }
    
  4. Comment’li olan satirlari hide et.
    namespace Microsoft.VisualStudio.Text.Formatting
    {
      public partial class LineTransformSource
      {
        public LineTransform GetLineTransform(ITextViewLine line)
        {
          if (System.Text.RegularExpressions.Regex.IsMatch(line.Extent.GetText(), @"\s*//"))
            return new LineTransform(0.001);
          else
            return line.DefaultLineTransform;
        }
      }
    }
    
  5. Selection olan satirlari 1.61 (golden ratio) scale et.
    
    
  6. Caret’in oldugu line’i 1.61 (golden ratio) scale et.
    
    
  7. Satirlarin en sagina line number ekle, ama her number ayni hizada olsun.
  8. Ilk satirdan once copyright goster.
  9. Son satirdan sonra file istatistiklerini goster.

June 10, 2014

Dsl inceleyen Dsl

Filed under: DSL — Ceyhun Ciper @ 07:58

Aslinda daha once MVVM generate etmek icin DSL’leri inceleyip ViewModel’lari create eden bir MVVMGen DSL’i yaratmistim; bunun ilk etabi bir DSL definition’i icindeki tum verileri toparlayip custom bir XML generate etmek olmustu. Ama DSL’leri zaten XML editlememek icin kullanmiyor muyum? Bu nedenle dsl’leri inceleyen bir dsl ihtiyaci hasil oldu.

Ilk yaklasimda MVVMGen sunu yapiyordu:

  1. Bir template ile bir dsl definition’inini analiz et
  2. Belli bir semaya uygun xml datasi gen. et
  3. xml datasindan C# class’lari generate et

1. adim zaten sakat: template’ler (debug edilebilmesine ragmen) pek kolay kullanimli degil; ozellikle intellisense sucks. Bu nedenle dsl designer extension’larina switch ettim. O zaman durum su:

  1. Dsl designer extension’lariyla dsl definition’ini analiz et
  2. Belli bir semaya uygun xml datasi gen. et
  3. xml datasindan C# class’lari generate et

2. adim icin de once bir sema tanimladim, sonra da xml’i buna gore (de)serialize ettim; ama iste burda “niye dsl’leri kullanmiyorum” diye kandime sormaya basladim… Yani dsl’in dsl’i… Ama sadece incelemek icin, yani bir meta-dsl degil. Boylelikle sema falan da yaratmaya veya xsd.exe’yi kullanmaya gerek kalmiyor.

3. adim icin ise template’ler kullanmak yerine Roslyn’i kullanmak daha mantikli.

2. adimin pre-requisite’leri:

  1. Load/save the dsl programmatically (easy)

 

December 1, 2013

GetProjectItemTemplate

Filed under: Uncategorized — Ceyhun Ciper @ 00:05

Getting the “Text Template” template:

var template = <EnvDTE80.Solution2>.GetProjectItemTemplate(“TextTemplate.CSharp.zip”, “CSharp”);

 

August 28, 2013

Hide a ToolWindow at VSShell Startup

Filed under: VSShell — Tags: — Ceyhun Ciper @ 21:29
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using EnvDTE80;

namespace Company.VSPackage1
{
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    [Guid(GuidList.guidVSPackage1PkgString)]
    [ProvideAutoLoad(UIContextGuids80.NoSolution)]
    public sealed class VSPackage1Package : Package, IVsShellPropertyEvents
    {
        private uint m_EventSinkCookie;

        protected override void Initialize()
        {
            base.Initialize();
        
            // Set an event listener for shell property changes
            var shellService = GetService(typeof(SVsShell)) as IVsShell;
            ErrorHandler.ThrowOnFailure(shellService.AdviseShellPropertyChanges(this, out m_EventSinkCookie));
        }

        public int OnShellPropertyChange(int propid, object val)
        {
            // We handle the event if zombie state changes from true to false
            if (propid == (int)__VSSPROPID.VSSPROPID_Zombie)
            {
                if ((bool)val == false)
                {
                    DTE2 dte = GetService(typeof(SDTE)) as DTE2;
                    dte.ExecuteCommand("View.SolutionExplorer");
                    dte.ExecuteCommand("Window.Hide");

                    // Unsubscribe from events
                    var shellService = GetService(typeof(SVsShell)) as IVsShell;
                    ErrorHandler.ThrowOnFailure(shellService.UnadviseShellPropertyChanges(m_EventSinkCookie));
                    m_EventSinkCookie = 0;

                }
            } 
            
            return VSConstants.S_OK;
        }
    }
}

Older Posts »

Blog at WordPress.com.