2
// RazorCodeFragmentState.cs
5
// Piotr Dowgiallo <sparekd@gmail.com>
7
// Copyright (c) 2012 Piotr Dowgiallo
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using MonoDevelop.Xml.StateEngine;
30
using MonoDevelop.AspNet.StateEngine;
31
using MonoDevelop.AspNet.Mvc.Parser;
33
namespace MonoDevelop.AspNet.Mvc.StateEngine
35
public abstract class RazorCodeFragmentState : RazorState
37
protected const int NONE = 0;
38
protected const int BRACKET = 1;
39
protected const int SOLIDUS = 2;
40
protected const int INSIDE_PARENTHESES = 3;
41
protected const int TRANSITION = 4;
42
protected const int MAXCONST = TRANSITION;
45
protected StringBuilder bracketsBuilder;
47
HtmlTagState htmlTagState;
48
HtmlClosingTagState htmlClosingTagState;
49
RazorCommentState razorCommentState;
50
RazorSpeculativeState speculativeState;
51
RazorExpressionState expressionState;
52
RazorCodeBlockState childBlockState;
54
public RazorCodeFragment CorrespondingBlock { get; set; }
55
public bool IsInsideParentheses { get; protected set; }
56
public bool IsInsideGenerics { get; protected set; }
58
public RazorCodeFragmentState ()
59
: this (new HtmlTagState (true), new HtmlClosingTagState (true),
60
new RazorCommentState (), new RazorExpressionState (), new RazorSpeculativeState ())
64
public RazorCodeFragmentState (HtmlTagState html, HtmlClosingTagState htmlClosing,
65
RazorCommentState comment, RazorExpressionState expression, RazorSpeculativeState speculative)
68
htmlClosingTagState = htmlClosing;
69
razorCommentState = comment;
70
expressionState = expression;
71
speculativeState = speculative;
74
Adopt (htmlClosingTagState);
75
Adopt (razorCommentState);
76
Adopt (expressionState);
77
Adopt (speculativeState);
79
bracketsBuilder = new StringBuilder ();
82
public override State PushChar (char c, IParseContext context, ref string rollback)
84
switch (context.StateTag) {
86
if (Char.IsLetter (c)) {
87
rollback = String.Empty;
88
return htmlClosingTagState;
90
context.StateTag = NONE;
94
if (Char.IsLetter (c)) {
95
rollback = String.Empty;
99
context.StateTag = SOLIDUS;
101
context.StateTag = NONE;
105
rollback = String.Empty;
108
return EnsureSetAndAdopted<RazorCodeBlockState> (ref childBlockState);
110
return razorCommentState;
112
return expressionState;
114
if (context.CurrentStateLength <= 2 || (!Char.IsLetterOrDigit (previousChar)
115
&& (Char.IsLetter (c) || c == '_')))
116
return speculativeState;
118
context.StateTag = NONE;
124
case INSIDE_PARENTHESES:
126
context.KeywordBuilder.Append (c);
128
if (context.KeywordBuilder.Length > 0)
129
context.KeywordBuilder.Remove (0, 1);
130
if (context.KeywordBuilder.Length == 0) {
131
context.StateTag = NONE;
132
IsInsideParentheses = false;
140
context.KeywordBuilder.Append (c);
141
context.StateTag = INSIDE_PARENTHESES;
142
IsInsideParentheses = true;
146
if (context.Nodes.Peek () is XElement || !Char.IsLetterOrDigit (previousChar)) {
147
context.StateTag = BRACKET;
148
IsInsideGenerics = false;
150
IsInsideGenerics = true;
154
IsInsideGenerics = false;
158
context.StateTag = TRANSITION;
172
// ParseOpeningBracket and ParseClosingBracket can use simplified method of tracking brackets.
173
// It's fast, and works correctly when parsing char by char, but sometimes may incorrectly determine
174
// the end of a block in nested subblocks when we click inside the block from another one,
175
// because the parent block isn't parsed from end to end then.
176
// The simplified version is used mostly for testing. In real environment finding matching brackets
177
// precisely is necessary for code completion.
179
public virtual State ParseOpeningBracket (char c, IParseContext context)
181
var rootState = RootState as RazorFreeState;
182
if (!rootState.UseSimplifiedBracketTracker && !CorrespondingBlock.FirstBracket.HasValue)
183
CorrespondingBlock.FindFirstBracket (context.Location);
184
else if (rootState.UseSimplifiedBracketTracker)
185
bracketsBuilder.Append (c);
189
public virtual State ParseClosingBracket<T> (char c, IParseContext context, State stateToReturn) where T : XNode
191
bool isEnding = false;
192
var rootState = RootState as RazorFreeState;
193
if (rootState.UseSimplifiedBracketTracker) {
194
if (bracketsBuilder.Length > 0)
195
bracketsBuilder.Remove (0, 1);
196
if (bracketsBuilder.Length == 0)
199
else if (!rootState.UseSimplifiedBracketTracker && CorrespondingBlock.IsEndingBracket (context.LocationMinus (1)))
203
StateEngineService.EndCodeFragment<T> (context);
204
return stateToReturn;