public static void DoWork(string targetFile) { // ensure we have a ParseAttribute for this file //if (!ParseStatus.ContainsKey(targetFile)) //{ // ParseStatus.Add(targetFile, new ParseAttribute()); //} //ParseStatusController.EnsureExists(targetFile); //bool IsReparsing = false; //lock(_synchronizationParseStatus) { // IsReparsing = ParseStatus[targetFile].IsReparsing; //} if (ParseStatusController.IsReparsing(targetFile)) { // TODO what is this for? does it help with threading? (probably not) Thread.Sleep(50); } else { lock (_synchronizationParseStatus) { ParseStatus[targetFile].IsReparsing = true; } VerilogGlobals.ReparseWork(threadbuffer, threadFile); // TODO once reparsing is done in a thread, we need to tell the viewport to redraww the screen Thread.Sleep(10); } }
/// <summary> /// LineParse /// </summary> /// <param name="theLine"></param> private static void LineParse(string theLine, int theLineNumber) { // first, parse the words and tokens string thisTokenString = ""; int LinePosition = 0; tokens = VerilogGlobals.VerilogKeywordSplit(theLine, priorToken); Boolean IsContinuedLineComment = false; // new lines never have a continued line comment; 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 commentHelper = new CommentHelper.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.CommentHelper.CommentItem Item in commentHelper.CommentItems) { // TODO - are we actually doing anything with TestComment, or is this just for testing VerilogGlobals.TextIsComment() ?? bool TestComment = VerilogGlobals.TextIsComment(theLineNumber, LinePosition); LinePosition += Item.ItemText.Length; // 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) { // nothing } // 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; double duration10 = (DateTime.Now - ProfileStart).TotalMilliseconds; VerilogGlobals.BuildHoverItems(Item.ItemText); double duration11 = (DateTime.Now - ProfileStart).TotalMilliseconds; } } } }
public static void DoWork(string targetFile) { // ensure we have a ParseAttribute for this file //if (!ParseStatus.ContainsKey(targetFile)) //{ // ParseStatus.Add(targetFile, new ParseAttribute()); //} //ParseStatusController.EnsureExists(targetFile); //bool IsReparsing = false; //lock(_synchronizationParseStatus) { // IsReparsing = ParseStatus[targetFile].IsReparsing; //} if (ParseStatusController.IsReparsing(targetFile)) { // TODO what is this for? does it help with threading? (probably not) System.Diagnostics.Debug.WriteLine("DoWork called while IsReparsing..."); Thread.Sleep(50); } else { lock (_synchronizationParseStatus) { ParseStatus[targetFile].IsReparsing = true; } //if ( 1==1 || (DateTime.Now - LastRefresh).TotalSeconds > 10) //{ // System.Diagnostics.Debug.WriteLine("BufferAttributes calling ReparseWork"); VerilogGlobals.ReparseWork(threadbuffer, threadFile); // LastRefresh = DateTime.Now; //} // TODO once reparsing is done in a thread, we need to tell the viewport to redraww the screen // does this redraw? // TheView.Selection.TextView.ViewScroller.ScrollViewportVerticallyByPixels(0); Thread.Sleep(10); } }
/// <summary> /// Determine which pieces of Quickinfo content should be displayed /// </summary> public void AugmentQuickInfoSession(IQuickInfoSession session, IList <object> quickInfoContent, out ITrackingSpan applicableToSpan) { applicableToSpan = null; if (_disposed) { throw new ObjectDisposedException("TestQuickInfoSource"); } var triggerPoint = (SnapshotPoint)session.GetTriggerPoint(_buffer.CurrentSnapshot); if (triggerPoint == null) { return; } foreach (IMappingTagSpan <VerilogToken.VerilogTokenTag> curTag in _aggregator.GetTags(new SnapshotSpan(triggerPoint, triggerPoint))) { // here we add hover text at runtime if (_VerilogKeywordHoverText.Keys.Contains(curTag.Tag.type)) { var tagSpan = curTag.Span.GetSpans(_buffer).First(); applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(tagSpan, SpanTrackingMode.EdgeExclusive); quickInfoContent.Add(_VerilogKeywordHoverText[curTag.Tag.type]); } else { // var thisTag = curTag.ToString(); //TODO is this where to add verilog variables? var tagSpan = curTag.Span.GetSpans(_buffer).First(); string thisHoverKey = tagSpan.GetText(); // 510 = tagSpan.Snapshot.GetLineFromPosition(tagSpan.Start.Position).Extent.Start.Position // 523 = ((Microsoft.VisualStudio.Text.Utilities.MappingPointSnapshot)curTag.Span.Start)._anchor.Position // by the time we get here, we've lost the scope of which module we are in, so a helper function is needed int thisLine = tagSpan.Snapshot.GetLineFromPosition(tagSpan.Start.Position).LineNumber; int thisPosition = tagSpan.Start.Position - tagSpan.Snapshot.GetLineFromPosition(tagSpan.Start.Position).Extent.Start.Position; // tagSpan.Snapshot.GetLineFromPosition(tagSpan.Start.Position).End.Position; string thisScopeName = VerilogGlobals.TextModuleName(thisLine, thisPosition); // TODO get proper values! if (VerilogGlobals.VerilogVariableHoverText[thisScopeName].Keys.Contains(thisHoverKey)) { applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(tagSpan, SpanTrackingMode.EdgeExclusive); quickInfoContent.Add(VerilogGlobals.VerilogVariableHoverText[thisScopeName][thisHoverKey]); } } //if (curTag.Tag.type == VerilogTokenTypes.Verilog_always) //{ // var tagSpan = curTag.Span.GetSpans(_buffer).First(); // applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(tagSpan, SpanTrackingMode.EdgeExclusive); // quickInfoContent.Add(_VerilogKeywordHoverText[VerilogTokenTypes.Verilog_always]); //} //else if (curTag.Tag.type == VerilogTokenTypes.Verilog_begin) //{ // var tagSpan = curTag.Span.GetSpans(_buffer).First(); // applicableToSpan = _buffer.CurrentSnapshot.CreateTrackingSpan(tagSpan, SpanTrackingMode.EdgeExclusive); // quickInfoContent.Add("Question Begin?"); //} } }
public static void ReparseWork(ITextBuffer buffer, string targetFile) { int thisBufferVersion = 0; System.Diagnostics.Debug.WriteLine("Starting ReparseWork..."); // ensure our ParseStatus dictionary of ParseAttribute items has an item for our current file //if (!ParseStatus.ContainsKey(targetFile)) //{ // ParseStatus.Add(targetFile, new ParseAttribute()); //} lock (_synchronizationParseStatus) { VerilogGlobals.ParseStatusController.EnsureExists(targetFile); ParseStatus[targetFile].IsReparsing = true; //IsReparsing = true; if (buffer == null) { ParseStatus[targetFile].IsReparsing = false; // IsReparsing = false; return; } if (buffer.EditInProgress) { ParseStatus[targetFile].IsReparsing = false; // IsReparsing = false; return; } try { thisBufferVersion = buffer.CurrentSnapshot.Version.VersionNumber; } catch { thisBufferVersion = 0; } // if we could not determine a version ( = 0), or if the last time we reparsed was for this same buffer, then exit if ((thisBufferVersion == 0) || (ParseStatus[targetFile].LastReparseVersion == thisBufferVersion)) { ParseStatus[targetFile].IsReparsing = false; // IsReparsing = false; return; } } //if ((DateTime.Now - ProfileStart).TotalMilliseconds < 1000) //{ // ProfileStart = DateTime.Now; // return; // never reparse more than once a second //} ProfileStart = DateTime.Now; ITextSnapshot newSnapshot = buffer.CurrentSnapshot; string thisChar = ""; string lastChar = ""; string thisLine = ""; bool IsActiveLineComment = false; bool IsActiveBlockComment = false; int thisLineNumber = 0; double duration2; double duration3; editingBufferAttributes = new List <BufferAttribute>(); // re-initialize the global editingBufferAttributes used for editing // TODO lock on private object, see _synchronizationParseStatus lock (editingBufferAttributes) { BufferAttribute bufferAttribute = new BufferAttribute(); // // Reparse AppendBufferAttribute // void AppendBufferAttribute() { duration2 = (DateTime.Now - ProfileStart).TotalMilliseconds; bufferAttribute.LineNumber = thisLineNumber; // TODO move this to separate function if (thisModuleName != "") { if (!ModuleNames.ContainsValue(thisModuleName)) { byte thisNewKey; if (ModuleNames.Count < 256) { thisNewKey = (byte)ModuleNames.Count; } else { // TODO this is actually an error! do something here (popup warning?) thisNewKey = 0; // we'll (incorrectly) assume global space if there are more than 255 modules } ModuleNames.Add(thisNewKey, thisModuleName); ModuleKeys.Add(thisModuleName, thisNewKey); // build two dictionaries for runtime performance // create placeholder for variables if (!VerilogVariables.ContainsKey(thisModuleName)) { VerilogVariables.Add(thisModuleName, new Dictionary <string, VerilogTokenTypes> { }); } // ensure VerilogVariableHoverText has a dictionary for [thisModuleName] if (!VerilogVariableHoverText.ContainsKey(thisModuleName)) { VerilogVariableHoverText.Add(thisModuleName, new Dictionary <string, string> { }); } } bufferAttribute.ModuleNameKey = ModuleKeys[thisModuleName]; // ModuleNames.FirstOrDefault(x => x.Value == thisModuleName).Key; // thanks stackoverflow https://stackoverflow.com/questions/2444033/get-dictionary-key-by-value } editingBufferAttributes.Add(bufferAttribute); bufferAttribute = new BufferAttribute(); // set rollover params bufferAttribute.RoundBracketDepth = editingBufferAttributes[editingBufferAttributes.Count - 1].RoundBracketDepth; bufferAttribute.SquareBracketDepth = editingBufferAttributes[editingBufferAttributes.Count - 1].SquareBracketDepth; bufferAttribute.SquigglyBracketDepth = editingBufferAttributes[editingBufferAttributes.Count - 1].SquigglyBracketDepth; bufferAttribute.IsComment = IsActiveBlockComment; bufferAttribute.IsEmpty = true; // although we may have carried over some values, at this point it is still "empty" duration3 = (DateTime.Now - ProfileStart).TotalMilliseconds; } void CharParse() { for (int i = 0; i < thisLine.Length; i++) { thisChar = thisLine.Substring(i, 1); switch (thisChar) { case "[": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.SquareBracketDepth++; bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); } break; case "]": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); bufferAttribute.SquareBracketDepth = (bufferAttribute.SquareBracketDepth > 0) ? (--bufferAttribute.SquareBracketDepth) : 0; } break; case "(": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.RoundBracketDepth++; bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); } break; case ")": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); bufferAttribute.RoundBracketDepth = (bufferAttribute.RoundBracketDepth > 0) ? (--bufferAttribute.RoundBracketDepth) : 0; } break; case "{": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.SquigglyBracketDepth++; bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); } break; case "}": if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.LineStart = i; // brackets are only 1 char long, starting bufferAttribute.LineEnd = i; // and ending at the same positions AppendBufferAttribute(); bufferAttribute.SquigglyBracketDepth = (bufferAttribute.SquigglyBracketDepth > 0) ? (--bufferAttribute.SquigglyBracketDepth) : 0; } break; case "*": // encountered "/*" if (lastChar == "/") { if (IsActiveLineComment || IsActiveBlockComment) { // AttributesChanged = false; // if there's an active line comment - nothing changes! } else { bufferAttribute.LineStart = i - 1; // started on prior char // bufferAttribute.LineEnd TBD IsActiveBlockComment = true; bufferAttribute.IsComment = true; AppendBufferAttribute(); } } else { // AttributesChanged = false; } break; case "/": // check for block comment end "*/" if (lastChar == "*") { if (!IsActiveLineComment) { IsActiveBlockComment = false; bufferAttribute.LineEnd = i; // bufferAttribute.IsComment = false; AppendBufferAttribute(); } else { // AttributesChanged = false; } } else { // detect line comments "//" if (lastChar == "/" && !IsActiveLineComment) // encountered first "//" on a line, can only be ended by new line { IsActiveLineComment = true; bufferAttribute.IsComment = true; bufferAttribute.LineStart = i - 1; // comment actually starts on prior char bufferAttribute.LineEnd = -1; // a value of -1 means the entire line, regardless of actual length. // AttributesChanged = (i > 1); // the attribute of the line will not change if the first char starts a comment AppendBufferAttribute(); } else { // AttributesChanged = false; } } break; default: // we'll keep track of ending string segment that may need to be added below; note if something interesting is found, we'll overwrite these bufferAttribute values, above if (bufferAttribute.LineStart < 0) { bufferAttribute.LineStart = i; // the first time we end up here, is the start of the string that does not match one of the above special cases } bufferAttribute.LineEnd = i; // keep track of the end. break; } lastChar = thisChar; } // end of for loop looking at each char in line } VerilogGlobals.InitHoverBuilder(); double duration4 = (DateTime.Now - ProfileStart).TotalMilliseconds; // reminder bufferAttribute is pointing to the contents of the last item in editingBufferAttributes foreach (var line in newSnapshot.Lines) { //Thread.Sleep(10); thisLine = line.GetText(); thisLineNumber = line.LineNumber; // zero-based line numbers // parse the entire line for tokens double duration6 = (DateTime.Now - ProfileStart).TotalMilliseconds; LineParse(thisLine, thisLineNumber); double duration7 = (DateTime.Now - ProfileStart).TotalMilliseconds; // some things, like bracket depth, require us to look at each character... // we'll build a helper table to be able to lookup bracket depth at // arbitrary points CharParse(); double duration8 = (DateTime.Now - ProfileStart).TotalMilliseconds; lastChar = ""; // the lastChar is irrelevant when spanning multiple lines, as we are only using it for comment detection if (!bufferAttribute.IsEmpty) { AppendBufferAttribute(); } if (editingBufferAttributes.Count > 0) { // when we reach the end of the line, we reach the end of the line comment! IsActiveLineComment = false; } double duration9 = (DateTime.Now - ProfileStart).TotalMilliseconds; if (!BufferFirstParseComplete) { // TODO - this was supposed to help intial file load of large files, but does not seem to help. BufferAttributes = editingBufferAttributes; } } // foreach line } // lock editingBufferAttributes double duration5 = (DateTime.Now - ProfileStart).TotalMilliseconds; // TODO - do we need a final, end-of-file bufferAttribute (probably not) lock (_synchronizationParseStatus) { // in case we got here from someplace that set NeedReparse to true - reset to indicate completion: VerilogGlobals.ParseStatus[targetFile].NeedReparse = true; //VerilogGlobals.NeedReparse = false; VerilogGlobals.ParseStatus[targetFile].LastParseTime = DateTime.Now; //VerilogGlobals.LastParseTime = DateTime.Now; VerilogGlobals.ParseStatus[targetFile].LastReparseVersion = thisBufferVersion; } double duration = (DateTime.Now - ProfileStart).TotalMilliseconds; BufferAttributes = editingBufferAttributes; BufferFirstParseComplete = true; lock (_synchronizationParseStatus) { ParseStatus[targetFile].IsReparsing = false; } } // Reparse