public DjangoForBlock(BlockParseInfo parseInfo, int inStart, DjangoVariable variable, int argsEnd, int reversedStart, Tuple<string, int>[] definedVars) : base(parseInfo) { InStart = inStart; Variable = variable; ArgsEnd = argsEnd; ReversedStart = reversedStart; _definedVars = definedVars; }
public DjangoForBlock(BlockParseInfo parseInfo, int inStart, DjangoVariable variable, int argsEnd, int reversedStart, Tuple <string, int>[] definedVars) : base(parseInfo) { InStart = inStart; Variable = variable; ArgsEnd = argsEnd; ReversedStart = reversedStart; _definedVars = definedVars; }
public void FilterRegexTests() { var testCases = new[] { new { Got = ("100"), Expected = DjangoVariable.Number("100", 0) }, new { Got = ("100.0"), Expected = DjangoVariable.Number("100.0", 0) }, new { Got = ("+100"), Expected = DjangoVariable.Number("+100", 0) }, new { Got = ("-100"), Expected = DjangoVariable.Number("-100", 0) }, new { Got = ("'fob'"), Expected = DjangoVariable.Constant("'fob'", 0) }, new { Got = ("\"fob\""), Expected = DjangoVariable.Constant("\"fob\"", 0) }, new { Got = ("fob"), Expected = DjangoVariable.Variable("fob", 0) }, new { Got = ("fob.oar"), Expected = DjangoVariable.Variable("fob.oar", 0) }, new { Got = ("fob|oar"), Expected = DjangoVariable.Variable("fob", 0, new DjangoFilter("oar", 4)) }, new { Got = ("fob|oar|baz"), Expected = DjangoVariable.Variable("fob", 0, new DjangoFilter("oar", 4), new DjangoFilter("baz", 8)) }, new { Got = ("fob|oar:'fob'"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Constant("oar", 4, "'fob'", 8)) }, new { Got = ("fob|oar:42"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Number("oar", 4, "42", 8)) }, new { Got = ("fob|oar:\"fob\""), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Constant("oar", 4, "\"fob\"", 8)) }, new { Got = ("fob|oar:100"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Number("oar", 4, "100", 8)) }, new { Got = ("fob|oar:100.0"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Number("oar", 4, "100.0", 8)) }, new { Got = ("fob|oar:+100.0"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Number("oar", 4, "+100.0", 8)) }, new { Got = ("fob|oar:-100.0"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Number("oar", 4, "-100.0", 8)) }, new { Got = ("fob|oar:baz.quox"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Variable("oar", 4, "baz.quox", 8)) }, new { Got = ("fob|oar:baz"), Expected = DjangoVariable.Variable("fob", 0, DjangoFilter.Variable("oar", 4, "baz", 8)) }, new { Got = ("{{ 100 }}"), Expected = DjangoVariable.Number("100", 3) }, new { Got = ("{{ 100.0 }}"), Expected = DjangoVariable.Number("100.0", 3) }, new { Got = ("{{ +100 }}"), Expected = DjangoVariable.Number("+100", 3) }, new { Got = ("{{ -100 }}"), Expected = DjangoVariable.Number("-100", 3) }, new { Got = ("{{ 'fob' }}"), Expected = DjangoVariable.Constant("'fob'", 3) }, new { Got = ("{{ \"fob\" }}"), Expected = DjangoVariable.Constant("\"fob\"", 3) }, new { Got = ("{{ fob }}"), Expected = DjangoVariable.Variable("fob", 3) }, new { Got = ("{{ fob.oar }}"), Expected = DjangoVariable.Variable("fob.oar", 3) }, new { Got = ("{{ fob|oar }}"), Expected = DjangoVariable.Variable("fob", 3, new DjangoFilter("oar", 7)) }, new { Got = ("{{ fob|oar|baz }}"), Expected = DjangoVariable.Variable("fob", 3, new DjangoFilter("oar", 7), new DjangoFilter("baz", 11)) }, new { Got = ("{{ fob|oar:'fob' }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Constant("oar", 7, "'fob'", 11)) }, new { Got = ("{{ fob|oar:42 }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Number("oar", 7, "42", 11)) }, new { Got = ("{{ fob|oar:\"fob\" }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Constant("oar", 7, "\"fob\"", 11)) }, new { Got = ("{{ fob|oar:100 }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Number("oar", 7, "100", 11)) }, new { Got = ("{{ fob|oar:100.0 }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Number("oar", 7, "100.0", 11)) }, new { Got = ("{{ fob|oar:+100.0 }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Number("oar", 7, "+100.0", 11)) }, new { Got = ("{{ fob|oar:-100.0 }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Number("oar", 7, "-100.0", 11)) }, new { Got = ("{{ fob|oar:baz.quox }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Variable("oar", 7, "baz.quox", 11)) }, new { Got = ("{{ fob|oar:baz }}"), Expected = DjangoVariable.Variable("fob", 3, DjangoFilter.Variable("oar", 7, "baz", 11)) }, }; foreach (var testCase in testCases) { Console.WriteLine(testCase.Got); var got = DjangoVariable.Parse(testCase.Got); ValidateFilter(testCase.Expected, got); } }
protected void ClassifyTemplateBody(ITextSnapshot snapshot, List <ClassificationSpan> spans, TemplateRegion region, int prefixLength, int suffixLength) { switch (region.Kind) { case TemplateTokenKind.Comment: spans.Add( new ClassificationSpan( new SnapshotSpan( snapshot, new Span(region.Start + prefixLength, region.Text.Length - (prefixLength + suffixLength)) ), _classifierProvider._commentClassType ) ); break; case TemplateTokenKind.Variable: var filterInfo = DjangoVariable.Parse(region.Text); if (filterInfo != null) { foreach (var curSpan in filterInfo.GetSpans()) { spans.Add(ToClassificationSpan(curSpan, snapshot, region.Start)); } } break; case TemplateTokenKind.Block: var blockInfo = region.Block ?? DjangoBlock.Parse(region.Text); if (blockInfo != null) { foreach (var curSpan in blockInfo.GetSpans()) { spans.Add(ToClassificationSpan(curSpan, snapshot, region.Start)); } } else if (region.Text.Length > (prefixLength + suffixLength)) // unterminated block at end of file { spans.Add( new ClassificationSpan( new SnapshotSpan( snapshot, new Span(region.Start + prefixLength, region.Text.Length - (prefixLength + suffixLength)) ), _classifierProvider._classType ) ); } break; } }
public static DjangoBlock Parse(BlockParseInfo parseInfo) { int start = 0; for (int i = 0; i < parseInfo.Args.Length && parseInfo.Args[i] == ' '; i++, start++) { } var variable = DjangoVariable.Parse( "var|" + parseInfo.Args.Substring(start), parseInfo.Start + start + parseInfo.Command.Length ); return(new DjangoFilterBlock(parseInfo, variable)); }
internal void ValidateFilter(DjangoVariable got, DjangoVariable expected) { Assert.AreEqual(expected.Expression.Value, got.Expression.Value); Assert.AreEqual(expected.Expression.Kind, got.Expression.Kind); Assert.AreEqual(expected.ExpressionStart, got.ExpressionStart); Assert.AreEqual(expected.Filters.Length, got.Filters.Length); for (int i = 0; i < expected.Filters.Length; i++) { if (expected.Filters[i].Arg == null) { Assert.AreEqual(null, got.Filters[i].Arg); } else { Assert.AreEqual(expected.Filters[i].Arg.Value, got.Filters[i].Arg.Value); Assert.AreEqual(expected.Filters[i].Arg.Kind, got.Filters[i].Arg.Kind); Assert.AreEqual(expected.Filters[i].ArgStart, got.Filters[i].ArgStart); } Assert.AreEqual(expected.Filters[i].Filter, got.Filters[i].Filter); } }
protected override void Reparse(string text) { Variable = DjangoVariable.Parse(text); }
/// <param name="kind">The type of template tag we are processing</param> /// <param name="templateText">The text of the template tag which we are offering a completion in</param> /// <param name="templateStart">The offset in the buffer where the template starts</param> /// <param name="triggerPoint">The point in the buffer where the completion was triggered</param> internal CompletionSet GetCompletionSet(CompletionOptions options, VsProjectAnalyzer analyzer, TemplateTokenKind kind, string templateText, int templateStart, SnapshotPoint triggerPoint, out ITrackingSpan applicableSpan) { int position = triggerPoint.Position - templateStart; IEnumerable <CompletionInfo> tags; IDjangoCompletionContext context; applicableSpan = GetWordSpan(templateText, templateStart, triggerPoint); switch (kind) { case TemplateTokenKind.Block: var block = DjangoBlock.Parse(templateText); if (block != null) { if (position <= block.ParseInfo.Start + block.ParseInfo.Command.Length) { // we are completing before the command // TODO: Return a new set of tags? Do nothing? Do this based upon ctrl-space? tags = FilterBlocks(CompletionInfo.ToCompletionInfo(analyzer.GetTags(), StandardGlyphGroup.GlyphKeyword), triggerPoint); } else { // we are in the arguments, let the block handle the completions context = new ProjectBlockCompletionContext(analyzer, _buffer); tags = block.GetCompletions(context, position); } } else { // no tag entered yet, provide the known list of tags. tags = FilterBlocks(CompletionInfo.ToCompletionInfo(analyzer.GetTags(), StandardGlyphGroup.GlyphKeyword), triggerPoint); } break; case TemplateTokenKind.Variable: var variable = DjangoVariable.Parse(templateText); context = new ProjectBlockCompletionContext(analyzer, _buffer); if (variable != null) { tags = variable.GetCompletions(context, position); } else { // show variable names tags = CompletionInfo.ToCompletionInfo(context.Variables, StandardGlyphGroup.GlyphGroupVariable); } break; default: throw new InvalidOperationException(); } var completions = tags .OrderBy(tag => tag.DisplayText, StringComparer.OrdinalIgnoreCase) .Select(tag => new DynamicallyVisibleCompletion( tag.DisplayText, tag.InsertionText, StripDocumentation(tag.Documentation), _glyphService.GetGlyph(tag.Glyph, StandardGlyphItem.GlyphItemPublic), "tag")); return(new FuzzyCompletionSet( "PythonDjangoTags", Resources.DjangoTagsCompletionSetDisplayName, applicableSpan, completions, options, CompletionComparer.UnderscoresLast)); }
public static DjangoForBlock Parse(BlockParseInfo parseInfo) { var words = parseInfo.Args.Split(' '); int inStart = -1; int inOffset = 0, inIndex = -1; var definitions = new List <Tuple <string, int> >(); for (int i = 0; i < words.Length; i++) { var word = words[i]; if (word == "in") { inStart = inOffset + parseInfo.Start + parseInfo.Command.Length; inIndex = i; break; } else if (words[i].IndexOfAny(NewLines) != -1) { // unterminated tag break; } if (!String.IsNullOrEmpty(word)) { definitions.Add(new Tuple <string, int>(word, inOffset + parseInfo.Start + parseInfo.Command.Length)); } inOffset += words[i].Length + 1; } // parse the arguments... int reversedStart = -1; DjangoVariable variable = null; int argsEnd = -1; if (inIndex != -1) { string filterText = ""; argsEnd = inStart + "in".Length + 1; for (int i = inIndex + 1; i < words.Length; i++) { int nlStart = words[i].IndexOfAny(NewLines); string trimmed = words[i]; if (nlStart != -1) { trimmed = words[i].Substring(0, nlStart); } if (i != inIndex + 1 && trimmed == words[i]) // if we trimmed we don't have an extra space { filterText += " "; argsEnd += 1; } if (trimmed == "reversed") { reversedStart = argsEnd; break; } filterText += trimmed; argsEnd += trimmed.Length; if (trimmed != words[i]) { // unterminated tag break; } } var trimmedFilter = filterText.TrimStart(' '); variable = DjangoVariable.Parse(trimmedFilter, inStart + "in".Length + 1 + filterText.Length - trimmedFilter.Length); } return(new DjangoForBlock(parseInfo, inStart, variable, argsEnd, reversedStart, definitions.ToArray())); }
public void BlockParserTests() { var testCases = new[] { new { Got = ("for x in "), Expected = (DjangoBlock) new DjangoForBlock(new BlockParseInfo("for", "x in ", 0), 6, null, 9, -1, new[] { new Tuple <string, int>("x", 4) }), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 9, Expected = new[] { "fob", "oar" } }, new { Position = 4, Expected = new string[0] } } }, new { Got = ("for x in oar"), Expected = (DjangoBlock) new DjangoForBlock(new BlockParseInfo("for", "x in oar", 0), 6, DjangoVariable.Variable("oar", 9), 12, -1, new[] { new Tuple <string, int>("x", 4) }), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 9, Expected = new[] { "fob", "oar" } }, new { Position = 4, Expected = new string[0] } } }, new { Got = ("for x in b"), Expected = (DjangoBlock) new DjangoForBlock(new BlockParseInfo("for", "x in b", 0), 6, DjangoVariable.Variable("b", 9), 10, -1, new[] { new Tuple <string, int>("x", 4) }), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 10, Expected = new [] { "fob", "oar" } }, new { Position = 4, Expected = new string[0] } } }, new { Got = ("autoescape"), Expected = (DjangoBlock) new DjangoAutoEscapeBlock(new BlockParseInfo("autoescape", "", 0), -1, -1), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 10, Expected = new[] { "on", "off" } } } }, new { Got = ("autoescape on"), Expected = (DjangoBlock) new DjangoAutoEscapeBlock(new BlockParseInfo("autoescape", " on", 0), 11, 2), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 10, Expected = new string[0] } } }, new { Got = ("comment"), Expected = (DjangoBlock) new DjangoArgumentlessBlock(new BlockParseInfo("comment", "", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 0, Expected = new string[0] } } }, new { Got = ("spaceless"), Expected = (DjangoBlock) new DjangoSpacelessBlock(new BlockParseInfo("spaceless", "", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 0, Expected = new string[0] } } }, new { Got = ("filter "), Expected = (DjangoBlock) new DjangoFilterBlock(new BlockParseInfo("filter", " ", 0), DjangoVariable.Variable("", 7)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 7, Expected = new [] { "cut", "lower" } } } }, new { Got = ("ifequal "), Expected = (DjangoBlock) new DjangoIfOrIfNotEqualBlock(new BlockParseInfo("ifequal", " ", 0), DjangoVariable.Variable("", 8)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 8, Expected = new [] { "fob", "oar" } } } }, new { Got = ("ifequal fob "), Expected = (DjangoBlock) new DjangoIfOrIfNotEqualBlock(new BlockParseInfo("ifequal", " fob ", 0), DjangoVariable.Variable("fob", 8)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 12, Expected = new [] { "fob", "oar" } } } }, new { Got = ("if "), Expected = (DjangoBlock) new DjangoIfBlock(new BlockParseInfo("if", " ", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 3, Expected = new [] { "fob", "oar", "not" } } } }, new { Got = ("if fob "), Expected = (DjangoBlock) new DjangoIfBlock(new BlockParseInfo("if", " fob ", 0), new BlockClassification(new Span(3, 3), Classification.Identifier)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 7, Expected = new [] { "and", "or" } } } }, new { Got = ("if fob and "), Expected = (DjangoBlock) new DjangoIfBlock(new BlockParseInfo("if", " fob and ", 0), new BlockClassification(new Span(3, 3), Classification.Identifier), new BlockClassification(new Span(7, 3), Classification.Keyword)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 11, Expected = new [] { "fob", "oar", "not" } } } }, new { Got = ("firstof "), Expected = (DjangoBlock) new DjangoMultiVariableArgumentBlock(new BlockParseInfo("firstof", " ", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 8, Expected = new [] { "fob", "oar" } } } }, new { Got = ("firstof fob|"), Expected = (DjangoBlock) new DjangoMultiVariableArgumentBlock(new BlockParseInfo("firstof", " fob|", 0), DjangoVariable.Variable("fob", 8)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 12, Expected = new [] { "cut", "lower" } } } }, new { Got = ("spaceless "), Expected = (DjangoBlock) new DjangoSpacelessBlock(new BlockParseInfo("spaceless", " ", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 10, Expected = new string[0] } } }, new { Got = ("widthratio "), Expected = (DjangoBlock) new DjangoWidthRatioBlock(new BlockParseInfo("widthratio", " ", 0)), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 11, Expected = new [] { "fob", "oar" } } } }, new { Got = ("templatetag "), Expected = (DjangoBlock) new DjangoTemplateTagBlock(new BlockParseInfo("templatetag", " ", 0), 11, null), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 11, Expected = new [] { "openblock", "closeblock", "openvariable", "closevariable", "openbrace", "closebrace", "opencomment", "closecomment" } } } }, new { Got = ("templatetag open"), Expected = (DjangoBlock) new DjangoTemplateTagBlock(new BlockParseInfo("templatetag", " open", 0), 11, null), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 15, Expected = new [] { "openblock", "openvariable", "openbrace", "opencomment" } } } }, new { Got = ("templatetag openblock "), Expected = (DjangoBlock) new DjangoTemplateTagBlock(new BlockParseInfo("templatetag", " openblock ", 0), 11, "openblock"), Context = TestCompletionContext.Simple, Completions = new[] { new { Position = 22, Expected = new string[0] } } }, }; foreach (var testCase in testCases) { Console.WriteLine(testCase.Got); var got = DjangoBlock.Parse(testCase.Got); ValidateBlock(testCase.Expected, got); foreach (var completionCase in testCase.Completions) { var completions = new HashSet <string>(got.GetCompletions(testCase.Context, completionCase.Position).Select(x => x.DisplayText)); Assert.AreEqual(completionCase.Expected.Length, completions.Count); var expected = new HashSet <string>(completionCase.Expected); foreach (var value in completions) { Assert.IsTrue(expected.Contains(value)); } } } }
public DjangoFilterBlock(BlockParseInfo parseInfo, DjangoVariable variable) : base(parseInfo) { _variable = variable; }
protected static IEnumerable<CompletionInfo> GetCompletions(IDjangoCompletionContext context, int position, DjangoVariable[] variables, int max = Int32.MaxValue) { for (int i = 0; i < variables.Length; i++) { if (position >= variables[i].ExpressionStart && (i == variables.Length - 1 || position < variables[i + 1].ExpressionStart)) { var res = variables[i].GetCompletions(context, position); if (res.Count() != 0) { return res; } } } if (variables.Length < max) { var vars = context.Variables; if (vars != null) { return CompletionInfo.ToCompletionInfo(vars.Keys, StandardGlyphGroup.GlyphGroupField); } } return new CompletionInfo[0]; }