Ejemplo n.º 1
0
            private static PostfixTemplateContext TryReparseWith([NotNull] ISolution solution, [NotNull] ITextControl textControl, [NotNull] string reparseString)
            {
                var offset   = textControl.Caret.Offset();
                var document = textControl.Document;

                try
                {
                    document.InsertText(offset, reparseString);

                    solution.GetPsiServices().Files.CommitAllDocuments();

                    foreach (var position in TextControlToPsi.GetElements <ITreeNode>(solution, document, offset))
                    {
                        var templateContextFactory = LanguageManager.Instance.TryGetService <IPostfixTemplateContextFactory>(position.Language);
                        if (templateContextFactory != null)
                        {
                            var executionContext = new PostfixTemplateExecutionContext(
                                solution, textControl, position.GetSettingsStore(), reparseString, false);

                            return(templateContextFactory.TryCreate(position, executionContext));
                        }
                    }

                    return(null);
                }
                finally
                {
                    var reparseRange = TextRange.FromLength(offset, reparseString.Length);
                    document.DeleteText(reparseRange);
                }
            }
Ejemplo n.º 2
0
            private IList <IPostfixLookupItem> TryReparseWith([NotNull] ISolution solution, [NotNull] ITextControl textControl,
                                                              [NotNull] string templateName, [NotNull] string reparseString)
            {
                var offset   = textControl.Caret.Offset();
                var document = textControl.Document;

                try
                {
                    document.InsertText(offset, reparseString);
                    solution.GetPsiServices().CommitAllDocuments();

                    var itemsOwner       = myItemsOwnerFactory.CreateLookupItemsOwner(textControl);
                    var executionContext = new PostfixExecutionContext(
                        myLifetime, solution, textControl, itemsOwner, reparseString, false);

                    foreach (var position in TextControlToPsi.GetElements <ITokenNode>(solution, document, offset))
                    {
                        var postfixContext = myTemplatesManager.IsAvailable(position, executionContext);
                        if (postfixContext == null)
                        {
                            continue;
                        }

                        return(myTemplatesManager.CollectItems(postfixContext, templateName: templateName));
                    }

                    return(null);
                }
                finally
                {
                    var reparseRange = TextRange.FromLength(offset, reparseString.Length);
                    document.DeleteText(reparseRange);
                }
            }
        private static IEnumerable <LocalOccurrence> SearchInCurrentFile(
            [NotNull] string searchText, [NotNull] IPsiSourceFile sourceFile)
        {
            var document = sourceFile.Document;

            var fileText = document.GetText();

            if (fileText == null)
            {
                yield break;
            }

            var offset = 0;

            while ((offset = fileText.IndexOf(searchText, offset, StringComparison.OrdinalIgnoreCase)) >= 0)
            {
                var occurrenceRange = TextRange.FromLength(offset, searchText.Length);
                var documentRange   = new DocumentRange(document, occurrenceRange);
                var documentLine    = (int)document.GetCoordsByOffset(offset).Line;

                var foundText = fileText.Substring(offset, searchText.Length);

                var leftIndex    = Math.Max(0, offset - 10);
                var leftFragment = fileText.Substring(leftIndex, offset - leftIndex);

                var endOffset     = offset + searchText.Length;
                var rightIndex    = Math.Min(endOffset + 10, fileText.Length);
                var rightFragment = fileText.Substring(endOffset, rightIndex - endOffset);

                yield return(new LocalOccurrence(
                                 documentRange, documentLine, foundText, leftFragment, rightFragment));

                offset++;
            }
        }
        private static void SearchInFile(
            [NotNull] string searchText, [NotNull] IPsiSourceFile sourceFile,
            [NotNull] List <IOccurence> consumer, [NotNull] CheckForInterrupt checkCanceled)
        {
            var fileText = sourceFile.Document.GetText();

            if (fileText == null)
            {
                return;
            }

            var index = 0;

            while ((index = fileText.IndexOf(searchText, index, StringComparison.OrdinalIgnoreCase)) >= 0)
            {
                var occurrenceRange = TextRange.FromLength(index, searchText.Length);
                var documentRange   = new DocumentRange(sourceFile.Document, occurrenceRange);
                var occurrence      = new RangeOccurence(sourceFile, documentRange);

                lock (consumer)
                {
                    consumer.Add(occurrence);
                }

                if (checkCanceled())
                {
                    break;
                }
                index++;
            }
        }
