Get the current filename from a Visual Studio text adornment extension
Asked Answered
H

3

8

I'm new to VS extension development. I'm currently working with the text adornment sample in VS 2015 and have been able to get coloured boxes showing correctly. Now I want to extend the sample so the adornment only appears on certain file names.

Googling has said I can use ITextDocumentFactoryService.TryGetTextDocument interface with the IWpfTextView.TextBuffer property to get a filename. This sounds great. But I can't seem to actually get the interface.

In my class I have:

    [Import]
    public ITextDocumentFactoryService TextDocumentFactoryService = null;

But it is always NULL.

How can I get ITextDocumentFactoryService?

namespace Test
{
    internal sealed class TestAdornment
    {
        [Import]
        public ITextDocumentFactoryService TextDocumentFactoryService = null;

        public TestAdornment(IWpfTextView view)
        {
        }

        /// <summary>
        /// Adds the scarlet box behind the 'a' characters within the given line
        /// </summary>
        /// <param name="line">Line to add the adornments</param>
        private void CreateVisuals(ITextViewLine line)
        {
            // TextDocumentFactoryService is NULL
        }
    }
}
Hudak answered 25/11, 2015 at 11:11 Comment(0)
A
5

TextAdornmentTextViewCreationListener.cs

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornmentTextViewCreationListener : IWpfTextViewCreationListener
{
    [Import]
    public ITextDocumentFactoryService textDocumentFactory { get; set; }

    //...

    public void TextViewCreated(IWpfTextView textView)
    {
        new TextAdornment(textView, textDocumentFactory);
    }
}

TextAdornment.cs

internal sealed class TextAdornment
    {
        private readonly ITextDocumentFactoryService textDocumentFactory;
        private ITextDocument TextDocument;

        //...    

        public TextAdornment(IWpfTextView view, ITextDocumentFactoryService textDocumentFactory)
        {
            //...

            this.textDocumentFactory = textDocumentFactory;

            //...
        }

     internal void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            var res = this.textDocumentFactory.TryGetTextDocument(this.view.TextBuffer, out this.TextDocument);
            if (res)
            {
                //this.TextDocument.FilePath;
            }
            else
            {
                //ERROR
            }
        }
    }
Aldis answered 17/8, 2016 at 12:48 Comment(2)
You should add some explanation.Karlee
Thanks! It worked for me. Is there any way to get path, relative to the project root (solution)?Sukiyaki
S
1

You got it via dependency injection.

As you only submitted 2 lines of code I suppose your context is set up, either explicitly by you, either implicitly by some environment who calls your code.

  • You should declare property instead of field
  • It should be public

Then automagically big brother will set it for you before you first access to it.

...or...

You can use constructor injection instead. Note: It is not you who will create your class.

private readonly ITextDocumentFactoryService _textDocumentFactoryService;

[ImportingConstructor]
internal YourClass(ITextDocumentFactoryService textDocumentFactoryService)
{
    _textDocumentFactoryService = textDocumentFactoryService;
}
Solatium answered 25/11, 2015 at 12:11 Comment(1)
It looks like it is declared properly but it doesn't get set. My member call (CreateVisuals) states that it is null. Therefore my context must not be set up right.Hudak
H
0

So in my case I needed to put the import statement into the AdornmentTextViewCreationListener. This implements IWpfTextViewCreationListener and is the one with the following decorating the class.

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]

Then I can add

private readonly ITextDocumentFactoryService _textDocumentFactoryService;
[ImportingConstructor]

to my class

Hudak answered 25/11, 2015 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.