private void BrowseToVariable(string elementName)
        {
            //find variables
            var elementsInScope = FortranSyntaxTreeModel.GetElementsAvailableInScope(
                SyntaxTreeMaintainer.GetSyntaxTrees(),
                GetCurrentMember());

            var firstMatch = elementsInScope.OfType <Variable>().FirstOrDefault(el => Equals(elementName, el.Name));

            if (firstMatch == null)
            {
                // second chance: try items in types:
                var typesInScope = elementsInScope.OfType <Fortran.Elements.Type>().ToList();

                foreach (var type in typesInScope)
                {
                    new FortranDeclarationParser().ParseDeclarationsAndUses(type);
                }

                firstMatch = elementsInScope.OfType <Fortran.Elements.Type>()
                             .SelectMany(t => t.LocalVariables)
                             .FirstOrDefault(el => Equals(elementName, el.Name));

                if (firstMatch == null)
                {
                    return;
                }
            }

            VisualStudio.Goto(firstMatch.Member.Root.CodeFile, firstMatch.Location.Line,
                              firstMatch.Location.Offset + 1);
        }
        private void ShowMethodSignatureAsToolTip(CompletionSession session, IMember currentMember, string currentLine, int currentIndex)
        {
            session.SignatureToolTip = "";

            try
            {
                if (currentMember == null)
                {
                    return;
                }

                var lineParser = new FortranStatementParser();
                var methodName = lineParser.FindMethodAtOffset(currentLine, currentIndex);

                if (String.IsNullOrEmpty(methodName))
                {
                    return;
                }

                var allMethodsInScope = FortranSyntaxTreeModel.GetElementsAvailableInScope(SyntaxTreeMaintainer.GetSyntaxTrees(), currentMember).
                                        OfType <IMethod>();

                var method = allMethodsInScope.FirstOrDefault(m => String.Equals(m.Name, methodName,
                                                                                 StringComparison.InvariantCultureIgnoreCase));

                if (method == null)
                {
                    if (fortranIntrinsics.ContainsKey(methodName))
                    {
                        var intrinsicDoc  = fortranIntrinsics[methodName];
                        var fistLineOfDoc = intrinsicDoc.Split('\n').FirstOrDefault() ?? ""; // take first line of documentation
                        session.SignatureToolTip = fistLineOfDoc;
                    }
                    return;
                }

                var declarationParser = new FortranDeclarationParser();
                var signatureParser   = new FortranSignatureParser();
                declarationParser.ParseDeclarationsAndUses(method);
                signatureParser.ParseMethodSignature(method);

                session.SignatureToolTip = method.Name +
                                           "(" +
                                           String.Join(", ", method.Parameters.Select(p => p.TypeString + " " + p.Name).ToArray()) +
                                           ")";
            }
            catch (Exception e)
            {
                Log.Error("Exception while generating signature tooltip", e);
            }
        }
        private void BrowseToCore(IEnumerable <SearchResult> _matches)
        {
            var matches = _matches.ToList();

            if (matches.Count == 1)
            {
                var match = matches.First();

                if (match.Member is Interface)
                {
                    BrowseToCore(FortranSyntaxTreeModel.FindInterfaceReferences(match.Member as Interface, match.SyntaxTree));
                }
                else
                {
                    VisualStudio.Goto(match.SyntaxTree.CodeFile, match.Member.Location.Line,
                                      match.Member.Location.Offset);
                }
            }
            else if (matches.Count > 1)
            {
                //let user make selection & then do recursive call
                dialog                  = CreateListFindControl();
                dialog.DataSource       = matches.Select(m => m.Member).OfType <object>().ToList();
                dialog.AlwaysShowList   = true;
                dialog.HideSearchDialog = true;
                dialog.MaxResults       = 25;
                dialog.OnGetIconForItem = FortranIconProvider.GetIconForMember;
                dialog.OnGetHintForItem = o => ((IMember)o).GetScopeDescription();
                dialog.DataMember       = "Name";
                dialog.ItemChosen      += (s, e) =>
                {
                    var chosenMember = s as IMember;
                    var match        = matches.First(m => m.Member == chosenMember);
                    BrowseToCore(new[] { match });     //recursive: perhaps user chose interface
                };
                dialog.Show();
            }
        }
        /// <summary>
        /// This method parses the current line, and determines which suggestions to show for code completion (intellisense)
        /// </summary>
        /// <param name="session"></param>
        private void UpdateCodeComplete(CompletionSession session)
        {
            //parse current line
            //set results
            //set filter
            try
            {
                ParseQueueProcessor.ShowProgressDialog = false; //maybe not actually required anymore

                var currentLine = VisualStudio.GetCurrentLine();

                var currentIndex = VisualStudio.GetCursorPositionInLine();

                var lineParser = new FortranStatementParser();

                var beginOfStatement = 0;

                var statement     = lineParser.FindEffectiveStatementAtOffset(currentLine, currentIndex, out beginOfStatement);
                var fullStatement = currentLine.Substring(beginOfStatement, currentIndex - beginOfStatement);

                var currentMember = GetCurrent <IMember>();

                ShowMethodSignatureAsToolTip(session, currentMember, currentLine, currentIndex);

                IList <INameable> codeCompleteOptions;
                var filter = "";
                var addLanguageKeywords = false;
                var codeElementsInScope =
                    FortranSyntaxTreeModel.GetElementsAvailableInScope(SyntaxTreeMaintainer.GetSyntaxTrees(),
                                                                       currentMember);

                // are we in a 'call something' statement?
                var callMatch = callRegex.Match(statement);
                if (callMatch.Success)
                {
                    //only subroutines
                    codeCompleteOptions          = codeElementsInScope.OfType <Subroutine>().Cast <INameable>().ToList(); //subroutines only
                    session.InsertionIndexInLine = beginOfStatement + callMatch.Groups[1].Index;
                    filter = callMatch.Groups[1].Value;
                }
                else if (!statement.Contains('%')) //local scope
                {
                    if (statement.Length > 0 &&
                        FortranParseHelper.IsWhiteSpace(statement[statement.Length - 1]))
                    {
                        //reset: wrong statement:
                        beginOfStatement += statement.Length;
                        statement         = "";
                    }

                    codeCompleteOptions          = codeElementsInScope.Where(ce => !(ce is Subroutine)).ToList(); //subroutines only available after a 'call'
                    session.InsertionIndexInLine = beginOfStatement;
                    filter = statement;
                    addLanguageKeywords = true;
                }
                else // nested in type, eg: channel % sourceNode % id
                {
                    var elements = FortranParseHelper.SplitElementsInStatement(statement, fullStatement, ref beginOfStatement, out filter);

                    if (elements.Count < 1)
                    {
                        throw new NotSupportedException("help!");
                    }

                    var variableName = elements[0];

                    var matchingVariable = codeElementsInScope
                                           .OfType <Variable>()
                                           .FirstOrDefault(lv => String.Equals(lv.Name, variableName, StringComparison.InvariantCultureIgnoreCase));

                    var typeOfVariable = matchingVariable.TypeString;

                    var currentType = codeElementsInScope
                                      .OfType <Type>()
                                      .FirstOrDefault(tp => String.Equals(tp.Name, typeOfVariable, StringComparison.InvariantCultureIgnoreCase));

                    for (int i = 1; i < elements.Count; i++)
                    {
                        if (currentType == null)
                        {
                            break;
                        }

                        var propertyName = elements[i];
                        var property     = GetElementsOfType(currentType).FirstOrDefault(vf => String.Equals(vf.Name, propertyName, StringComparison.InvariantCultureIgnoreCase));

                        typeOfVariable = property.TypeString;

                        currentType = codeElementsInScope
                                      .OfType <Type>()
                                      .FirstOrDefault(tp => String.Equals(tp.Name, typeOfVariable, StringComparison.InvariantCultureIgnoreCase));
                    }

                    if (currentType == null)
                    {
                        codeCompleteOptions = new INameable[] { }
                    }
                    ;
                    else
                    {
                        codeCompleteOptions = GetElementsOfType(currentType).Cast <INameable>().ToList();
                    }

                    session.InsertionIndexInLine = beginOfStatement;
                }

                // gather all results
                var completionItems = codeCompleteOptions.Select(e => new CompletionItem(e.Name, FortranIconProvider.GetIconForMember(e))
                {
                    ToolTip = GetTooltipForMember(currentMember, e)
                }).ToList();
                if (addLanguageKeywords)
                {
                    foreach (var keyword in fortranKeywords)
                    {
                        completionItems.Add(new CompletionItem(keyword, null));
                    }

                    foreach (var intrinsic in fortranIntrinsics)
                    {
                        completionItems.Add(new CompletionItem(intrinsic.Key, IntrinsicIcon)
                        {
                            ToolTip = intrinsic.Value
                        });
                    }
                }
                session.SetCompletionSet(completionItems, filter);
            }
            catch (Exception e)
            {
                Log.Error("Error while updating code complete", e);
            }
            finally
            {
                ParseQueueProcessor.ShowProgressDialog = true; //messes with intellisense popup
            }
        }
        /// <summary>
        /// This method parses the current line, and determines which suggestions to show for code completion (intellisense)
        /// </summary>
        /// <param name="session"></param>
        private void UpdateCodeComplete(CompletionSession session)
        {
            //parse current line
            //set results
            //set filter
            try
            {
                ParseQueueProcessor.ShowProgressDialog = false; //maybe not actually required anymore

                var currentLine = VisualStudio.GetCurrentLine();

                var currentIndex = VisualStudio.GetCursorPositionInLine();

                var lineParser = new FortranStatementParser();

                var beginOfStatement = 0;

                var statement     = lineParser.FindEffectiveStatementAtOffset(currentLine, currentIndex, out beginOfStatement);
                var fullStatement = currentLine.Substring(beginOfStatement, currentIndex - beginOfStatement);

                var currentMember = GetCurrent <IMember>();

                ShowMethodSignatureAsToolTip(session, currentMember, currentLine, currentIndex);

                IList <INameable> codeCompleteOptions;
                var filter = "";
                var addLanguageKeywords = false;
                var codeElementsInScope =
                    FortranSyntaxTreeModel.GetElementsAvailableInScope(SyntaxTreeMaintainer.GetSyntaxTrees(),
                                                                       currentMember);

                // are we in a 'call something' statement?
                var callMatch = callRegex.Match(statement);
                if (callMatch.Success)
                {
                    //only subroutines
                    codeCompleteOptions          = codeElementsInScope.OfType <Subroutine>().Cast <INameable>().ToList(); //subroutines only
                    session.InsertionIndexInLine = beginOfStatement + callMatch.Groups[1].Index;
                    filter = callMatch.Groups[1].Value;
                }
                else if (!statement.Contains('%')) //local scope
                {
                    if (statement.Length > 0 &&
                        FortranParseHelper.IsWhiteSpace(statement[statement.Length - 1]))
                    {
                        //reset: wrong statement:
                        beginOfStatement += statement.Length;
                        statement         = "";
                    }

                    codeCompleteOptions          = codeElementsInScope.Where(ce => !(ce is Subroutine)).ToList(); //subroutines only available after a 'call'
                    session.InsertionIndexInLine = beginOfStatement;
                    filter = statement;
                    addLanguageKeywords = true;
                }
                else // nested in type, eg: channel % sourceNode % id
                {
                    var elements = FortranParseHelper.SplitElementsInStatement(statement, fullStatement, ref beginOfStatement, out filter);

                    if (elements.Count < 1)
                    {
                        throw new NotSupportedException("help!");
                    }

                    var variableName = elements[0];

                    var matchingVariable = codeElementsInScope
                                           .OfType <Variable>()
                                           .FirstOrDefault(lv => String.Equals(lv.Name, variableName, StringComparison.InvariantCultureIgnoreCase));

                    var typeOfVariable = matchingVariable.TypeString;

                    var currentType = codeElementsInScope
                                      .OfType <Type>()
                                      .FirstOrDefault(tp => String.Equals(tp.Name, typeOfVariable, StringComparison.InvariantCultureIgnoreCase));

                    for (int i = 1; i < elements.Count; i++)
                    {
                        if (currentType == null)
                        {
                            break;
                        }

                        var propertyName = elements[i];
                        var property     = GetElementsOfType(currentType).FirstOrDefault(vf => String.Equals(vf.Name, propertyName, StringComparison.InvariantCultureIgnoreCase));

                        typeOfVariable = property.TypeString;

                        currentType = codeElementsInScope
                                      .OfType <Type>()
                                      .FirstOrDefault(tp => String.Equals(tp.Name, typeOfVariable, StringComparison.InvariantCultureIgnoreCase));
                    }

                    if (currentType == null)
                    {
                        codeCompleteOptions = new INameable[] { }
                    }
                    ;
                    else
                    {
                        codeCompleteOptions = GetElementsOfType(currentType).Cast <INameable>().ToList();
                    }

                    session.InsertionIndexInLine = beginOfStatement;
                }

                // gather all results
                var completionItems = codeCompleteOptions.Select(e => new CompletionItem(e.Name, FortranIconProvider.GetIconForMember(e))
                {
                    ToolTip = GetTooltipForMember(currentMember, e)
                }).ToList();
                if (addLanguageKeywords)
                {
                    foreach (var keyword in fortranKeywords)
                    {
                        completionItems.Add(new CompletionItem(keyword, null));
                    }

                    foreach (var intrinsic in fortranIntrinsics)
                    {
                        completionItems.Add(new CompletionItem(intrinsic.Key, IntrinsicIcon)
                        {
                            ToolTip = intrinsic.Value
                        });
                    }
                }

                {//YK, 2020, also add all the words already in this current file
                    //check file content.
                    var myFileContents = VisualStudio.GetCurrentCodeFileContent();

                    {
                        ////two methods to replace \t, \n, \r, tested and works
                        //myFileContents = Regex.Replace(myFileContents, @"\t", " ");
                        ////myFileContents = myFileContents.Replace("\t", " ");
                        //myFileContents = myFileContents.Replace("\r", " ");
                        //myFileContents = myFileContents.Replace("\n", " ");
                    }

                    {//example to remove separator...
                     //char[] separators = new char[] { ' ', ';', ',', '\r', '\t', '\n', '(', ')', '!', ':', '=', '+', '*', '/' };
                     //string s = "replace;multiple,characters\tin;a,c\rsharp,string";
                     //string[] temp = s.Split(separators, StringSplitOptions.RemoveEmptyEntries);
                     //s = String.Join("\n", temp);
                    }

                    {//example to remove duplicated string
                     //String[] a = { "1", "1", "2", "1", "1", "3", "1", "1", };
                     //Console.WriteLine("原数组长度:    {0}", a.Length);
                     //Console.WriteLine("排除后数组长度:{0}", a.Distinct<string>().ToArray().Length);
                     //Console.ReadKey();
                    }

                    char[]   separators = new char[] { ' ', ';', ',', '\r', '\t', '\n', '(', ')', '!', ':', '=', '+', '-', '*', '/', '&', '.', '\'', '<', '>', '{', '}', '[', ']', '$', '%', '?' };
                    string   s          = myFileContents;
                    string[] myFileContentSplittedStr         = myFileContents.Split(separators, StringSplitOptions.RemoveEmptyEntries);
                    string[] myFileContentSplittedStrDistinct = myFileContentSplittedStr.Distinct <string>().ToArray();
                    foreach (var keyword in myFileContentSplittedStrDistinct)
                    {
                        //{//example to add non-duplicated string
                        //    //if (!listString.Contains(eachString))
                        //    //    listString.Add(eachString);
                        //}

                        completionItems.Add(new CompletionItem(keyword, null));
                    }
                }

                session.SetCompletionSet(completionItems, filter);
            }
            catch (Exception e)
            {
                Log.Error("Error while updating code complete", e);
            }
            finally
            {
                ParseQueueProcessor.ShowProgressDialog = true; //messes with intellisense popup
            }
        }