private static bool NeedAutoinsertCloseBracket(CachingLexer lexer) { using (LexerStateCookie.Create(lexer)) { TokenNodeType typedToken = lexer.TokenType; // find the leftmost non-closed bracket (including typed) of typed class so that there are no opened brackets of other type var bracketMatcher = new PsiBracketMatcher(); TokenNodeType tokenType = typedToken; int leftParenthPos = lexer.CurrentPosition; do { if (tokenType == typedToken && bracketMatcher.IsStackEmpty()) { leftParenthPos = lexer.CurrentPosition; } else if (!bracketMatcher.ProceedStack(tokenType)) { break; } lexer.Advance(-1); } while ((tokenType = lexer.TokenType) != null); // Try to find the matched pair bracket lexer.CurrentPosition = leftParenthPos; return(!bracketMatcher.FindMatchingBracket(lexer)); } }
public virtual IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { TreeTextRange oldRange = this.GetTreeTextRange(); Logger.Assert(changedRange.ContainedIn(oldRange), "The condition “changedRange.ContainedIn(oldRange)” is false."); int newLength = oldRange.Length - changedRange.Length + insertedTextLen; // Find starting comment if (!cachingLexer.FindTokenAt(oldRange.StartOffset.Offset) || cachingLexer.TokenType != this.GetTokenType() || cachingLexer.TokenStart != oldRange.StartOffset.Offset || cachingLexer.TokenEnd != oldRange.StartOffset.Offset + newLength) { return(null); } var element = TreeElementFactory.CreateLeafElement( cachingLexer.TokenType, new ProjectedBuffer( cachingLexer.Buffer, new TextRange(cachingLexer.TokenStart, cachingLexer.TokenStart + newLength)), 0, newLength); var comment = element as Comment; if (comment == null || this.CommentType != comment.CommentType) { return(null); } return(comment); }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { TreeOffset currStartOffset = GetTreeStartOffset(); int currLength = GetTextLength(); Logger.Assert(changedRange.StartOffset >= currStartOffset && changedRange.EndOffset <= (currStartOffset + currLength), "changedRange.StartOffset >= currStartOffset && changedRange.EndOffset <= (currStartOffset+currLength)"); int newLength = currLength - changedRange.Length + insertedTextLen; LanguageService languageService = Language.LanguageService(); if (languageService != null) { var parser = (IPsiParser)languageService.CreateParser(new ProjectedLexer(cachingLexer, new TextRange(currStartOffset.Offset, currStartOffset.Offset + newLength)), GetPsiModule(), GetSourceFile()); TreeElement newElement = parser.ParseStatement(); if (newElement.GetTextLength() == 0) { return(null); } if ((newElement.GetTextLength() == newLength) && (";".Equals(newElement.GetText().Substring(newElement.GetTextLength() - 1)))) { var psiFile = GetContainingNode <PsiFile>(); if (psiFile != null) { psiFile.ClearTables(); } return(newElement as IRuleDeclaration); } } return(null); }
private bool HandleLeftBraceTyped(ITypingContext typingContext) { ITextControl textControl = typingContext.TextControl; using (CommandProcessor.UsingCommand("Smart LBRACE")) { typingContext.CallNext(); // check if typed char is a token int charPos = TextControlToLexer(textControl, textControl.Caret.Offset() - 1); CachingLexer lexer = GetCachingLexer(textControl); if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos) { return(true); } if (NeedAutoinsertCloseBracket(lexer)) { if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(true); } AutoinsertRBrace(textControl, lexer); int position = charPos + 1; if (position >= 0) { textControl.Caret.MoveTo(position, CaretVisualPlacement.DontScrollIfVisible); } } } return(true); }
private bool IsAtValidStartToken(CachingLexer cachingLexer) { // Make sure the current token is one we can start resyncing from. A body node can start with practically anything // so the best we can do is make sure there are no significant tokens before us - i.e. the only preceding tokens // should be whitespace, new lines, comment and document or directive end var tokenBuffer = cachingLexer.TokenBuffer; for (var i = cachingLexer.CurrentPosition - 1; i >= 0; i--) { var token = tokenBuffer[i]; // Start of buffer, start of document, end of previous document if (token.Type == null || token.Type == YamlTokenType.DIRECTIVES_END || token.Type == YamlTokenType.DOCUMENT_END) { return(true); } if (!token.Type.IsComment && !token.Type.IsWhitespace) { return(false); } } return(true); }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { var currentStartOffset = GetTreeStartOffset(); var currentLength = GetTextLength(); Assertion.Assert( changedRange.StartOffset >= currentStartOffset && changedRange.EndOffset <= currentStartOffset + currentLength, "changedRange.StartOffset >= currentStartOffset && changedRange.EndOffset <= (currentStartOffset+currentLength)"); var newLength = currentLength - changedRange.Length + insertedTextLen; // Can we resync from the start point? if (!cachingLexer.FindTokenAt(currentStartOffset.Offset) || cachingLexer.TokenStart != currentStartOffset.Offset || !IsAtValidStartToken(cachingLexer)) { return(null); } // Try to find a valid end point TokenNodeType tokenType; var calculatedNewLength = 0; while ((tokenType = cachingLexer.TokenType) != null && (calculatedNewLength += cachingLexer.TokenEnd - cachingLexer.TokenStart) < newLength) { // We shouldn't encounter these until the end of the changed range if (tokenType == YamlTokenType.DOCUMENT_END || tokenType == YamlTokenType.DIRECTIVES_END) { return(null); } cachingLexer.Advance(); } if (calculatedNewLength != newLength || !IsAtValidEndToken(cachingLexer)) { return(null); } // TODO: Should this be synchronised? // The C# implementation isn't... if (!myOpened) { var buffer = ProjectedBuffer.Create(cachingLexer.Buffer, new TextRange(currentStartOffset.Offset, currentStartOffset.Offset + newLength)); var closedChameleon = new ClosedChameleonElement(YamlTokenType.CHAMELEON, buffer, TreeOffset.Zero, new TreeOffset(buffer.Length)); return(new ChameleonDocumentBody(closedChameleon)); } var projectedLexer = new ProjectedLexer(cachingLexer, new TextRange(currentStartOffset.Offset, currentStartOffset.Offset + newLength)); var parser = (IYamlParser)Language.LanguageService().CreateParser(projectedLexer, GetPsiModule(), GetSourceFile()); var openedChameleon = parser.ParseDocumentBody(); return(new ChameleonDocumentBody(openedChameleon)); }
/// <summary> /// When a " is typed, insert another ". /// </summary> private bool OnQuoteTyped(ITypingContext context) { ITextControl textControl = context.TextControl; // the " character should be skipped to avoid double insertions if (_skippingTypingAssist.ShouldSkip(textControl.Document, context.Char)) { _skippingTypingAssist.SkipIfNeeded(textControl.Document, context.Char); return(true); } // get the token type after " CachingLexer cachingLexer = GetCachingLexer(textControl); int offset = textControl.Selection.OneDocRangeWithCaret().GetMinOffset(); if (cachingLexer == null || offset <= 0 || !cachingLexer.FindTokenAt(offset)) { return(false); } // there is already another quote after the ", swallow the typing TokenNodeType tokenType = cachingLexer.TokenType; if (tokenType == T4TokenNodeTypes.Quote) { textControl.Caret.MoveTo(offset + 1, CaretVisualPlacement.DontScrollIfVisible); return(true); } // we're inside or after an attribute value, simply do nothing and let the " be typed if (tokenType == T4TokenNodeTypes.Value) { return(false); } // insert the first " TextControlUtil.DeleteSelection(textControl); textControl.FillVirtualSpaceUntilCaret(); textControl.Document.InsertText(offset, "\""); // insert the second " context.QueueCommand(() => { using (CommandProcessor.UsingCommand("Inserting \"")) { textControl.Document.InsertText(offset + 1, "\""); textControl.Caret.MoveTo(offset + 1, CaretVisualPlacement.DontScrollIfVisible); } // ignore if a subsequent " is typed by the user _skippingTypingAssist.SetCharsToSkip(textControl.Document, "\""); // popup auto completion _codeCompletionSessionManager.ExecuteAutoCompletion <T4AutopopupSettingsKey>(textControl, Solution, key => key.InDirectives); }); return(true); }
private bool HandleColonTyped(ITypingContext typingContext) { ITextControl textControl = typingContext.TextControl; if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(false); } using (CommandProcessor.UsingCommand("Smart :")) { TextControlUtil.DeleteSelection(textControl); textControl.FillVirtualSpaceUntilCaret(); int charPos = TextControlToLexer(textControl, textControl.Caret.Offset()); CachingLexer lexer = GetCachingLexer(textControl); if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos || lexer.TokenType != PsiTokenType.COLON) { typingContext.CallNext(); } else { int position = charPos + 1; if (position < 0) { return(true); } textControl.Caret.MoveTo(position, CaretVisualPlacement.DontScrollIfVisible); } if (NeedAutoinsertSemicolon(textControl)) { if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(true); } char c = typingContext.Char; int insertPos = charPos; if (insertPos >= 0) { textControl.Document.InsertText(insertPos + 1, ";"); textControl.Caret.MoveTo(insertPos + 1, CaretVisualPlacement.DontScrollIfVisible); } // format statement if (GetTypingAssistOption(textControl, TypingAssistOptions.FormatStatementOnSemicolonExpression)) { DoFormatStatementOnColon(textControl); } } return(true); } }
// smart backspaces expecteed that GetExtraStub return not null value, "foo " is typical value protected override string GetExtraStub(CachingLexer lexer, int offset) { using (LexerStateCookie.Create(lexer)) { lexer.FindTokenAt(offset); if (!(lexer.TokenType is CppTokenNodeType)) { return("foo "); } } return(base.GetExtraStub(lexer, offset)); }
private bool FindCgContent(ITextControl textControl, out CachingLexer lexer) { var offset = textControl.Caret.DocumentOffset().Offset; // base is important here! lexer = base.GetCachingLexer(textControl); if (lexer == null || !lexer.FindTokenAt(offset)) { return(false); } return(true); }
private bool HandleLeftBracketOrParenthTyped(ITypingContext typingContext) { ITextControl textControl = typingContext.TextControl; using (CommandProcessor.UsingCommand("Smart " + typingContext.Char)) { typingContext.CallNext(); using (WriteLockCookie.Create()) { // check if typed char is a token CachingLexer lexer = GetCachingLexer(textControl); int charPos = TextControlToLexer(textControl, textControl.Caret.Offset() - 1); if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos) { return(true); } if (lexer.TokenType != PsiTokenType.LBRACKET && lexer.TokenType != PsiTokenType.LPARENTH) { return(true); } // check that next token is good one TokenNodeType nextTokenType = lexer.LookaheadToken(1); if (nextTokenType != null && nextTokenType != PsiTokenType.WHITE_SPACE && nextTokenType != PsiTokenType.NEW_LINE && nextTokenType != PsiTokenType.C_STYLE_COMMENT && nextTokenType != PsiTokenType.END_OF_LINE_COMMENT && nextTokenType != PsiTokenType.SEMICOLON && nextTokenType != PsiTokenType.RBRACKET && nextTokenType != PsiTokenType.RBRACE && nextTokenType != PsiTokenType.RPARENTH) { return(true); } if (NeedAutoinsertCloseBracket(lexer)) { if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(true); } char c = typingContext.Char; int insertPos = charPos; if (insertPos >= 0) { textControl.Document.InsertText(insertPos + 1, c == '(' ? ")" : c == '[' ? "]" : "}"); textControl.Caret.MoveTo(insertPos + 1, CaretVisualPlacement.DontScrollIfVisible); } } } } return(true); }
private bool ShouldIgnoreCaretPosition(ITextControl textControl, out CachingLexer lexer) { var offset = textControl.Caret.DocumentOffset().Offset; // base is important here! lexer = base.GetCachingLexer(textControl); if (lexer == null || !lexer.FindTokenAt(offset)) { return(true); } // inside HLSL program return(lexer.TokenType is CppTokenNodeType); }
/// <summary>When = is typed, insert "".</summary> private bool OnEqualTyped(ITypingContext context) { ITextControl textControl = context.TextControl; // get the token type before = CachingLexer cachingLexer = GetCachingLexer(textControl); int offset = textControl.Selection.OneDocRangeWithCaret().GetMinOffset(); if (cachingLexer == null || offset <= 0 || !cachingLexer.FindTokenAt(offset - 1)) { return(false); } // do nothing if we're not after an attribute name TokenNodeType tokenType = cachingLexer.TokenType; if (tokenType != T4TokenNodeTypes.TOKEN) { return(false); } // insert = textControl.Selection.Delete(); textControl.FillVirtualSpaceUntilCaret(); textControl.Document.InsertText(offset, "="); textControl.Caret.MoveTo(offset + 1, CaretVisualPlacement.DontScrollIfVisible); // insert "" context.QueueCommand(() => { using (CommandProcessor.UsingCommand("Inserting \"\"")) { textControl.Document.InsertText(offset + 1, "\"\""); textControl.Caret.MoveTo(offset + 2, CaretVisualPlacement.DontScrollIfVisible); } // ignore if a subsequent " is typed by the user SkippingTypingAssist.SetCharsToSkip(textControl.Document, "\""); // popup auto completion _codeCompletionSessionManager.ExecuteAutoCompletion <T4AutopopupSettingsKey>(textControl, Solution, key => key.InDirectives); }); return(true); }
private TextRange FixRange(int startOffset, int endOffset, [CanBeNull] string logicalName, IBuffer buffer, CachingLexer lexer) { // todo: remove when visualfsharp#3920 is implemented // trim foo.``bar`` to ``bar`` const int minimumEscapedNameLength = 5; if (endOffset >= minimumEscapedNameLength && buffer.Length >= minimumEscapedNameLength && buffer[endOffset - 1] == '`' && buffer[endOffset - 2] == '`') { for (var i = endOffset - 4; i >= startOffset; i--) { if (buffer[i] == '`' && buffer[i + 1] == '`') { return(new TextRange(i, endOffset)); } } } if (logicalName != null && PrettyNaming.IsMangledOpName(logicalName)) { var sourceName = PrettyNaming.DecompileOpName.Invoke(logicalName); if (sourceName.Length == endOffset - startOffset) { return(new TextRange(startOffset, endOffset)); } // todo: use lexer buffer if (lexer.FindTokenAt(endOffset - 1) && lexer.TokenType is TokenNodeType tokenType) { var opText = tokenType == FSharpTokenType.SYMBOLIC_OP ? sourceName : logicalName; return(new TextRange(endOffset - opText.Length, endOffset)); } } // trim foo.bar to bar for (var i = endOffset - 1; i > startOffset; i--) { if (buffer[i].Equals('.')) { return(new TextRange(i + 1, endOffset)); } } return(new TextRange(startOffset, endOffset)); }
public override string CalculateInjectionIndent(CachingLexer lexer, ITextControl textControl) { var offset = textControl.Caret.DocumentOffset(); using (LexerStateCookie.Create(lexer)) { if (!lexer.FindTokenAt(offset.Offset)) { return(""); } var tt = lexer.TokenType; while (tt != null) { lexer.Advance(-1); tt = lexer.TokenType; if (tt == ShaderLabTokenType.CG_PROGRAM || tt == ShaderLabTokenType.CG_INCLUDE || tt == ShaderLabTokenType.HLSL_PROGRAM || tt == ShaderLabTokenType.HLSL_INCLUDE || tt == ShaderLabTokenType.GLSL_PROGRAM || tt == ShaderLabTokenType.GLSL_INCLUDE) { break; } } if (tt != null) { var doc = textControl.Document; var lineStart = doc.GetLineStartOffset(doc.GetCoordsByOffset(lexer.TokenStart).Line); lexer.FindTokenAt(lineStart); tt = lexer.TokenType; Assertion.AssertNotNull(tt, "Lexer.TokenType may not be null"); while (tt.IsWhitespace) { lexer.Advance(); tt = lexer.TokenType; } var tokenLineStart = doc.GetLineStartOffset(doc.GetCoordsByOffset(lexer.TokenStart).Line); return(doc.GetText(new TextRange(tokenLineStart, lexer.TokenStart))); } } return(""); }
private bool NeedSkipCloseBracket(CachingLexer lexer, char charTyped) { // check if the next token matches the typed char TokenNodeType nextToken = lexer.TokenType; if ((charTyped == ')' && nextToken != PsiTokenType.RPARENTH) || (charTyped == ']' && nextToken != PsiTokenType.RBRACKET) || (charTyped == '}' && nextToken != PsiTokenType.RBRACE)) { return(false); } // find the leftmost non-closed bracket (excluding typed) of typed class so that there are no opened brackets of other type var bracketMatcher = new PsiBracketMatcher(); TokenNodeType searchTokenType = charTyped == ')' ? PsiTokenType.LPARENTH : charTyped == ']' ? PsiTokenType.LBRACKET : PsiTokenType.LBRACE; int? leftParenthPos = null; TokenNodeType tokenType; for (lexer.Advance(-1); (tokenType = lexer.TokenType) != null; lexer.Advance(-1)) { if (tokenType == searchTokenType && bracketMatcher.IsStackEmpty()) { leftParenthPos = lexer.CurrentPosition; } else if (!bracketMatcher.ProceedStack(tokenType)) { break; } } // proceed with search result if (leftParenthPos == null) { return(false); } lexer.CurrentPosition = leftParenthPos.Value; return(bracketMatcher.FindMatchingBracket(lexer)); }
private TokenNodeType FindPreviousToken([CanBeNull] CachingLexer lexer, int initialOffset) { if (lexer == null) { return(null); } for (int offset = initialOffset; offset >= 0; offset -= 1) { if (!lexer.FindTokenAt(offset)) { continue; } var tokenType = lexer.TokenType; if (tokenType?.IsWhitespace != false) { continue; } return(tokenType); } return(null); }
private bool IsAtValidEndToken(CachingLexer cachingLexer) { // There is no token marking the exact end of the chameleon body - make sure the next significant token is EOF, // directives end or document end TokenNodeType tokenType; while ((tokenType = cachingLexer.TokenType) != null) { if (tokenType == YamlTokenType.DOCUMENT_END || tokenType == YamlTokenType.DIRECTIVES_END) { return(true); } if (!tokenType.IsComment && !tokenType.IsWhitespace) { return(false); } cachingLexer.Advance(); } return(true); }
private bool HandleRightBracketTyped(ITypingContext typingContext) { ITextControl textControl = typingContext.TextControl; if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(false); } using (CommandProcessor.UsingCommand("Smart bracket")) { TextControlUtil.DeleteSelection(textControl); int charPos = TextControlToLexer(textControl, textControl.Caret.Offset()); CachingLexer lexer = GetCachingLexer(textControl); if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos) { return(false); } if (NeedSkipCloseBracket(lexer, typingContext.Char)) { int position = charPos + 1; if (position >= 0) { textControl.Caret.MoveTo(position, CaretVisualPlacement.DontScrollIfVisible); } } else { typingContext.CallNext(); } } return(true); }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { TreeTextRange oldRange = this.GetTreeTextRange(); Logger.Assert(changedRange.ContainedIn(oldRange), "The condition “changedRange.ContainedIn(oldRange)” is false."); int newLength = oldRange.Length - changedRange.Length + insertedTextLen; // Find starting comment if (!cachingLexer.FindTokenAt(oldRange.StartOffset.Offset) || cachingLexer.TokenType != GetTokenType() || cachingLexer.TokenStart != oldRange.StartOffset.Offset || cachingLexer.TokenEnd != oldRange.StartOffset.Offset + newLength) { return null; } LeafElementBase element = TreeElementFactory.CreateLeafElement(cachingLexer.TokenType, new ProjectedBuffer(cachingLexer.Buffer, new TextRange(cachingLexer.TokenStart, cachingLexer.TokenStart + newLength)), 0, newLength); var comment = element as Comment; if (comment == null || CommentType != comment.CommentType) { return null; } return comment; }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { TreeOffset currStartOffset = GetTreeStartOffset(); int currLength = GetTextLength(); Logger.Assert(changedRange.StartOffset >= currStartOffset && changedRange.EndOffset <= (currStartOffset + currLength), "changedRange.StartOffset >= currStartOffset && changedRange.EndOffset <= (currStartOffset+currLength)"); int newLength = currLength - changedRange.Length + insertedTextLen; LanguageService languageService = Language.LanguageService(); if (languageService != null) { var parser = (IPsiParser)languageService.CreateParser(new ProjectedLexer(cachingLexer, new TextRange(currStartOffset.Offset, currStartOffset.Offset + newLength)), GetPsiModule(), GetSourceFile()); TreeElement newElement = parser.ParseStatement(); if (newElement.GetTextLength() == 0) { return null; } if ((newElement.GetTextLength() == newLength) && (";".Equals(newElement.GetText().Substring(newElement.GetTextLength() - 1)))) { var psiFile = GetContainingNode<PsiFile>(); if (psiFile != null) { psiFile.ClearTables(); } return newElement as IRuleDeclaration; } } return null; }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { return(null); }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { throw new System.NotImplementedException(); }
private bool IsBlockStart([NotNull] CachingLexer lexer) => lexer.TokenType == T4TokenNodeTypes.STATEMENT_BLOCK_START || lexer.TokenType == T4TokenNodeTypes.EXPRESSION_BLOCK_START || lexer.TokenType == T4TokenNodeTypes.FEATURE_BLOCK_START;
public FilteringPsiLexer(CachingLexer lexer) : base(lexer) { }
protected override string CalculateBaseIndent(CachingLexer lexer, ITextControl textControl) { return(myCppDummyFormatter.CalculateInjectionIndent(lexer, textControl)); }
public override IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { return(base.ReSync(cachingLexer, changedRange, insertedTextLen) as DocComment); }
/*private bool HandleRightBraceTyped(ITypingContext typingContext) * { * var textControl = typingContext.TextControl; * using (CommandProcessor.UsingCommand("Smart LBRACE")) * { * typingContext.CallNext(); * * // check if typed char is a token * int charPos = TextControlToLexer(textControl, textControl.Caret.Offset() - 1); * CachingLexer lexer = GetCachingLexer(textControl); * if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos) * return true; * * if (NeedAutoinsertCloseBracket(lexer)) * { * if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) * return true; * * AutoinsertRBrace(textControl, lexer); * var position = charPos + 1; * if (position >= 0) * textControl.Caret.MoveTo(position, CaretVisualPlacement.DontScrollIfVisible); * } * } * return true; * }*/ private bool AutoinsertRBrace(ITextControl textControl, CachingLexer lexer) { int charPos = lexer.TokenEnd; int lBracePos = charPos - 1; if (lexer.TokenType != PsiTokenType.LBRACE) { return(false); } if (!NeedAutoinsertCloseBracket(lexer)) { return(false); } // insert RBRACE next to the LBRACE IDocument document = textControl.Document; int position = lBracePos; if (position < 0) { return(false); } document.InsertText(position + 1, "}"); // Commit PSI IFile file = CommitPsi(textControl); if (file == null) { return(false); } TreeTextRange treeLBraceRange = file.Translate(new DocumentRange(document, new TextRange(lBracePos + 1))); if (!treeLBraceRange.IsValid()) { return(false); } var rBraceToken = file.FindTokenAt(treeLBraceRange.StartOffset) as ITokenNode; if (rBraceToken == null || rBraceToken.GetTokenType() != PsiTokenType.RBRACE) { return(false); } TreeOffset positionForRBrace = rBraceToken.GetTreeTextRange().EndOffset; // move RBRACE to another position, if necessary DocumentRange documentRangeForRBrace = file.GetDocumentRange(positionForRBrace); if (documentRangeForRBrace.IsValid() && documentRangeForRBrace.TextRange.StartOffset != lBracePos + 1) { int pos = documentRangeForRBrace.TextRange.StartOffset; if (pos >= 0) { document.InsertText(pos, "}"); document.DeleteText(new TextRange(lBracePos + 1, lBracePos + 2)); } } return(true); }
public IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) => null; // No reparse for now.
private bool HandleQuoteTyped(ITypingContext typingContext) { ITextControl textControl = typingContext.TextControl; if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) { return(false); } using (CommandProcessor.UsingCommand("Smart quote")) { TextControlUtil.DeleteSelection(textControl); textControl.FillVirtualSpaceUntilCaret(); CachingLexer lexer = GetCachingLexer(textControl); IBuffer buffer = lexer.Buffer; int charPos = TextControlToLexer(textControl, textControl.Caret.Offset()); TokenNodeType correspondingTokenType = PsiTokenType.STRING_LITERAL; if (charPos < 0 || !lexer.FindTokenAt(charPos)) { return(false); } TokenNodeType tokenType = lexer.TokenType; // check if we should skip the typed char if (charPos < buffer.Length && buffer[charPos] == typingContext.Char && tokenType == correspondingTokenType && lexer.TokenStart != charPos && buffer[lexer.TokenStart] != '@') { int position = charPos; if (position >= 0) { textControl.Caret.MoveTo(position + 1, CaretVisualPlacement.DontScrollIfVisible); } return(true); } // check that next token is a good one if (tokenType != null && !IsStopperTokenForStringLiteral(tokenType)) { return(false); } // find next not whitespace token while (lexer.TokenType == PsiTokenType.WHITE_SPACE) { lexer.Advance(); } bool doInsertPairQuote = (lexer.TokenType == correspondingTokenType) && ((lexer.TokenEnd > lexer.TokenStart + 1) && (lexer.Buffer[lexer.TokenStart] == typingContext.Char) && (lexer.Buffer[lexer.TokenEnd - 1] == typingContext.Char)); // do inserting of the requested char and updating of the lexer typingContext.CallNext(); lexer = GetCachingLexer(textControl); // charPos = TextControlToLexer(textControl, textControl.CaretModel.Offset - 1); if (!doInsertPairQuote) { // check if the typed char is the beginning of the corresponding token if (!lexer.FindTokenAt(charPos)) { return(true); } bool isStringWithAt = lexer.TokenType == PsiTokenType.STRING_LITERAL && lexer.TokenStart == charPos - 1 && lexer.Buffer[lexer.TokenStart] == '@'; if ((lexer.TokenStart != charPos) && !isStringWithAt) { return(true); } // check if there is unclosed token of the corresponding type up to the end of the source line int newPos = charPos; if (newPos < 0) { return(true); } DocumentCoords documentCoords = textControl.Document.GetCoordsByOffset(newPos); int offset = textControl.Document.GetLineEndOffsetNoLineBreak(documentCoords.Line) - 1; int lexerOffset = TextControlToLexer(textControl, offset); if (lexerOffset >= 0) { lexer.FindTokenAt(lexerOffset); } if (lexerOffset < 0 || lexer.TokenType == null) { charPos = TextControlToLexer(textControl, textControl.Caret.Offset() - 1); if (charPos >= 0) { lexer.FindTokenAt(charPos); } else { return(true); } } doInsertPairQuote = (lexer.TokenType == correspondingTokenType) && ((lexer.TokenEnd == lexer.TokenStart + 1) || (lexer.Buffer[lexer.TokenEnd - 1] != typingContext.Char) || (isStringWithAt && (lexer.TokenStart == charPos - 1) && (lexer.TokenEnd != charPos + 1))); } // insert paired quote if (doInsertPairQuote) { charPos++; int documentPos = charPos; if (documentPos >= 0) { textControl.Document.InsertText(documentPos, typingContext.Char == '\'' ? "'" : "\""); textControl.Caret.MoveTo(documentPos, CaretVisualPlacement.DontScrollIfVisible); } } } return(true); }
public TextRange GetBlockComment(CachingLexer lexer) { return(lexer.TokenType == ShaderLabTokenType.MULTI_LINE_COMMENT ? new TextRange(lexer.TokenStart, lexer.TokenEnd) : TextRange.InvalidRange); }
private bool DoHandleEnterAfterLBracePressed(ITextControl textControl) { int charPos = TextControlToLexer(textControl, textControl.Caret.Offset()); if (charPos <= 0) { return(false); } // Check that token before caret is LBRACE CachingLexer lexer = GetCachingLexer(textControl); if (!lexer.FindTokenAt(charPos - 1)) { return(false); } if (lexer.TokenType == PsiTokenType.WHITE_SPACE) { charPos = lexer.TokenStart; lexer.Advance(-1); } if (lexer.TokenType != PsiTokenType.LBRACE) { return(false); } int lBracePos = lexer.TokenStart; // If necessary, do RBRACE autoinsert bool braceInserted = false; if (GetTypingAssistOption(textControl, TypingAssistOptions.BraceInsertTypeExpression) == SmartBraceInsertType.ON_ENTER) { braceInserted = AutoinsertRBrace(textControl, lexer); // Resync with modified text lexer = GetCachingLexer(textControl); lexer.FindTokenAt(lBracePos); Logger.Assert(lexer.TokenType == PsiTokenType.LBRACE, "The condition (lexer.TokenType == CSharpTokenType.LBRACE) is false."); } // Find the matched RBRACE and check they are on the same line int rBracePos; if (!new PsiBracketMatcher().FindMatchingBracket(lexer, out rBracePos)) { return(false); } int textControlLBracePos = lBracePos; int textControlRBracePos = rBracePos; if (textControlLBracePos < 0 || textControlRBracePos < 0 || (!braceInserted && textControl.Document.GetCoordsByOffset(textControlLBracePos).Line != textControl.Document.GetCoordsByOffset(textControlRBracePos).Line)) { return(false); } // Commit PSI for current document IFile file = CommitPsi(textControl); if (file == null) { return(false); } // Find nodes at the tree for braces TreeOffset lBraceTreePos = file.Translate(new DocumentRange(textControl.Document, lBracePos)).StartOffset; TreeOffset rBraceTreePos = file.Translate(new DocumentRange(textControl.Document, rBracePos)).StartOffset; var lBraceNode = file.FindTokenAt(lBraceTreePos) as ITokenNode; if (lBraceNode == null || lBraceNode.GetTokenType() != PsiTokenType.LBRACE) { return(false); } var rBraceNode = file.FindTokenAt(rBraceTreePos) as ITokenNode; if (rBraceNode == null || rBraceNode.GetTokenType() != PsiTokenType.RBRACE) { return(false); } TreeTextRange reparseTreeOffset = file.Translate(new DocumentRange(textControl.Document, charPos)); const string dummyText = "a"; return(ReformatForSmartEnter(dummyText, textControl, file, reparseTreeOffset, lBraceTreePos, rBraceTreePos)); }
public override IChameleonNode ReSync(CachingLexer cachingLexer, TreeTextRange changedRange, int insertedTextLen) { return base.ReSync(cachingLexer, changedRange, insertedTextLen) as DocComment; }