Ejemplo n.º 5
0
        private ReferenceCollection CreateTypeNameReferences(ICSharpLiteralExpression literal,
                                                             ExpectedObjectTypeReferenceKind kind)
        {
            var literalValue = (string)literal.ConstantValue.Value;

            if (literalValue == null)
            {
                return(ReferenceCollection.Empty);
            }

            var symbolCache = literal.GetPsiServices().Symbols;

            IQualifier qualifier    = null;
            var        references   = new LocalList <IReference>();
            var        startIndex   = 0;
            var        nextDotIndex = literalValue.IndexOf('.');

            while (true)
            {
                var endIndex = nextDotIndex != -1 ? nextDotIndex : literalValue.Length;

                // startIndex + 1 to skip leading quote in tree node, which doesn't exist in literalValue
                var rangeWithin = TextRange.FromLength(startIndex + 1, endIndex - startIndex);

                // Behaviour and resolution is almost identical for each part.
                // For a single component, it is either a Unity object with an inferred namespace, a type in the global
                // namespace, or the namespace for an as yet uncompleted qualified type name
                // For a trailing component, it is a qualified reference, and could be a type, or a continuation of the
                // namespace qualification
                // For a middle component, it could be a namespace, or the user typing a new type, with the trailing
                // text being the old component
                // When there is no qualifier, resolve should match:
                // * inferred type, with expected type check
                // * type in global namespace, with expected type check
                // * namespace, with expected type check (so namespace won't be the last thing)
                // When there is a qualifier, resolve should match
                // * namespaces
                // * qualified type with expected type check
                // For the final component, resolve should match namespaces, but with the expected type check
                // At all times, completion should show both namespaces and qualified types
                // Leading and trailing space are treated as part of a name, and will cause resolve to fail
                // TODO: Handle trailing dot
                var isFinalPart = nextDotIndex == -1;
                var reference   = new UnityObjectTypeOrNamespaceReference(literal, qualifier, literal.Literal, rangeWithin,
                                                                          kind, symbolCache, isFinalPart);

                references.Add(reference);
                if (nextDotIndex == -1)
                {
                    break;
                }

                startIndex   = nextDotIndex + 1;
                nextDotIndex = literalValue.IndexOf('.', startIndex);
                qualifier    = reference;
            }

            return(new ReferenceCollection(references.ReadOnlyList()));
        }
        public sealed override TextRange GetTextRangeToDelete()
        {
            if (this.GenerationMode == ByPatternInPlaceGenerationMode.ReplaceMatchedText)
            {
                return(this.MatchResult.GetDocumentRange().TextRange);
            }

            return(TextRange.FromLength(0));
        }
Ejemplo n.º 7
0
 /// <nodoc />
 public static SymbolLocation GetLocationFromNode(INode node, ISymbol symbol)
 {
     return(SymbolLocation.LocalLocation(
                node.GetSourceFile().Path.AbsolutePath,
                TextRange.FromLength(
                    node.GetNodeStartPositionWithoutTrivia(),
                    node.GetNodeWidth()),
                symbol));
 }
Ejemplo n.º 8
0
            public void Execute(IDataContext context, DelegateExecute nextExecute)
            {
                var solution = context.GetData(ProjectModel.DataContext.DataConstants.SOLUTION);

                if (solution == null)
                {
                    return;
                }

                var textControl = context.GetData(TextControl.DataContext.DataConstants.TEXT_CONTROL);

                if (textControl == null)
                {
                    return;
                }

                if (myLookupWindowManager.CurrentLookup != null)
                {
                    return;
                }

                const string commandName  = "Expanding postfix template with [Tab]";
                var          updateCookie = myChangeUnitFactory.CreateChangeUnit(textControl, commandName);

                try
                {
                    using (myCommandProcessor.UsingCommand(commandName))
                    {
                        var postfixItem = GetTemplateFromTextControl(solution, textControl);
                        if (postfixItem != null)
                        {
                            TipsManager.Instance.FeatureIsUsed(
                                "Plugin.ControlFlow.PostfixTemplates.<tab>", textControl.Document, solution);

                            var nameLength = postfixItem.Identity.Length;
                            var offset     = textControl.Caret.Offset() - nameLength;

                            postfixItem.Accept(
                                textControl, TextRange.FromLength(offset, nameLength),
                                LookupItemInsertType.Insert, Suffix.Empty, solution, keepCaretStill: false);

                            return;
                        }

                        updateCookie.Dispose();
                    }
                }
                catch
                {
                    updateCookie.Dispose();
                    throw;
                }

                nextExecute();
            }
