private void UpdateJavaScriptBlockSpans() { if (IsHtmlFile) { _javaScriptBlockSpans = JScriptEditorUtil.GetJavaScriptBlockSpans(_lbm); } else { if (_javaScriptBlockSpans == null) { _javaScriptBlockSpans = new List <BlockSpan>(1); } else { _javaScriptBlockSpans.Clear(); } _javaScriptBlockSpans.Add(new BlockSpan(0, _buffer.CurrentSnapshot.Length, false)); } _javaScriptBlockStarts.Clear(); _javaScriptBlockEnds.Clear(); foreach (BlockSpan javaScriptBlockSpan in _javaScriptBlockSpans) { _javaScriptBlockStarts.Add(javaScriptBlockSpan.Start); _javaScriptBlockEnds.Add(javaScriptBlockSpan.End); } }
public void AugmentCompletionSession(ICompletionSession session, IList <CompletionSet> completionSets) { if (IsHtmlFile && completionSets.Any()) { var bottomSpan = completionSets.First().ApplicableTo; if (!JScriptEditorUtil.IsInJScriptLanguageBlock(_lbm, bottomSpan.GetStartPoint(bottomSpan.TextBuffer.CurrentSnapshot))) { // This is an HTML statement completion session, so do nothing return; } } // TODO: Reflect over the ShimCompletionSet to see where the Description value comes from // as setting the property does not actually change the value. var newCompletionSets = completionSets .Select(cs => cs == null ? cs : new ScriptCompletionSet( cs.Moniker, cs.DisplayName, cs.ApplicableTo, cs.Completions .Select(c => c == null ? c : new Completion( c.DisplayText, c.InsertionText, DocCommentHelper.ProcessParaTags(c.Description), c.IconSource, c.IconAutomationText)) .ToList(), cs.CompletionBuilders)) .ToList(); completionSets.Clear(); newCompletionSets.ForEach(cs => completionSets.Add(cs)); }
void UpdateWordAdornments() { var currentRequest = RequestedPoint; var wordSpans = new List <SnapshotSpan>(); var word = GetExtentOfWord(currentRequest); // Find all words in the buffer like the one the caret is on bool foundWord = true; // If we've selected something not worth highlighting, we might have missed a "word" by a little bit if (!WordExtentIsValid(currentRequest, word)) { // Before we retry, make sure it is worthwhile if (word.Span.Start != currentRequest || currentRequest == currentRequest.GetContainingLine().Start || char.IsWhiteSpace((currentRequest - 1).GetChar())) { foundWord = false; } else { // Try again, one character previous. // If the caret is at the end of a word, pick up the word. word = GetExtentOfWord(currentRequest - 1); // If the word still isn't valid, we're done if (!WordExtentIsValid(currentRequest, word)) { foundWord = false; } } } SynchronousUpdate(currentRequest, new NormalizedSnapshotSpanCollection(), null); if (!foundWord) { return; } SnapshotSpan currentWord = word.Span; // If this is the current word, and the caret moved within a word, we're done. if (CurrentWord.HasValue && currentWord == CurrentWord) { return; } // If the word is not an identifier, then don't search for matches. if (!JScriptEditorUtil.IsClassifiedAs(Classifier, currentWord.Start, JScriptClassifications.Identifier)) { return; } var request = new FindMatchesRequest { WordSpan = currentWord, RequestPoint = currentRequest }; FindAllMatches(request); }
private bool BraceShouldBeIgnored(SnapshotPoint bracePoint) { // if the prev char is a comment, string or operator then don't try matching // Note: The editor incorrectly classifies braces in regex literals as operators. // We are using this fact to detect if the brace is in a regex literal and thus ignore it. // Genuine braces have no classification at all. return(JScriptEditorUtil.IsClassifiedAs(_classifier, bracePoint, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)); }
internal static bool FindMatchingBrace(ILanguageBlockManager lbm, IClassifier classifier, SnapshotPoint startPoint, bool findClosing, char open, char close, int maxLines, ref bool maxLinesReached, out SnapshotSpan pairSpan) { // Get script block we're working in // lbm will be null if this is not in an HTML file var scriptBlock = lbm != null ? JScriptEditorUtil.GetJavaScriptBlockSpans(lbm) .Single(b => b.Start <= startPoint.Position && b.End >= startPoint.Position) : new BlockSpan(0, startPoint.Snapshot.TextBuffer.CurrentSnapshot.Length, true); return(findClosing ? FindMatchingCloseChar(scriptBlock, classifier, startPoint, open, close, maxLines, ref maxLinesReached, out pairSpan) : FindMatchingOpenChar(scriptBlock, classifier, startPoint, close, open, maxLines, ref maxLinesReached, out pairSpan)); }
private void SynchronousUpdate(SnapshotPoint currentRequest, IEnumerable <SnapshotSpan> newSpans, SnapshotSpan?newCurrentWord) { ViewDispatcher.BeginInvoke(new Action(() => { if (currentRequest != RequestedPoint) { return; } WordSpans = new NormalizedSnapshotSpanCollection( newSpans.Where(s => JScriptEditorUtil.IsClassifiedAsJavaScript(Classifier, s.Start))); CurrentWord = newCurrentWord; OnTagsChanged(new SnapshotSpan(View.TextBuffer.CurrentSnapshot, 0, View.TextBuffer.CurrentSnapshot.Length)); })); }
public IEnumerable <ITagSpan <TextMarkerTag> > GetTags(NormalizedSnapshotSpanCollection spans) { #if DEBUG Util.Log("GetTags called"); #endif if (spans.Count == 0) // there is no content in the buffer { yield break; } // don't do anything if the current SnapshotPoint is not initialized or after the end of the buffer if (!_currentCharPoint.HasValue || _currentCharPoint.Value.Position > _currentCharPoint.Value.Snapshot.Length) { yield break; } // hold on to a snapshot of the current character var currentCharPoint = _currentCharPoint.Value; // if the requested snapshot isn't the same as the one the brace is on, translate our spans to the expected snapshot if (spans[0].Snapshot != currentCharPoint.Snapshot) { currentCharPoint = currentCharPoint.TranslateTo(spans[0].Snapshot, PointTrackingMode.Positive); } // get the current char and the previous char var currentChar = currentCharPoint.Position != currentCharPoint.Snapshot.Length ? (char?)currentCharPoint.GetChar() : null; var prevCharPoint = currentCharPoint == 0 ? currentCharPoint : currentCharPoint - 1; // if currentChar is 0 (beginning of buffer), don't move it back var prevChar = prevCharPoint != 0 ? prevCharPoint.GetChar() : default(char?); // Can't get prevChar if point is 0 var maxLines = _view.TextViewLines.Count * _viewScreensToSearchOver; char closeChar; // If neither current or previous char is in a JS language block, return if (IsHtmlFile && !JScriptEditorUtil.IsInJScriptLanguageBlock(_lbm, currentCharPoint) && !JScriptEditorUtil.IsInJScriptLanguageBlock(_lbm, prevCharPoint)) { yield break; } // Check if char to right of cursor is an opening brace if (currentChar.HasValue && _braceList.TryGetValue(currentChar.Value, out closeChar)) // the value is the open brace { foreach (var s in GetTagSpans(currentCharPoint, currentChar.Value, closeChar, maxLines)) { yield return(s); } } // Check if char to left of cursor is a closing brace var openChar = _braceList.Where(kvp => kvp.Value.Equals(prevChar)) .Select(n => n.Key) .FirstOrDefault(); if (openChar != default(char)) // the value is the close brace, which is the *previous* character { foreach (var s in GetTagSpans(prevCharPoint, prevChar.Value, openChar, maxLines)) { yield return(s); } } }
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { //_broker.GetSessions(_textView).Any() //_broker.IsCompletionActive(_textView) if (_broker.IsCompletionActive(_textView)) { if (!IsHtmlFile || (_broker.GetSessions(_textView).Any(cs => cs.IsStarted && !cs.IsDismissed && cs.CompletionSets.Any(set => JScriptEditorUtil.IsInJScriptLanguageBlock(_lbm, set.ApplicableTo.GetStartPoint(_textView.TextSnapshot)))))) { var userTypedPeriod = UserTypedPeriod(pguidCmdGroup, nCmdID, pvaIn); var userTypedParens = UserTypedParens(pguidCmdGroup, nCmdID, pvaIn); if (UserPerfomedCommitAction(pguidCmdGroup, nCmdID, pvaIn) || userTypedPeriod || userTypedParens) { ForActiveCompletionSessions(s => { if (nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB || // Always complete on TAB s.SelectedCompletionSet.SelectionStatus.IsSelected) // If completion is selected (not just highlighted) { s.Commit(); } else { s.Dismiss(); } }); if (!userTypedPeriod && !userTypedParens) { return(VSConstants.S_OK); // Don't let anybody else handle this command } } if (UserTypedOperator(pguidCmdGroup, nCmdID, pvaIn) && !userTypedPeriod) { ForActiveCompletionSessions(s => s.Dismiss()); Debug.WriteLine("Dismissed all active completion sessions because user typed an operator"); } } } return(NextCmdTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)); }
List <ITrackingSpan> ReparseRange(ITextSnapshot snapshot, int reparseRangeStart, int reparseRangeEnd, out bool unbalanced) { var currentSections = new List <ITrackingSpan>(); var openCurlies = new Stack <int>(); bool isInJavaScript = IsInJavaScriptBlock(reparseRangeStart); unbalanced = false; for (int i = reparseRangeStart; i < reparseRangeEnd; i++) { var point = new SnapshotSpan(snapshot, i, 1).Start; // If current point is not in a JS language block, return if (!isInJavaScript) { if (_javaScriptBlockStarts.Contains(i)) { // Our scan just barely entered a JavaScript block isInJavaScript = true; // We don't want opening curly from open JavaScript block to match with // a closing curly from another block, so purge all unmatched (dangling) // opening curlies from the previous block. openCurlies.Clear(); } else { continue; } } if (_javaScriptBlockEnds.Contains(i)) { isInJavaScript = false; } var ch = snapshot[i]; if (ch == '{' || ch == '}') { if (JScriptEditorUtil.IsClassifiedAs(_classifier, point, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)) { continue; } } switch (ch) { case '{': openCurlies.Push(i); break; case '}': if (openCurlies.Count > 0) { int start = openCurlies.Pop(); var line = _buffer.CurrentSnapshot.GetLineFromPosition(i); if (start < line.Start.Position) { currentSections.Add(snapshot.CreateTrackingSpan(start, i - start + 1, SpanTrackingMode.EdgeExclusive)); } } else { unbalanced = true; } break; default: break; } } if (openCurlies.Count > 0) { unbalanced = true; } return(currentSections); }
// TODO: Can we refactor FindMatchingCloseChar and FindMatchingOpenChar into a single method? static bool FindMatchingCloseChar(BlockSpan scriptBlock, IClassifier classifier, SnapshotPoint startPoint, char open, char close, int maxLines, ref bool maxLinesReached, out SnapshotSpan pairSpan) { var isHTML = startPoint.Snapshot.ContentType.TypeName.Equals("HTML", StringComparison.OrdinalIgnoreCase); pairSpan = new SnapshotSpan(startPoint.Snapshot, 1, 1); var line = startPoint.GetContainingLine(); var lineText = line.GetText(); var lineNumber = line.LineNumber; var offset = startPoint.Position - line.Start.Position + 1; var endOfScriptBlockReached = false; var stopLineNumber = startPoint.Snapshot.LineCount - 1; if (maxLines > 0) { stopLineNumber = Math.Min(stopLineNumber, lineNumber + maxLines); } #if DEBUG var startTicks = DateTime.Now.Ticks; Util.Log("Looking for matching closing brace '{0}'", close); #endif var openCount = 0; while (true) { // walk the entire line while (offset < line.Length) { // Check if we've hit the end of the script block if (scriptBlock.End < line.Start + offset) { // We've hit the end of a script block endOfScriptBlockReached = true; break; } char currentChar = lineText[offset]; var currentCharPoint = line.Start + offset; if (currentChar == close) // found the close character { if (JScriptEditorUtil.IsClassifiedAs(classifier, currentCharPoint, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)) { #if DEBUG Util.Log("Candidate closing brace found but ignored because it was a comment, string or operator"); #endif } else if (openCount > 0) { openCount--; } else // found the matching close { #if DEBUG Util.Log("Matching closing brace '{0}' found after {1}ms", close, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif pairSpan = new SnapshotSpan(startPoint.Snapshot, currentCharPoint, 1); return(true); } } else if (currentChar == open) // this is another open { if (JScriptEditorUtil.IsClassifiedAs(classifier, currentCharPoint, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)) { #if DEBUG Util.Log("New opening brace found but ignored because it was a comment, string or operator"); #endif } else { openCount++; } } offset++; } if (endOfScriptBlockReached) { break; } // move on to the next line if (++lineNumber > stopLineNumber) { #if DEBUG Util.Log("Reached max lines ({0}), stopped looking at line {1} after {2}ms", maxLines, stopLineNumber, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif // Set maxLinesReached flag only if we actually hit max lines limit, not just end of buffer maxLinesReached = stopLineNumber >= maxLines; break; } // Move to next line line = line.Snapshot.GetLineFromLineNumber(lineNumber); lineText = line.GetText(); offset = 0; } #if DEBUG Util.Log("Matching closing brace '{0}' was not found. Open count: {1} after {2}ms", close, openCount, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif return(false); }
static bool FindMatchingOpenChar(BlockSpan scriptBlock, IClassifier classifier, SnapshotPoint startPoint, char open, char close, int maxLines, ref bool maxLinesReached, out SnapshotSpan pairSpan) { var isHTML = startPoint.Snapshot.ContentType.TypeName.Equals("HTML", StringComparison.OrdinalIgnoreCase); pairSpan = new SnapshotSpan(startPoint, startPoint); ITextSnapshotLine line = startPoint.GetContainingLine(); var lineNumber = line.LineNumber; var offset = startPoint - line.Start - 1; // move the offset to the character before this one var startOfScriptBlockReached = false; // if the offset is negative, move to the previous line if (offset < 0) { line = line.Snapshot.GetLineFromLineNumber(--lineNumber); offset = line.Length - 1; } var lineText = line.GetText(); var stopLineNumber = 0; var nominalStopLineNumber = lineNumber - maxLines; if (maxLines > 0) { stopLineNumber = Math.Max(stopLineNumber, nominalStopLineNumber); } #if DEBUG var startTicks = DateTime.Now.Ticks; Util.Log("Looking for matching opening brace '{0}'", open); #endif var closeCount = 0; Debug.Assert(scriptBlock != null); while (true) { // Walk the entire line while (offset >= 0) { // Check if we've hit the start of the script block if (scriptBlock.Start > line.Start + offset) { // We've hit the end of a script block startOfScriptBlockReached = true; break; } char currentChar = lineText[offset]; var currentCharPoint = line.Start + offset; if (currentChar == open) // found the open character { if (JScriptEditorUtil.IsClassifiedAs(classifier, currentCharPoint, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)) { #if DEBUG Util.Log("Candidate opening brace found but ignored because it was a comment, string or operator"); #endif } else if (closeCount > 0) { closeCount--; } else // We've found the matching open character { #if DEBUG Util.Log("Matching opening brace '{0}' found in {1}ms", open, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif pairSpan = new SnapshotSpan(currentCharPoint, 1); // we just want the character itself return(true); } } else if (currentChar == close) { if (JScriptEditorUtil.IsClassifiedAs(classifier, currentCharPoint, JScriptClassifications.Comment, JScriptClassifications.String, JScriptClassifications.Operator)) { #if DEBUG Util.Log("New closing brace found but ignored because it was a comment, string or operator"); #endif } else { closeCount++; } } offset--; } if (startOfScriptBlockReached) { break; } // Move to the previous line if (--lineNumber < stopLineNumber) { // Set maxLinesReached flag only if we actually hit max lines limit, not just start of buffer maxLinesReached = stopLineNumber == nominalStopLineNumber; #if DEBUG Util.Log("Reached max lines ({0}, stopped looking at line {1} after {2}ms", maxLines, stopLineNumber, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif break; } line = line.Snapshot.GetLineFromLineNumber(lineNumber); lineText = line.GetText(); offset = line.Length - 1; } #if DEBUG Util.Log("Matching opening brace '{0}' was not found. Open count: {1} after {2}ms", open, closeCount, TimeSpan.FromTicks(DateTime.Now.Ticks - startTicks).TotalMilliseconds); #endif return(false); }