private void Parse(Span span) { List <Token> Tokens = null; Tokens = Lexer.Lex(Snapshot.GetText(span)); for (int r = Regions.Count - 1; r >= 0; r--) { if (span.Contains(new Span(Regions[r].StartIndex, Regions[r].Length))) { Regions.RemoveAt(r); } } int t = 0; Stack <FoldRegion> regions = new Stack <FoldRegion>(); while (t < Tokens.Count) { Token token = Tokens[t]; if (token.Type == TokenType.Keyword) { if (token.Content == "begin") { FoldRegion newRegion = new FoldRegion(token.StartIndex); if (t < Tokens.Count - 1) { Token blockType = Tokens[t + 1]; newRegion.CollapsedText = "begin " + blockType.Content; if (blockType.Type == TokenType.Keyword && t < Tokens.Count - 2) { if (blockType.Content == "class") { Token className = Tokens[t + 2]; newRegion.CollapsedText += " " + className.Content; } /*else if (blockType.Content == "subroutine") * { * Token subName = Tokens[t + 2]; * newRegion.CollapsedText += " " + subName.Content; * }*/ else if (blockType.Content == "function" || blockType.Content == "method") { Token name = Tokens[t + 2]; newRegion.CollapsedText += " " + name.Content; } } } newRegion.CollapsedText += "..."; regions.Push(newRegion); } else if (token.Content == "end") { if (regions.Count > 0) { FoldRegion region = regions.Pop(); region.Length = token.StartIndex + token.Length - region.StartIndex; region.ClosingTokenLength = token.Content.Length; // Adjust for the given span region.StartIndex += span.Start; Regions.Add(region); } } } t++; } this.TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(Snapshot, span))); }
private void Buffer_Changed(object sender, TextContentChangedEventArgs e) { if (e.Changes.Count == 0) { return; } //throw new NotImplementedException(); Snapshot = e.After; // Update the already changed regions Span invalidateRange = e.Changes[0].NewSpan; // All fold regions contained here will be deleted and reparsed foreach (ITextChange change in e.Changes) { // expand invalidateRange to include change.NewSpan invalidateRange = invalidateRange.Union(change.NewSpan); // - Fix up starts and lengths of spans before/after/around // - Invalidate spans intersecting for (int r = Regions.Count - 1; r >= 0; r--) { FoldRegion region = Regions[r]; if (region.StartIndex < change.OldPosition) { // Starts before the change - check end position if (region.StartIndex + region.Length < change.OldPosition) { // Ends before the change - do nothing } else if (region.StartIndex + region.Length - region.ClosingTokenLength > change.OldEnd) { // Ends after the change - adjust length region.Length += change.Delta; } else { // Ends during the change - delete and invalidate Regions.RemoveAt(r); invalidateRange = invalidateRange.Union(new Span(region.StartIndex, region.Length)); } } else if (region.StartIndex >= change.OldEnd) { // Starts after the change - adjust start region.StartIndex += change.Delta; } else { // Starts in the change - delete and invalidate Regions.RemoveAt(r); invalidateRange = invalidateRange.Union(new Span(region.StartIndex, region.Length)); } } // Check to see if we just added a tail part to a now-valid folding region, and if we did, seek upwards until we find the corresponding top. for (int line = Snapshot.GetLineNumberFromPosition(change.NewPosition); line <= Snapshot.GetLineNumberFromPosition(change.NewEnd); line++) { string lineText = Snapshot.GetLineFromLineNumber(line).GetText(); List <Token> lineTokens = Lexer.Lex(lineText); if (lineTokens.Count > 0 && lineTokens[0].Type == TokenType.Keyword && lineTokens[0].Content == "end") { if (lineTokens[0].Content == "end") { // Scan upwards until we find a matching begin, or the beginning of the file. int startLine = line - 1; int endCount = 1; // increase by one for every end that we pass, and decrease for every begin. while (startLine >= 0 && endCount > 0) { string startLineText = Snapshot.GetLineFromLineNumber(startLine).GetText(); List <Token> startLineTokens = Lexer.Lex(startLineText); if (startLineTokens.Count > 0 && startLineTokens[0].Type == TokenType.Keyword) { if (startLineTokens[0].Content == "end") { endCount++; } else if (startLineTokens[0].Content == "begin") { endCount--; } } startLine--; } startLine++; int start = Snapshot.GetLineFromLineNumber(startLine).Start.Position; int end = Snapshot.GetLineFromLineNumber(line).End.Position; invalidateRange = invalidateRange.Union(new Span(start, end - start)); } else if (lineTokens[0].Content == "begin") { // Scan downwards until we find a matching end, or the end of the file. int endLine = line + 1; int beginCount = 1; while (endLine < Snapshot.LineCount && beginCount > 0) { string endLineText = Snapshot.GetLineFromLineNumber(endLine).GetText(); List <Token> endLineTokens = Lexer.Lex(endLineText); if (endLineTokens.Count > 0 && endLineTokens[0].Type == TokenType.Keyword) { if (endLineTokens[0].Content == "begin") { beginCount++; } else if (endLineTokens[0].Content == "end") { beginCount--; } } endLine++; } endLine--; int start = Snapshot.GetLineFromLineNumber(line).Start.Position; int end = Snapshot.GetLineFromLineNumber(endLine).End.Position; invalidateRange = invalidateRange.Union(new Span(start, end - start)); } } } } // Make sure we don't invalidate past the end of the file (can be caused by killing fold regions that were where we would now consider out of bounds) if (invalidateRange.End > Snapshot.Length) { invalidateRange = new Span(invalidateRange.Start, Snapshot.Length - invalidateRange.Start); } Parse(invalidateRange); }
private void ProcessRegion(ref int pos, int prevLevel, Dictionary <Int32, FoldRegion> regions, FoldRegion reg) { @ref.Send(Sci.SCI_SETFOLDLEVEL, pos, prevLevel | Sci.SC_FOLDLEVELHEADERFLAG | Sci.SC_FOLDLEVELBASE); pos++; for (; pos < reg.EndLine; pos++) { FoldRegion child; if (regions.TryGetValue(pos, out child)) { ProcessRegion(ref pos, reg.Level, regions, child); } @ref.Send(Sci.SCI_SETFOLDLEVEL, pos, reg.Level | Sci.SC_FOLDLEVELBASE); } }