Ejemplo n.º 9
0
        public bool Navigate(ISolution solution, PopupWindowContextSource windowContext, bool transferFocus,
                             TabOptions tabOptions = TabOptions.Default)
        {
            var psiFile = mySourceFile.GetPrimaryPsiFile();

            if (psiFile == null || !psiFile.Language.Is <JsonLanguage>())
            {
                return(false);
            }

            var range = TextRange.FromLength(myNavigationTreeOffset, myName.Length);

            return(mySourceFile.Navigate(range, transferFocus, tabOptions, windowContext));
        }
Ejemplo n.º 10
0
        public string DumpToString()
        {
            // +2 for the quotes, +1 to put it after the quote
            var range = TextRange.FromLength(myDeclaredElementTreeOffset, myName.Length + 3);
            var line  = RangeOccurrenceUtil.GetTrimmedLinePossibleMultiline(mySourceFile,
                                                                            range, null, out var occurrenceInLineRange)
                        .Insert(occurrenceInLineRange.StartOffset, "|")
                        .Insert(occurrenceInLineRange.EndOffset, "|");
            var builder = new StringBuilder();

            builder.AppendFormat("TO: [O] {0}", line);
            builder.AppendFormat(" RANGE: {0} @ {1}", range.ToInvariantString(),
                                 mySourceFile.DisplayName);
            return(builder.ToString());
        }
Ejemplo n.º 11
0
            private bool IsAvailableOrExecuteEww([NotNull] ISolution solution, [NotNull] ITextControl textControl, bool execute)
            {
                var offset = textControl.Caret.Offset();
                var prefix = LiveTemplatesManager.GetPrefix(textControl.Document, offset);

                if (!TemplateWithNameExists(prefix))
                {
                    return(false);
                }

                var files        = textControl.Document.GetPsiSourceFiles(solution);
                var allLanguages = files.SelectMany(file => file.GetPsiServices().Files.GetLanguages(file, PsiLanguageCategories.Primary)).Distinct();

                foreach (var psiLanguageType in allLanguages)
                {
                    var contextFactory = LanguageManager.Instance.TryGetService <IPostfixTemplateContextFactory>(psiLanguageType);
                    if (contextFactory == null)
                    {
                        continue;
                    }

                    foreach (var reparseString in contextFactory.GetReparseStrings())
                    {
                        var templateContext = TryReparseWith(solution, textControl, reparseString);
                        if (templateContext != null)
                        {
                            if (!templateContext.IsSemanticallyMakeSence())
                            {
                                return(false);
                            }

                            var templatesManager = LanguageManager.Instance.GetService <IPostfixTemplatesManager>(psiLanguageType);

                            if (execute)
                            {
                                var nameRange = TextRange.FromLength(offset - prefix.Length, prefix.Length);
                                templatesManager.ExecuteTemplateByName(templateContext, prefix, textControl, nameRange);
                                return(true);
                            }

                            return(templatesManager.IsTemplateAvailableByName(templateContext, prefix));
                        }
                    }
                }

                return(false);
            }
        public override void Execute(IDataContext context, DelegateExecute nextExecute)
        {
            var solution = context.GetData(ProjectModel.DataContext.DataConstants.SOLUTION);

            Assertion.AssertNotNull(solution, "solution == null");
            var textControl = context.GetData(TextControl.DataContext.DataConstants.TEXT_CONTROL);

            Assertion.AssertNotNull(textControl, "textControl == null");

            var commandProcessor           = Shell.Instance.GetComponent <ICommandProcessor>();
            var documentTransactionManager = solution.GetComponent <DocumentTransactionManager>();

            using (commandProcessor.UsingCommand("ZenCoding"))
            {
                using (documentTransactionManager.CreateTransactionCookie(DefaultAction.Commit, "ZenCoding"))
                {
                    string abbr;
                    var    abbrRange = textControl.Selection.OneDocRangeWithCaret();
                    if (abbrRange.IsValid && abbrRange.Length > 0)
                    {
                        abbr = textControl.Document.GetText(abbrRange);
                    }
                    else
                    {
                        var coords = textControl.Caret.PositionValue.ToDocLineColumn();
                        int start;
                        var engine   = GetEngine(solution);
                        var lineText = textControl.Document.GetLineText(coords.Line);
                        abbr = engine.FindAbbreviationInLine(lineText, (int)coords.Column, out start);
                        if (start == -1)
                        {
                            Win32Declarations.MessageBeep(MessageBeepType.Error);
                            return;
                        }
                        abbrRange = TextRange
                                    .FromLength(textControl.Caret.PositionValue.ToDocOffset(), -abbr.Length)
                                    .Normalized();
                    }

                    int insertPoint;
                    var projectFile = textControl.ToProjectFile(solution);
                    var expanded    = GetEngine(solution).ExpandAbbreviation(abbr, GetDocTypeForFile(projectFile), out insertPoint);
                    CheckAndIndent(solution, projectFile, textControl, abbrRange, expanded, insertPoint);
                }
            }
        }
