Пример #1
0
        /// <summary>
        /// Return an enumerable of suitable edits to add open directives for all given namespaces for which no open directive already exists.
        /// Returns an edit for opening a given namespace even if an alias is already defined for that namespace.
        /// Returns an empty enumerable if suitable edits could not be determined.
        /// </summary>
        private static IEnumerable <TextEdit> OpenDirectiveSuggestions(this FileContentManager file, int lineNr, IEnumerable <string> namespaces)
        {
            // determine the first fragment in the containing namespace
            var nsElements = file?.NamespaceDeclarationTokens()
                             .TakeWhile(t => t.Line <= lineNr).LastOrDefault() // going by line here is fine - inaccuracies if someone has multiple namespace and callable declarations on the same line seem acceptable...
                             ?.GetChildren(deep: false);
            var firstInNs = nsElements?.FirstOrDefault()?.GetFragment();

            if (file is null || nsElements is null || firstInNs?.Kind == null)
            {
                return(Enumerable.Empty <TextEdit>());
            }

            // determine what open directives already exist
            var insertOpenDirAt = firstInNs.Range.Start;
            var openDirs        = nsElements.SelectNotNull(t => t.GetFragment().Kind?.OpenedNamespace())
                                  .TakeWhile(opened => opened.IsValue)
                                  .Select(opened => (
                                              opened.Item.Item1.Symbol.AsDeclarationName(null),
                                              opened.Item.Item2.IsValue ? opened.Item.Item2.Item.Symbol.AsDeclarationName("") : null))
                                  .Where(opened => opened.Item1 != null)
                                  .GroupBy(opened => opened.Item1, opened => opened.Item2) // in case there are duplicate open directives...
                                  .ToImmutableDictionary(opened => opened.Key, opened => opened.First());

            // range and whitespace info for inserting open directives
            var additionalLinesAfterOpenDir = firstInNs.Kind.OpenedNamespace().IsNull ? $"{Environment.NewLine}{Environment.NewLine}" : "";
            var indentationAfterOpenDir     = file.GetLine(insertOpenDirAt.Line).Text.Substring(0, insertOpenDirAt.Column);
            var whitespaceAfterOpenDir      = $"{Environment.NewLine}{additionalLinesAfterOpenDir}{(string.IsNullOrWhiteSpace(indentationAfterOpenDir) ? indentationAfterOpenDir : "    ")}";

            // construct a suitable edit
            return(namespaces.Distinct().Where(ns => !openDirs.Contains(ns, null)).Select(suggestedNS => // filter all namespaces that are already open
            {
                var directive = $"{Keywords.importDirectiveHeader.id} {suggestedNS}";
                return new TextEdit
                {
                    Range = new Lsp.Range {
                        Start = insertOpenDirAt.ToLsp(), End = insertOpenDirAt.ToLsp()
                    },
                    NewText = $"{directive};{whitespaceAfterOpenDir}"
                };
            }));
        }