Django Editor in VS 2010 – Part 7 (Code Completion – Source)

Look here for complete source

Ok. This post is the last and, I hope, the shortest and the simplest one in the Django Editor series. All what's left to cover is the source for the code completion part of the NDjango editor.

To continue line of reasoning from the previous post, the code completion source works in very much the same way as the quick info (see posts 4 and 5 of the series). The source provider is registered as an MEF component and creates source objects for text buffers as necessary. Here is the code:

    [Export(typeof(ICompletionSourceProvider))]
    [Name("NDjango Completion Source")]
    [Order(Before = "default")]
    [ContentType(Constants.NDJANGO)]
    internal class SourceProvider : ICompletionSourceProvider
    {
        [Import]
        internal INodeProviderBroker nodeProviderBroker { get; set; }
 
        public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer, IEnvironment environment)
        {
            if (nodeProviderBroker.IsNDjango(textBuffer, environment))
                return new Source();
            return null;
        }
    }

And the source itself is responsible for providing the code completion data:

    internal class Source : ICompletionSource
    {
        public ReadOnlyCollection GetCompletionInformation(ICompletionSession session)
        {
            List completionNodes = session.Properties[typeof(Source)] as List;
            if (completionNodes != null)
            {
                // Calculate the location of the textspan to be replaced with
                // the selection. We always want to replace the entire word
                ITextSnapshot snapshot = session.SubjectBuffer.CurrentSnapshot;
                int triggerPoint = session.TriggerPoint.GetPosition(snapshot);
                ITextSnapshotLine line = snapshot.GetLineFromPosition(triggerPoint);
                string lineString = line.GetText();
                // position of the first non-space character before the tag name
                int start = lineString.Substring(0, triggerPoint - line.Start.Position).
                    LastIndexOfAny(new char[] {' ', '\t', '%'})
                    + line.Start.Position + 1;
                // length of the word currently in the tag name position in the tag
                int length = lineString.Substring(triggerPoint - line.Start.Position).
                    IndexOfAny(new char[] {' ', '\t', '%'} )
                    + triggerPoint - start;
 
                CompletionSet completionSet = new CompletionSet(
                    "ndjango.completions",
                    session.SubjectBuffer.CurrentSnapshot.CreateTrackingSpan(
                    start, length, SpanTrackingMode.EdgeInclusive),
                    CompletionsForNodes(completionNodes),
                    null);
                return new ReadOnlyCollection(new List { completionSet });
            }
 
            return null;
        }
 
        private IEnumerable CompletionsForNodes(IEnumerable nodes)
        {
            foreach (INode node in nodes)
                foreach (string value in node.Values)
                    yield return new Completion(value, value, value);
        }
    }

Even though it is pretty easy to create a custom code completion presenter, I decided against creating my own presenter. And the only thing you need to do to make the standard one work is to feed it with a list of code completion sets in return value of the GetCompletionInformation method. One of the parameters you have to provide when creating your completion set is the tracking span. This tracking span determines what text will be replaced by the value selected by the user from the list of available values.

The rest of the voodoo in the code shown above has to do with calculation of this tracking span as well as building the list of values to show.

And this concludes our discussion of building django editor for Visual Studio 2010. As of the time of this writing I am getting ready to roll out a beta version of the django designer.

Looking back at as the project comes to completion, I can safely say that as planned the project consisted of two parts - extending the django parser for more detailed diagnostics and building the Visual Studio Editor capable of consuming the information. Of course, during the course of the project there were some design challenges. To my pleasant surprise almost all of them were related to the django parser rather than the actual editor code.

When I just started the project after the first look at the VSEditor I was saying that building custom editors in Visual Studio 2010 is a breeze. Now, when the project is at its completion, I still stand by my statement.

P.S. The project is open source, so feel free to browse the source code in the subversion repository. Currently the source code is in the development branch called VS2010Designer. The project is still in development, so there will be changes from the code published in the log. If you are want to look at the code matching exactly the code published in the posts look at the tag I created for this purpose. The tag name is Designer_blog_version. I hope you will find it helpful

2 Responses to “Django Editor in VS 2010 – Part 7 (Code Completion – Source)”

  1. MapPoint 2010 and Streets & Trips 2010 arrive - TECHNOLOGY - TechBlog Says:

    [...] Adventures in programming » Blog Archive » Django Editor in VS ... [...]

  2. Jest Practices: Best Practices for Humor in the Workplace « WETONG Blog Says:

    [...] Adventures in programming » Blog Archive » Django Editor in VS … [...]

Leave a Reply