Ejemplo n.º 13
0
        private TextRange GetPostfixRange([NotNull] ITextControl textControl, TextRange nameRange)
        {
            Assertion.Assert(nameRange.IsValid, "nameRange.IsValid");

            var length    = nameRange.Length + myReparseString.Length;
            var textRange = TextRange.FromLength(nameRange.StartOffset, length);

            // find dot before postfix template name
            var buffer = textControl.Document.Buffer;

            for (var index = nameRange.StartOffset - 1; index > 0; index--)
            {
                if (buffer[index] == '.')
                {
                    return(textRange.SetStartTo(index));
                }
            }

            return(textRange);
        }
        protected override IReference BindToInternal(IDeclaredElement declaredElement, ISubstitution substitution)
        {
            // Fix up name
            if (declaredElement.ShortName != GetName())
            {
                var newReference = ReferenceWithinElementUtil <ITokenNode> .SetText(this, declaredElement.ShortName,
                                                                                    (node, buffer) =>
                {
                    // The new name is substituted into the existing text, which includes quotes
                    var unquotedStringValue = buffer.GetText(TextRange.FromLength(1, buffer.Length - 2));
                    return(CSharpElementFactory.GetInstance(node)
                           .CreateStringLiteralExpression(unquotedStringValue)
                           .Literal);
                });

                return(newReference.BindTo(declaredElement));
            }

            // Fix up qualification (e.g. move namespace)
            if (declaredElement is ITypeElement newType && !newType.Equals(Resolve().DeclaredElement))
            {
                var oldRange = new TreeTextRange(TreeOffset.Zero, new TreeOffset(myOwner.GetTextLength()));
                ReferenceWithinElementUtil <ITokenNode> .SetText(myOwner.Literal, oldRange,
                                                                 newType.GetClrName().FullName, (node, buffer) =>
                {
                    // We're replacing the whole text and don't provide quotes in the new string
                    var unquotedStringValue = buffer.GetText();
                    return(CSharpElementFactory.GetInstance(node)
                           .CreateStringLiteralExpression(unquotedStringValue)
                           .Literal);
                }, myOwner);

                var newReference = myOwner.FindReference <UnityObjectTypeOrNamespaceReference>(r => r.myIsFinalPart);
                Assertion.AssertNotNull(newReference, "newReference != null");
                return(newReference);
            }

            return(this);
        }
Ejemplo n.º 15
0
        private static string InsertQualifierAsArgument([NotNull] ICSharpExpression qualifierExpression,
                                                        [NotNull] IList <IMethod> allMethods, int argumentsCount,
                                                        [NotNull] ITextControl textControl, TextRange decoration,
                                                        [NotNull] string decorationText)
        {
            var qualifierText = qualifierExpression.GetText();

            var enumerationType = FindEnumerationType(qualifierExpression);

            if (enumerationType != null)
            {
                qualifierText = "typeof(" + qualifierText + ")";
            }

            if (FirstArgumentAlwaysPassByRef(allMethods))
            {
                qualifierText = "ref " + qualifierText;
            }

            if (argumentsCount > 0 || HasOnlyMultipleParameters(allMethods))
            {
                qualifierText += ", ";
            }

            var parenthesisOpenIndex = decorationText.IndexOf('(');

            if (parenthesisOpenIndex < 0)
            {
                qualifierText = "(" + qualifierText;
            }

            // insert qualifier as first argument
            var shift       = (parenthesisOpenIndex >= 0) ? parenthesisOpenIndex + 1 : decoration.Length;
            var argPosition = TextRange.FromLength(decoration.StartOffset + shift, 0);

            textControl.Document.ReplaceText(argPosition, qualifierText);
            return(qualifierText);
        }
