// Step 3: Implement the CreateTagger method to return an instance of HighlightWordTagger. public ITagger <T> CreateTagger <T>(ITextView textView, ITextBuffer buffer) where T : ITag { //provide highlighting only on the top buffer if (textView.TextBuffer != buffer) { return(null); } string thisFile = VerilogLanguage.VerilogGlobals.GetDocumentPath(textView.TextSnapshot); // TODO - do we really want to reparse here?? // this appears to be the only place called when first opening a file. (?) // // keywords: onload initialize startup // VerilogGlobals.ParseStatusController.Init(thisFile); //lock (VerilogGlobals.ParseStatus[thisFile]) //{ // // VerilogGlobals.NeedReparse = true; // VerilogGlobals.ParseStatus[thisFile].NeedReparse = true; //} // VerilogGlobals.ParseStatus_NeedReparse_SetValue(thisFile, true); VerilogGlobals.ParseStatusController.NeedReparse_SetValue(thisFile, true); VerilogGlobals.Reparse(buffer, thisFile); // parse the buffer at file load time ITextStructureNavigator textStructureNavigator = TextStructureNavigatorSelector.GetTextStructureNavigator(buffer); return(new HighlightWordTagger(textView, buffer, TextSearchService, textStructureNavigator) as ITagger <T>); }
//private void Start() //{ // System.Diagnostics.Debug.WriteLine("1. Call thread task"); // StartMyLongRunningTask(); // System.Diagnostics.Debug.WriteLine("2. Do something else"); //} //private void StartMyLongRunningTask() //{ // ThreadStart starter = myLongRunningTask; // starter += () => // { // myLongRunningTaskDone(); // }; // Thread _thread = new Thread(starter) { IsBackground = true }; // _thread.Start(); //} //private void myLongRunningTaskDone() //{ // System.Diagnostics.Debug.WriteLine("3. Task callback result"); //} //private void myLongRunningTask() //{ // string thisFile = VerilogLanguage.VerilogGlobals.GetDocumentPath(_buffer.CurrentSnapshot); // VerilogGlobals.Reparse(_buffer, thisFile); // note that above, we are checking that the e.After is the same as the _buffer //} /// <summary> /// BufferChanged - handle Buffer Changed event. If buffer has a character with possible far-reaching consequences /// then force a rescan of the enture buffer. See also HighlightWordTaggerProvider /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BufferChanged(object sender, TextContentChangedEventArgs e) { // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). if (e.After != _buffer.CurrentSnapshot) { return; } if (e.Changes.Count < 1) { // TODO - how did we get here if there are no changes? (found this after exception during debug. no apparent invoke. ) return; } string theNewText = e.Changes[0].NewText; string theOldText = e.Changes[0].OldText; if (e.Changes.Count > 1) { // TODO - why exit if there is more than one change (perhaps exit if LESS than 1? no!) return; } // we are only interested when the old and new text are different. // yes, the event seems to be triggered even with no apparent changes // if (theNewText != theOldText) { // even if the buffer is different, only certain characters require a full reparse // typically brackets (since we keep track of depth) and comment chars: if (VerilogGlobals.IsRefreshChar(theNewText) || VerilogGlobals.IsRefreshChar(theOldText)) { string thisFile = VerilogLanguage.VerilogGlobals.GetDocumentPath(_buffer.CurrentSnapshot); // VerilogGlobals.ParseStatus_NeedReparse_SetValue(thisFile, true); VerilogGlobals.ParseStatusController.NeedReparse_SetValue(thisFile, true); //VerilogGlobals.ParseStatus_EnsureExists(thisFile); //VerilogGlobals.ParseStatus[thisFile].NeedReparse = true; // VerilogGlobals.NeedReparse = true; //myLongRunningTask(); VerilogGlobals.Reparse(_buffer, thisFile); // note that above, we are checking that the e.After is the same as the _buffer } } else { System.Diagnostics.Debug.WriteLine("BufferChanged called but new and old text not different!"); } }
// Step 4: The event handlers both call the UpdateAtCaretPosition method. void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e) { // If a new snapshot wasn't generated, then skip this layout if (e.NewSnapshot != e.OldSnapshot) { UpdateAtCaretPosition(View.Caret.Position); string thisFile = VerilogLanguage.VerilogGlobals.GetDocumentPath(View.TextSnapshot); //VerilogGlobals.ParseStatus_EnsureExists(thisFile); //VerilogGlobals.ParseStatus[thisFile].NeedReparse = true; // VerilogGlobals.ParseStatus_NeedReparse_SetValue(thisFile, true); ParseStatusController.NeedReparse_SetValue(thisFile, true); //VerilogGlobals.NeedReparse = true; VerilogGlobals.Reparse(SourceBuffer, thisFile); } }
/// <summary> /// BufferChanged - handle Buffer Changed event. If buffer has a character with possible far-reaching consequences /// then force a rescan of the enture buffer. See also HighlightWordTaggerProvider /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BufferChanged(object sender, TextContentChangedEventArgs e) { // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). if (e.After != _buffer.CurrentSnapshot) { return; } string theNewText = e.Changes[0].NewText; string theOldText = e.Changes[0].OldText; if (e.Changes.Count > 1) { return; } // we are only interested when the old and new text are different. // yes, the event seems to be triggered even with no apparent changes // if (theNewText != theOldText) { // even if the buffer is different, only certain characters require a full reparse // typically brackets (since we keep track of depth) and comment chars: if (VerilogGlobals.IsRefreshChar(theNewText) || VerilogGlobals.IsRefreshChar(theOldText)) { string thisFile = VerilogLanguage.VerilogGlobals.GetDocumentPath(_buffer.CurrentSnapshot); // VerilogGlobals.ParseStatus_NeedReparse_SetValue(thisFile, true); VerilogGlobals.ParseStatusController.NeedReparse_SetValue(thisFile, true); //VerilogGlobals.ParseStatus_EnsureExists(thisFile); //VerilogGlobals.ParseStatus[thisFile].NeedReparse = true; // VerilogGlobals.NeedReparse = true; VerilogGlobals.Reparse(_buffer, thisFile); // note that above, we are checking that the e.After is the same as the _buffer } } }
/// <summary> /// IEnumerable VerilogTokenTag GetTags /// </summary> /// <param name="spans"></param> /// <returns></returns> public IEnumerable <ITagSpan <VerilogTokenTag> > GetTags(NormalizedSnapshotSpanCollection spans) { //while (VerilogGlobals.IsReparsing) { // do we really want to do this? (probably not) // System.Threading.Thread.Sleep(10); } //System.Diagnostics.Debug.WriteLine("Starting IEnumerable<ITagSpan<VerilogTokenTag>>"); // bool EditInProgress = spans.snapshot.TextBuffer.EditInProgress; // since we can start mid-text, we don't know if the current span is in the middle of a comment // init TODO - we don't really want to call this for every enumeration! // VerilogGlobals.InitHoverBuilder(); VerilogGlobals.IsContinuedBlockComment = IsOpenBlockComment(spans); // TODO - does spans always contain the full document? (appears perhaps not) VerilogGlobals.VerilogToken[] tokens = null; VerilogGlobals.VerilogToken priorToken = new VerilogGlobals.VerilogToken(); // look at each span for tokens, comments, etc foreach (SnapshotSpan curSpan in spans) { if (tokens != null && tokens.Length >= 1) { priorToken = tokens[tokens.Length - 1]; // get the token from the prior line } ITextSnapshotLine containingLine = curSpan.Start.GetContainingLine(); int curLoc = containingLine.Start.Position; int LinePosition = 0; string thisTokenString = ""; tokens = VerilogGlobals.VerilogKeywordSplit(containingLine.GetText(), priorToken); Boolean IsContinuedLineComment = false; // comments with "//" are only effective for the current line, but /* can span multiple lines foreach (VerilogGlobals.VerilogToken VerilogToken in tokens) // this group of tokens in in a single line { // by the time we get here, we might have a tag with adjacent comments: // assign// // //assign // assign//comment // /*assign*/ // assign/*comment*/ thisTokenString = VerilogToken.Part; CommentHelper commentHelper = new CommentHelper(thisTokenString, IsContinuedLineComment, VerilogGlobals.IsContinuedBlockComment); VerilogGlobals.IsContinuedBlockComment = commentHelper.HasBlockStartComment; IsContinuedLineComment = commentHelper.HasOpenLineComment; // we'll use this when processing the VerilogToken item in the commentHelper, above foreach (CommentHelper.CommentItem Item in commentHelper.CommentItems) { bool TestComment = VerilogGlobals.TextIsComment(containingLine.LineNumber, LinePosition); LinePosition += Item.ItemText.Length; var tokenSpan = new SnapshotSpan(curSpan.Snapshot, new Span(curLoc, Item.ItemText.Length)); if (tokenSpan.IntersectsWith(curSpan)) { // is this item a comment? If so, color as appropriate. comments take highest priority: no other condition will change color of a comment if (Item.IsComment) { // System.Diagnostics.Debug.WriteLine("IEnumerable VerilogTokenTag yield comment for item " + Item.ItemText??""); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogTokenTypes.Verilog_Comment))); } // otherwise when not a comment, check to see if it is a keyword else { // first check to see if any new variables are being defined; // VerilogGlobals.BuildHoverItems(Item.ItemText); // check for standard keyword syntax higlighting if (VerilogGlobals.VerilogTypes.ContainsKey(Item.ItemText)) { System.Diagnostics.Debug.WriteLine("IEnumerable VerilogTokenTag yield " + Item.ItemText); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogTypes[Item.ItemText]))); } else if (VerilogGlobals.VerilogVariables.ContainsKey(Item.ItemText)) { // we are instantiation a module; recall VerilogVariables is first a dictionary of scope (aka module), then a dictionary of variables in each module scope // TODO do we need: if (tokenSpan.IntersectsWith(curSpan)) System.Diagnostics.Debug.WriteLine("IEnumerable VerilogTokenTag yield variable module " + Item.ItemText); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogTypes["variable_module"]))); } else { // check to see if this is a variable string thisScope = VerilogGlobals.TextModuleName(containingLine.LineNumber, curLoc - containingLine.Start.Position); // TODO if (VerilogGlobals.VerilogVariables.ContainsKey(thisScope)) { // the current scope (typically a module name) is defined. So do we have a known variable? if (VerilogGlobals.VerilogVariables[thisScope].ContainsKey(Item.ItemText)) { // TODO do we need: if (tokenSpan.IntersectsWith(curSpan)) System.Diagnostics.Debug.WriteLine("IEnumerable VerilogTokenTag yield variable " + Item.ItemText); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogVariables[thisScope][Item.ItemText]))); } else if (VerilogGlobals.VerilogVariables.ContainsKey(VerilogGlobals.SCOPE_CONST) && VerilogGlobals.VerilogVariables[VerilogGlobals.SCOPE_CONST].ContainsKey(Item.ItemText)) { yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogVariables[VerilogGlobals.SCOPE_CONST][Item.ItemText]))); } else { // no tag colorization for the explicit token, but perhaps based on context: int thisDelimiterIndex = 0; int thisDelimiterTotalDepth; //int thisDelimiterTotalDepth = VerilogToken.SquareBracketDepth + // VerilogToken.RoundBracketDepth + // VerilogToken.SquigglyBracketDepth; // int testValue = VerilogGlobals.BracketDepth(containingLine.LineNumber, curLoc - containingLine.Start.Position); switch (VerilogToken.Context) { case VerilogGlobals.VerilogTokenContextType.SquareBracketOpen: case VerilogGlobals.VerilogTokenContextType.SquareBracketClose: thisDelimiterTotalDepth = VerilogGlobals.BracketDepth(containingLine.LineNumber, curLoc - containingLine.Start.Position); thisDelimiterIndex = (thisDelimiterTotalDepth % 5); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, // see _VerilogTypes["bracket_type1"] .. _VerilogTypes["bracket_type5"] new VerilogTokenTag(VerilogGlobals.VerilogTypes["bracket_type" + (thisDelimiterIndex).ToString()]))); break; case VerilogGlobals.VerilogTokenContextType.RoundBracketClose: case VerilogGlobals.VerilogTokenContextType.RoundBracketOpen: thisDelimiterTotalDepth = VerilogGlobals.BracketDepth(containingLine.LineNumber, curLoc - containingLine.Start.Position); thisDelimiterIndex = (thisDelimiterTotalDepth % 5); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, // see _VerilogTypes["bracket_type1"] .. _VerilogTypes["bracket_type5"] new VerilogTokenTag(VerilogGlobals.VerilogTypes["bracket_type" + (thisDelimiterIndex).ToString()]))); break; case VerilogGlobals.VerilogTokenContextType.SquigglyBracketOpen: case VerilogGlobals.VerilogTokenContextType.SquigglyBracketClose: thisDelimiterTotalDepth = VerilogGlobals.BracketDepth(containingLine.LineNumber, curLoc - containingLine.Start.Position); thisDelimiterIndex = (thisDelimiterTotalDepth % 5); // see _VerilogTypes["bracket_type1"] .. _VerilogTypes["bracket_type5"] yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogTypes["bracket_type" + (thisDelimiterIndex).ToString()]))); break; case VerilogGlobals.VerilogTokenContextType.SquareBracketContents: yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogTokenTypes.Verilog_BracketContent))); break; case VerilogGlobals.VerilogTokenContextType.AlwaysAt: yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogTokenTypes.Verilog_always))); break; default: // no highlighting break; } } } else { if (VerilogGlobals.VerilogVariables.ContainsKey(VerilogGlobals.SCOPE_CONST) && VerilogGlobals.VerilogVariables[VerilogGlobals.SCOPE_CONST].ContainsKey(Item.ItemText)) { //yield return new TagSpan<VerilogTokenTag>(tokenSpan, // new VerilogTokenTag(VerilogGlobals.VerilogTypes["Verilog_Value"])); yield return(new TagSpan <VerilogTokenTag>(tokenSpan, new VerilogTokenTag(VerilogGlobals.VerilogVariables[VerilogGlobals.SCOPE_CONST][Item.ItemText]))); } else { // TODO - how do we get here when thisScope *is* defined? timing? // A: we destroy the VerilogVariables when rescanning (otherwise everyuthing is a duplicate) TODO: keep track of where variables are defined. don't rebui;d System.Diagnostics.Debug.WriteLine("Warning! VerilogGlobals.VerilogVariables.ContainsKey({0}) not defined!", thisScope); } } } } } // note that no chars are lost when splitting string with VerilogKeywordSplit, so no adjustment needed in location curLoc += Item.ItemText.Length; } } } }