Ejemplo n.º 16
0
        public void ShowMenu(
            [NotNull] IProjectModelElement projectElement, [CanBeNull] ITextControl textControl,
            [CanBeNull] GotoByNameDataConstants.SearchTextData initialText)
        {
            var solution   = projectElement.GetSolution();
            var definition = Lifetimes.Define(solution.GetLifetime());

            var controller = new GotoWordController(
                definition.Lifetime, myShellLocks, projectElement, textControl);

            if (textControl != null)
            {
                // use selected text if there is no initial
                // todo: how to make this work with recent list?
                var selection = textControl.Selection.Ranges.Value;
                if (selection != null && selection.Count == 1)
                {
                    var docRange = selection[0].ToDocRangeNormalized();
                    if (docRange.Length > 0)
                    {
                        var selectedText = textControl.Document.GetText(docRange);
                        initialText = new GotoByNameDataConstants.SearchTextData(
                            selectedText, TextRange.FromLength(selectedText.Length));
                    }
                }
            }

            var menu = new GotoByNameMenu(
                myMenuComponent, definition, controller.Model,
                myUiApplication.MainWindow, initialText);

            var menuDoc = menu.MenuView.Value.Document.NotNull("menuDoc != null");

            menuDoc.SelectedItem.FlowInto(
                definition.Lifetime, controller.SelectedItem,
                FConverter: item => (item != null) ? item.Key : null);
        }
Ejemplo n.º 17
0
        private ILookupItem CreateMethodItem(CSharpCodeCompletionContext context,
                                             UnityEventFunction eventFunction, IClassLikeDeclaration declaration,
                                             bool hasReturnType, AccessRights accessRights,
                                             MemberGenerationContext generationContext)
        {
            if (CSharpLanguage.Instance == null)
            {
                return(null);
            }

            // Only show the modifier in the list text if it's not already specified and there isn't a return type, in
            // which case we default to `private`. E.g. if someone types `OnAnim`, then show `private void OnAnimate...`
            // but if they type `void OnAnim`, they don't want a modifier, and if they type `public void OnAnim` then
            // they want to use `public`
            var showModifier = false;

            if (!hasReturnType && accessRights == AccessRights.NONE)
            {
                showModifier = true;
                accessRights = AccessRights.PRIVATE;
            }

            // Note that we can't keep this declaration - it will become invalid as the user types to narrow down the
            // search and modifies the PSI file. This only affects ReSharper, Rider has different code completion
            // mechanism
            var factory           = CSharpElementFactory.GetInstance(declaration, false);
            var methodDeclaration = eventFunction.CreateDeclaration(factory, declaration, accessRights);

            if (methodDeclaration.DeclaredElement == null)
            {
                return(null);
            }

            // This is effectively the same as GenerateMemberPresentation, but without the overhead that comes
            // with the flexibility of formatting any time of declared element. We just hard code the format
            var predefinedType = context.PsiModule.GetPredefinedType();
            var parameters     = string.Empty;

            if (eventFunction.Parameters.Length > 0)
            {
                var sb = new StringBuilder();
                for (var i = 0; i < eventFunction.Parameters.Length; i++)
                {
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }

                    var parameter = eventFunction.Parameters[i];
                    var type      = predefinedType.TryGetType(parameter.ClrTypeName, NullableAnnotation.Unknown);
                    var typeName  = type?.GetPresentableName(CSharpLanguage.Instance) ??
                                    parameter.ClrTypeName.ShortName;
                    sb.AppendFormat("{0}{1}{2}", parameter.IsByRef ? "out" : string.Empty,
                                    typeName, parameter.IsArray ? "[]" : string.Empty);
                }
                parameters = sb.ToString();
            }
            var text            = $"{eventFunction.Name}({parameters})";
            var parameterOffset = eventFunction.Name.Length;

            var modifier = showModifier
                ? CSharpDeclaredElementPresenter.Instance.Format(accessRights) + " "
                : string.Empty;

            var psiIconManager = context.BasicContext.LookupItemsOwner.Services.PsiIconManager;

            // Note that because this is a text based lookup item, then it won't be included if the normal C# method
            // filter is applied. We can't make it a method based lookup item because the DeclaredElement isn't valid in
            // this situation - it's not a real method, and a DeclaredElementInfo would try to store a pointer to it,
            // and be unable to recreate it when it's needed.
            var textualInfo = new UnityEventFunctionTextualInfo(generationContext.MemberReplaceRanges, text, text)
            {
                Ranges = context.CompletionRanges
            };

            var lookupItem = LookupItemFactory.CreateLookupItem(textualInfo)
                             .WithPresentation(item =>
            {
                var displayName = new RichText($"{modifier}{text} {{ ... }}");

                // GenerateMemberPresentation marks everything as bold, and the parameters + block syntax as not important
                var parameterStartOffset = modifier.Length + parameterOffset;
                LookupUtil.MarkAsNotImportant(displayName,
                                              TextRange.FromLength(parameterStartOffset, displayName.Length - parameterStartOffset));
                LookupUtil.AddEmphasize(displayName, new TextRange(modifier.Length, displayName.Length));

                var image = psiIconManager.GetImage(CLRDeclaredElementType.METHOD);
                psiIconManager.AttachExtensions(image, GetAccessExtensions(accessRights));
                var marker = item.Info.Ranges.CreateVisualReplaceRangeMarker();
                return(new SimplePresentation(displayName, image, marker));
            })
                             .WithBehavior(_ => new UnityEventFunctionBehavior(textualInfo, eventFunction, accessRights))
                             .WithMatcher(_ =>
                                          new ShiftedDeclaredElementMatcher(eventFunction.Name, modifier.Length, textualInfo));

            var description = GetDescription(context, methodDeclaration);

            return(new WrappedLookupItem(lookupItem, description));
        }
Ejemplo n.º 18
0
        private ILookupItem CreateMethodItem(CSharpCodeCompletionContext context,
                                             UnityEventFunction eventFunction, IClassLikeDeclaration declaration,
                                             bool hasReturnType, AccessRights accessRights)
        {
            if (CSharpLanguage.Instance == null)
            {
                return(null);
            }

            // Only show the modifier in the list text if it's not already specified and there isn't a return type, in
            // which case we default to `private`. E.g. if someone types `OnAnim`, then show `private void OnAnimate...`
            // but if they type `void OnAnim`, they don't want a modifier, and if they type `public void OnAnim` then
            // they want to use `public`
            var showModifier = false;

            if (!hasReturnType && accessRights == AccessRights.NONE)
            {
                showModifier = true;
                accessRights = AccessRights.PRIVATE;
            }

            var factory           = CSharpElementFactory.GetInstance(declaration, false);
            var methodDeclaration = eventFunction.CreateDeclaration(factory, declaration, accessRights);

            if (methodDeclaration.DeclaredElement == null)
            {
                return(null);
            }

            var instance = new DeclaredElementInstance(methodDeclaration.DeclaredElement);

            var declaredElementInfo = new DeclaredElementInfoWithoutParameterInfo(methodDeclaration.DeclaredName,
                                                                                  instance, CSharpLanguage.Instance, context.BasicContext.LookupItemsOwner, context)
            {
                Ranges = context.CompletionRanges
            };

            // This is effectively the same as GenerateMemberPresentation, but without the overhead that comes
            // with the flexibility of formatting any time of declared element. We just hard code the format
            var predefinedType = context.PsiModule.GetPredefinedType();
            var parameters     = string.Empty;

            if (eventFunction.Parameters.Length > 0)
            {
                var sb = new StringBuilder();
                for (var i = 0; i < eventFunction.Parameters.Length; i++)
                {
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }

                    var parameter = eventFunction.Parameters[i];
                    var type      = predefinedType.TryGetType(parameter.ClrTypeName, NullableAnnotation.Unknown);
                    var typeName  = type?.GetPresentableName(CSharpLanguage.Instance) ??
                                    parameter.ClrTypeName.ShortName;
                    sb.AppendFormat("{0}{1}{2}", parameter.IsByRef ? "out" : string.Empty,
                                    typeName, parameter.IsArray ? "[]" : string.Empty);
                }
                parameters = sb.ToString();
            }
            var text            = $"{eventFunction.Name}({parameters})";
            var parameterOffset = eventFunction.Name.Length;

            var modifier = showModifier
                ? CSharpDeclaredElementPresenter.Instance.Format(accessRights) + " "
                : string.Empty;

            var psiIconManager = context.BasicContext.LookupItemsOwner.Services.PsiIconManager;

            return(LookupItemFactory.CreateLookupItem(declaredElementInfo)
                   .WithPresentation(item =>
            {
                var displayName = new RichText($"{modifier}{text} {{ ... }}");

                // GenerateMemberPresentation marks everything as bold, and the parameters + block syntax as not important
                var parameterStartOffset = modifier.Length + parameterOffset;
                LookupUtil.MarkAsNotImportant(displayName,
                                              TextRange.FromLength(parameterStartOffset, displayName.Length - parameterStartOffset));
                LookupUtil.AddEmphasize(displayName, new TextRange(modifier.Length, displayName.Length));

                var image = psiIconManager.GetImage(methodDeclaration.DeclaredElement,
                                                    methodDeclaration.DeclaredElement.PresentationLanguage, true);
                var marker = item.Info.Ranges.CreateVisualReplaceRangeMarker();
                return new SimplePresentation(displayName, image, marker);
            })
                   .WithBehavior(_ => new UnityEventFunctionBehavior(myShellLocks, declaredElementInfo, eventFunction, accessRights))
                   .WithMatcher(_ =>
                                new ShiftedDeclaredElementMatcher(eventFunction.Name, modifier.Length, declaredElementInfo,
                                                                  context.BasicContext.IdentifierMatchingStyle)));
        }
Ejemplo n.º 19
0
        protected override void DoTest(IProject testProject)
        {
            var positionsToCheck = GetCaretPositions().DefaultIfEmpty(GetCaretPosition()).ToList();

            Assert.IsNotEmpty(positionsToCheck, "Nothing to check - put {caret} where necessary");

            var reparsedNodes = new List <ITreeNode>();

            ShellInstance.GetComponent <TestIdGenerator>().Reset();
            var psiFiles = Solution.GetPsiServices().Files;

            void PsiChanged(ITreeNode node, PsiChangedElementType type)
            {
                if (node != null)
                {
                    reparsedNodes.Add(node);
                }
            }

            psiFiles.AfterPsiChanged += PsiChanged;

            try
            {
                var textControl = OpenTextControl();
                {
                    using (CompilationContextCookie.GetOrCreate(testProject.GetResolveContext()))
                    {
                        // number of original files
                        var originalFiles = new Dictionary <IPsiSourceFile, int>();
                        foreach (var caretPosition in positionsToCheck)
                        {
                            var projectFile = GetProjectFile(testProject, caretPosition.FileName);
                            Assert.NotNull(projectFile);

                            foreach (var psiSourceFile in projectFile.ToSourceFiles())
                            {
                                originalFiles.Add(psiSourceFile, GetPsiFiles(psiSourceFile).Count);
                            }
                        }

                        var checkAll = GetSetting(textControl.Document.Buffer, "CHECKALL");

                        // change text
                        var actions = GetSettings(textControl.Document.Buffer, "ACTION");
                        if (actions.Count == 0)
                        {
                            throw new Exception("No actions found");
                        }
                        foreach (var action in actions)
                        {
                            if (action.Length == 0)
                            {
                                continue;
                            }
                            var text = action.Substring(1).Replace("{LEFT}", "{").Replace("{RIGHT}", "}");
                            switch (action.ToCharArray()[0])
                            {
                            case '+':
                                textControl.Document.InsertText(textControl.Caret.Offset(), text);
                                break;

                            case '-':
                                textControl.Document.DeleteText(TextRange.FromLength(textControl.Caret.Offset(), Convert.ToInt32(text)));
                                break;

                            case '>':
                                textControl.Caret.MoveTo(textControl.Caret.Offset() + Convert.ToInt32(text),
                                                         CaretVisualPlacement.Generic);
                                break;

                            case '<':
                                textControl.Caret.MoveTo(textControl.Caret.Offset() - Convert.ToInt32(text),
                                                         CaretVisualPlacement.Generic);
                                break;

                            default:
                                var actionManager = ShellInstance.GetComponent <IActionManager>();
                                actionManager.Defs.GetActionDefById(TextControlActions.Composition.Compose(action, false))
                                .EvaluateAndExecute(actionManager);
                                break;
                            }

                            if (String.Equals(checkAll, "true", StringComparison.InvariantCultureIgnoreCase))
                            {
                                foreach (var data in originalFiles)
                                {
                                    GetPsiFiles(data.Key);
                                }
                            }
                        }

                        foreach (var data in originalFiles)
                        {
                            var psiSourceFile = data.Key;

                            Assert.IsTrue(psiSourceFile.IsValid());

                            // get reparsed files
                            var reparsedFiles = GetPsiFiles(psiSourceFile);

                            Assert.AreEqual(reparsedFiles.Count, data.Value, "Reparsed psi files count mismatch for {0}", psiSourceFile);

                            // check reparsed element
                            ExecuteWithGold(psiSourceFile, writer =>
                            {
                                if (reparsedNodes.IsEmpty())
                                {
                                    writer.Write("Fully reparsed");
                                }
                                else
                                {
                                    reparsedNodes.Sort((n1, n2) => String.CompareOrdinal(n1.Language.Name, n2.Language.Name));
                                    foreach (var reparsedNode in reparsedNodes)
                                    {
                                        if (reparsedNode is IFile)
                                        {
                                            writer.WriteLine("{0}: Fully reparsed", reparsedNode.Language);
                                        }
                                        else
                                        {
                                            var nodeType = reparsedNode.GetType();
                                            writer.WriteLine("{0}: reparsed node type: {1}, text: {2}", reparsedNode.Language,
                                                             PresentNodeType(nodeType), reparsedNode.GetText());
                                        }
                                    }
                                }
                                if (DoDumpRanges)
                                {
                                    DumpRanges <PsiLanguageType>(psiSourceFile, writer);
                                }
                            });

                            // drop psi files cache
                            WriteLockCookie.Execute(() => psiFiles.MarkAsDirty(psiSourceFile));

                            var files = GetPsiFiles(psiSourceFile);
                            Assert.AreEqual(files.Count, reparsedFiles.Count, "Psi files count mismatch");

                            foreach (var pair in files)
                            {
                                var language = pair.Key;
                                Assert.IsTrue(reparsedFiles.TryGetValue(language, out var reparsedFile), "Failed to find psi file for {0}", language);

                                CompareTrees(pair.Value, reparsedFile);
                            }
                        }
                    }
                }
            }
            finally
            {
                psiFiles.AfterPsiChanged -= PsiChanged;
                reparsedNodes.Clear();
            }
        }
        private static ILookupItem CreateMethodItem(CSharpCodeCompletionContext context,
                                                    UnityEventFunction eventFunction, IClassLikeDeclaration declaration, bool addModifier)
        {
            if (CSharpLanguage.Instance == null)
            {
                return(null);
            }

            var method = eventFunction.CreateDeclaration(CSharpElementFactory.GetInstance(declaration, false), declaration);

            if (method.DeclaredElement == null)
            {
                return(null);
            }

            var instance = new DeclaredElementInstance(method.DeclaredElement);

            var declaredElementInfo = new DeclaredElementInfoWithoutParameterInfo(method.DeclaredName, instance, CSharpLanguage.Instance,
                                                                                  context.BasicContext.LookupItemsOwner, context)
            {
                Ranges = context.CompletionRanges
            };

            // This is effectively the same as GenerateMemberPresentation, but without the overhead that comes
            // with the flexibility of formatting any time of declared element. We just hard code the format
            var predefinedType = context.PsiModule.GetPredefinedType();
            var parameters     = string.Empty;

            if (eventFunction.Parameters.Length > 0)
            {
                var sb = new StringBuilder();
                for (var i = 0; i < eventFunction.Parameters.Length; i++)
                {
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }

                    var parameter = eventFunction.Parameters[i];
                    var type      = predefinedType.TryGetType(parameter.ClrTypeName);
                    var typeName  = type?.GetPresentableName(CSharpLanguage.Instance) ??
                                    parameter.ClrTypeName.ShortName;
                    sb.AppendFormat("{0}{1}{2}", parameter.IsByRef ? "out" : string.Empty,
                                    typeName, parameter.IsArray ? "[]" : string.Empty);
                }
                parameters = sb.ToString();
            }
            var text            = $"{eventFunction.Name}({parameters})";
            var parameterOffset = eventFunction.Name.Length;
            var modifier        = addModifier ? "private " : string.Empty;

            var psiIconManager = context.BasicContext.LookupItemsOwner.Services.PsiIconManager;

            return(LookupItemFactory.CreateLookupItem(declaredElementInfo)
                   .WithPresentation(item =>
            {
                var displayName = new RichText($"{modifier}{text} {{ ... }}");

                // GenerateMemberPresentation marks everything as bold, and the parameters + block syntax as not important
                var parameterStartOffset = modifier.Length + parameterOffset;
                LookupUtil.MarkAsNotImportant(displayName,
                                              TextRange.FromLength(parameterStartOffset, displayName.Length - parameterStartOffset));
                LookupUtil.AddEmphasize(displayName, new TextRange(modifier.Length, displayName.Length));

                var image = psiIconManager.GetImage(CLRDeclaredElementType.METHOD, PsiIconExtension.Private);
                var marker = item.Info.Ranges.CreateVisualReplaceRangeMarker();
                return new SimplePresentation(displayName, image, marker);
            })
                   .WithBehavior(_ => new UnityEventFunctionBehavior(declaredElementInfo, eventFunction))
                   .WithMatcher(_ =>
                                new ShiftedDeclaredElementMatcher(text, modifier.Length, declaredElementInfo,
                                                                  context.BasicContext.IdentifierMatchingStyle)));
        }