private void StartOrEndBold(StringBuilder stringBuilder, MarkupKind markupKind) { if (markupKind == MarkupKind.Markdown) { stringBuilder.Append("**"); } }
public void Execute(IToolServices toolService) { Position position = toolService.PointerOverPosition; MarkupInfo markups = toolService.Node.Markups; MarkupKind markupKindOnPosition = markups.RemoveMarkupOnPosition(position); if (SequenceMarkup == SequenceMarkupKind.Letter) { char letter = markups.GetSmallestUnusedLetter(); if (letter != '0' && markupKindOnPosition != MarkupKind.Label) { markups.AddMarkup <Label>(new Label(position, letter.ToString())); } } else { int number = markups.GetSmallestUnusedNumber(); if (markupKindOnPosition != MarkupKind.Label) { markups.AddMarkup <Label>(new Label(position, number.ToString())); } } _shadows = toolService.Node.Markups.FillSequenceShadowMap(toolService.GameTree.BoardSize, SequenceMarkup); }
public object Initialize(JToken arg) { /* We want to support the hover capability. When we get a hover request we will respond * with the appropriate text. * Check the client's declared capabilities to identify what hover format the client expects * before returning a hover response from the server. Stash away the expected format for use * when composing the hover response. */ var b = arg.ToObject <InitializeParams>(); MarkupKind[] m = b.Capabilities.TextDocument.Hover.ContentFormat; // in the case of Visual Studio, this is what I am observing. Capturing that as an assertion // just in case things change. System.Diagnostics.Debug.Assert(m != null && m.Length == 1 && m[0] == MarkupKind.PlainText); HoverContentFormat = m[0]; /* *"hover" is the only capability that we wil report back as supported. */ var capabilities = new ServerCapabilities(); capabilities.HoverProvider = true; var result = new InitializeResult(); result.Capabilities = capabilities; Initialized?.Invoke(this, new EventArgs()); return(result); }
/* * We could potentially provide a variety of features here. * But I will keep this simple. I unpack the parameters to extract the file name and hover position * and use that as the payload for my remote method call. */ internal void OnTextDocumentHovered(TextDocumentPositionParams parameter, MarkupKind m) { string markupkind = m.ToString(); string msg = string.Empty; if (m == MarkupKind.PlainText) { msg = "The bar LSP - " + " File: " + parameter.TextDocument.Uri.AbsolutePath + " Line: " + parameter.Position.Line + " Character: " + parameter.Position.Character + " HoverContentFormat: " + markupkind; } else if (m == MarkupKind.Markdown) { // should never be taken in Visual Studio as per my observation. See assertion in // LanguageServerTarget.Initialize(). // Even if we force this path via the debugger, the below text is not interpreted // as markdown when displayed in VS. msg = "The bar LSP - " + " **File:** " + parameter.TextDocument.Uri.AbsolutePath + " _Line:_ " + parameter.Position.Line + " _Character:_ " + parameter.Position.Character + " **HoverContentFormat:** " + markupkind; } else { msg = "The bar LSP - " + " HoverContentFormat: " + "unknown."; System.Diagnostics.Debug.Fail("unknown hover content format"); // just for me to break in and attach the debugger. } // Send a informational message this.ShowMessage(msg, MessageType.Info); }
public void Execute(IToolServices toolService) { Position position = toolService.PointerOverPosition; MarkupInfo markups = toolService.Node.Markups; MarkupKind markupKindOnPosition = markups.RemoveMarkupOnPosition(position); // If the removed markup is the same as the new one than do not add anything. if (IsMarkupEqual(SimpleMarkup, markupKindOnPosition)) { return; } if (SimpleMarkup == SimpleMarkupKind.Circle) { markups.AddMarkup <Circle>(new Circle(position)); } if (SimpleMarkup == SimpleMarkupKind.Cross) { markups.AddMarkup <Cross>(new Cross(position)); } if (SimpleMarkup == SimpleMarkupKind.Square) { markups.AddMarkup <Square>(new Square(position)); } if (SimpleMarkup == SimpleMarkupKind.Triangle) { markups.AddMarkup <Triangle>(new Triangle(position)); } }
/// <summary> /// Returns information about the item at the specified position as Hover information. /// Returns null if some parameters are unspecified (null), /// or if the specified position is not a valid position within the currently processed file content, /// or if no token exists at the specified position. /// </summary> public static Hover?HoverInformation( this FileContentManager file, CompilationUnit compilation, Position?position, MarkupKind format = MarkupKind.PlainText) { Hover?GetHover(string?info) => info == null ? null : new Hover { Contents = new MarkupContent { Kind = format, Value = info }, Range = new Lsp.Range { Start = position?.ToLsp(), End = position?.ToLsp() } }; var markdown = format == MarkupKind.Markdown; var symbolInfo = file?.TryGetQsSymbolInfo(position, false, out var _); if (file is null || symbolInfo == null || compilation == null || position is null) { return(null); } if (symbolInfo.UsedLiterals.Any()) { return(GetHover(symbolInfo.UsedLiterals.Single().LiteralInfo(markdown))); } var locals = compilation.TryGetLocalDeclarations(file, position, out var cName, includeDeclaredAtPosition: true); var nsName = cName?.Namespace ?? file.TryGetNamespaceAt(position); if (nsName == null) { return(null); } // TODO: add hover for functor generators and functor applications // TODO: add hover for new array expr ? // TODO: add nested types - requires dropping the .Single and actually resolving to the closest match! return(GetHover(symbolInfo.UsedVariables.Any() ? compilation.GlobalSymbols.VariableInfo(locals, nsName, file.FileName, symbolInfo.UsedVariables.Single(), markdown) : symbolInfo.UsedTypes.Any() ? compilation.GlobalSymbols.TypeInfo(nsName, file.FileName, symbolInfo.UsedTypes.Single(), markdown) : symbolInfo.DeclaredSymbols.Any() ? compilation.GlobalSymbols.DeclarationInfo(locals, nsName, file.FileName, symbolInfo.DeclaredSymbols.Single(), markdown) : null)); }
/// <summary> /// Indicates whether the given markups have the same type. /// </summary> /// <param name="simpleMarkupKind">Markup kind.</param> /// <param name="markupKind">Other markup kind.</param> /// <returns>True, if the type of given markups equals.</returns> private bool IsMarkupEqual(SimpleMarkupKind simpleMarkupKind, MarkupKind markupKind) { switch (simpleMarkupKind) { case SimpleMarkupKind.Circle: return(markupKind == MarkupKind.Circle); case SimpleMarkupKind.Cross: return(markupKind == MarkupKind.Cross); case SimpleMarkupKind.Square: return(markupKind == MarkupKind.Square); case SimpleMarkupKind.Triangle: return(markupKind == MarkupKind.Triangle); } return(false); }
/// <summary> /// Resolves additional information for the given completion item. Returns the original completion item if no /// additional information is available, or if the completion item is no longer valid or accurate. /// <para/> /// Returns null if any parameter is null or the file given in the original completion request is invalid or /// ignored. /// </summary> internal CompletionItem ResolveCompletion(CompletionItem item, CompletionItemData data, MarkupKind format) => item != null && ValidFileUri(data?.TextDocument?.Uri) && !IgnoreFile(data.TextDocument.Uri) ? this.Projects.ResolveCompletion(item, data, format) : null;
/// <summary> /// Returns information about the item at the specified position as Hover information. /// Returns null if the given file is listed as to be ignored, /// or if some parameters are unspecified (null), /// or if the specified position is not a valid position within the currently processed file content, /// or if no token exists at the specified position at this time. /// </summary> public Hover HoverInformation(TextDocumentPositionParams param, MarkupKind format = MarkupKind.PlainText) => ValidFileUri(param?.TextDocument?.Uri) && !IgnoreFile(param.TextDocument.Uri) ? this.Projects.HoverInformation(param, format) : null;
/// <summary> /// Returns the signature help information for a call expression if there is such an expression at the specified position. /// Returns null if the given file is listed as to be ignored, /// or if some parameters are unspecified (null), /// or if the specified position is not a valid position within the currently processed file content /// or if no call expression exists at the specified position at this time /// or if no signature help information can be provided for the call expression at the specified position. /// </summary> public SignatureHelp SignatureHelp(TextDocumentPositionParams param, MarkupKind format = MarkupKind.PlainText) => ValidFileUri(param?.TextDocument?.Uri) && !IgnoreFile(param.TextDocument.Uri) ? this.Projects.SignatureHelp(param, format) : null;
/// <summary> /// Updates the given completion item with additional information if any is available. The completion item /// returned is a reference to the same completion item that was given; the given completion item is mutated /// with the additional information. /// <para/> /// Returns null (and the item is not updated) if any argument is null. /// </summary> public static CompletionItem ResolveCompletion( this CompilationUnit compilation, CompletionItem item, CompletionItemData data, MarkupKind format) { if (compilation == null || item == null || data == null) { return(null); } var documentation = TryGetDocumentation(compilation, data, item.Kind, format == MarkupKind.Markdown); if (documentation != null) { item.Documentation = new MarkupContent { Kind = format, Value = documentation } } ; return(item); }
public MarkupContent(MarkupKind kind, string value) { Kind = kind; Value = value; }
public override bool TryCreateTooltip( AggregateBoundAttributeDescription attributeDescriptionInfo, MarkupKind markupKind, [NotNullWhen(true)] out MarkupContent?tooltipContent) { if (attributeDescriptionInfo is null) { throw new ArgumentNullException(nameof(attributeDescriptionInfo)); } var associatedAttributeInfos = attributeDescriptionInfo.DescriptionInfos; if (associatedAttributeInfos.Count == 0) { tooltipContent = null; return(false); } // This generates a markdown description that looks like the following: // **ReturnTypeName** SomeTypeName.**SomeProperty** // // The Summary documentation text with `CrefTypeValues` in code. // // Additional description infos result in a triple `---` to separate the markdown entries. var descriptionBuilder = new StringBuilder(); for (var i = 0; i < associatedAttributeInfos.Count; i++) { var descriptionInfo = associatedAttributeInfos[i]; if (descriptionBuilder.Length > 0) { descriptionBuilder.AppendLine(); descriptionBuilder.AppendLine("---"); } StartOrEndBold(descriptionBuilder, markupKind); if (!TypeNameStringResolver.TryGetSimpleName(descriptionInfo.ReturnTypeName, out var returnTypeName)) { returnTypeName = descriptionInfo.ReturnTypeName; } var reducedReturnTypeName = ReduceTypeName(returnTypeName); descriptionBuilder.Append(reducedReturnTypeName); StartOrEndBold(descriptionBuilder, markupKind); descriptionBuilder.Append(" "); var tagHelperTypeName = descriptionInfo.TypeName; var reducedTagHelperTypeName = ReduceTypeName(tagHelperTypeName); descriptionBuilder.Append(reducedTagHelperTypeName); descriptionBuilder.Append("."); StartOrEndBold(descriptionBuilder, markupKind); descriptionBuilder.Append(descriptionInfo.PropertyName); StartOrEndBold(descriptionBuilder, markupKind); var documentation = descriptionInfo.Documentation; if (!TryExtractSummary(documentation, out var summaryContent)) { continue; } descriptionBuilder.AppendLine(); descriptionBuilder.AppendLine(); var finalSummaryContent = CleanSummaryContent(summaryContent); descriptionBuilder.Append(finalSummaryContent); } tooltipContent = new MarkupContent { Kind = markupKind, Value = descriptionBuilder.ToString(), }; return(true); }
/// <summary> /// Returns the signature help information for a call expression if there is such an expression at the specified position. /// Returns null if some parameters are unspecified (null), /// or if the specified position is not a valid position within the currently processed file content, /// or if no call expression exists at the specified position at this time, /// or if no signature help information can be provided for the call expression at the specified position. /// </summary> public static SignatureHelp?SignatureHelp( this FileContentManager file, CompilationUnit compilation, Position?position, MarkupKind format = MarkupKind.PlainText) { // getting the relevant token (if any) var fragment = file?.TryGetFragmentAt(position, out var _, includeEnd: true); if (file is null || position is null || fragment?.Kind == null || compilation == null) { return(null); } var fragmentStart = fragment.Range.Start; // getting the overlapping call expressions (if any), and determine the header of the called callable bool OverlapsWithPosition(Range symRange) => (fragmentStart + symRange).ContainsEnd(position); var overlappingEx = fragment.Kind.CallExpressions().Where(ex => ex.Range.IsValue && OverlapsWithPosition(ex.Range.Item)).ToList(); if (!overlappingEx.Any()) { return(null); } overlappingEx.Sort((ex1, ex2) => // for nested call expressions, the last expressions (by range) is always the closest one { var(x, y) = (ex1.Range.Item, ex2.Range.Item); int result = x.Start.CompareTo(y.Start); return(result == 0 ? x.End.CompareTo(y.End) : result); }); var nsName = file.TryGetNamespaceAt(position); var(method, args) = overlappingEx.Last().Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .CallLikeExpression c ? (c.Item1, c.Item2) : (null, null); if (nsName == null || method == null || args == null) { return(null); } // getting the called identifier as well as what functors have been applied to it List <QsFunctor> FunctorApplications(ref QsExpression ex) { var(next, inner) = ex.Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .AdjointApplication adj ? (QsFunctor.Adjoint, adj.Item) : ex.Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .ControlledApplication ctl ? (QsFunctor.Controlled, ctl.Item) : (null, null); var fs = inner == null ? new List <QsFunctor>() : FunctorApplications(ref inner); if (next != null) { fs.Add(next); } ex = inner ?? ex; return(fs); } var functors = FunctorApplications(ref method); var id = method.Expression as QsExpressionKind <QsExpression, QsSymbol, QsType> .Identifier; if (id == null) { return(null); } // extracting and adapting the relevant information for the called callable ResolutionResult <CallableDeclarationHeader> .Found?methodDecl = null; if (id.Item1.Symbol is QsSymbolKind <QsSymbol> .Symbol sym) { methodDecl = compilation.GlobalSymbols.TryResolveAndGetCallable( sym.Item, nsName, file.FileName) as ResolutionResult <CallableDeclarationHeader> .Found; } else if (id.Item1.Symbol is QsSymbolKind <QsSymbol> .QualifiedSymbol qualSym) { methodDecl = compilation.GlobalSymbols.TryGetCallable( new QsQualifiedName(qualSym.Item1, qualSym.Item2), nsName, file.FileName) as ResolutionResult <CallableDeclarationHeader> .Found; } if (methodDecl == null) { return(null); } var(documentation, argTuple) = (methodDecl.Item.Documentation, methodDecl.Item.ArgumentTuple); var nrCtlApplications = functors.Where(f => f.Equals(QsFunctor.Controlled)).Count(); while (nrCtlApplications-- > 0) { var ctlQsName = QsLocalSymbol.NewValidName(nrCtlApplications == 0 ? "cs" : $"cs{nrCtlApplications}"); argTuple = SyntaxGenerator.WithControlQubits(argTuple, QsNullable <Position> .Null, ctlQsName, QsNullable <Range> .Null); } // now that we now what callable is called we need to check which argument should come next bool BeforePosition(Range symRange) => fragmentStart + symRange.End < position; IEnumerable <(Range?, string?)> ExtractParameterRanges( QsExpression?ex, QsTuple <LocalVariableDeclaration <QsLocalSymbol> > decl) { var @null = ((Range?)null, (string?)null); IEnumerable <(Range?, string?)> SingleItem(string paramName) { var arg = ex?.Range == null ? ((Range?)null, paramName) : ex.Range.IsValue ? (ex.Range.Item, paramName) : @null; // no signature help if there are invalid expressions return(new[] { arg }); } if (decl is QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .QsTupleItem dItem) { return(SingleItem(dItem.Item.VariableName is QsLocalSymbol.ValidName n ? n.Item : "__argName__")); } var declItems = decl as QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .QsTuple; var exItems = ex?.Expression as QsExpressionKind <QsExpression, QsSymbol, QsType> .ValueTuple; if (declItems == null) { return(new[] { @null }); } if (exItems == null && declItems.Item.Length > 1) { return(SingleItem(decl.PrintArgumentTuple())); } var argItems = exItems != null ? exItems.Item.ToImmutableArray <QsExpression?>() : ex == null ? ImmutableArray <QsExpression?> .Empty : ImmutableArray.Create <QsExpression?>(ex); return(argItems.AddRange(Enumerable.Repeat <QsExpression?>(null, declItems.Item.Length - argItems.Length)) .Zip(declItems.Item, (e, d) => (e, d)) .SelectMany(arg => ExtractParameterRanges(arg.Item1, arg.Item2))); } var callArgs = ExtractParameterRanges(args, argTuple).ToArray(); if (id == null || callArgs == null || callArgs.Any(item => item.Item2 == null)) { return(null); // no signature help if there are invalid expressions } // finally we can build the signature help information MarkupContent AsMarkupContent(string str) => new MarkupContent { Kind = format, Value = str }; ParameterInformation AsParameterInfo(string?paramName) => new ParameterInformation { Label = paramName, Documentation = AsMarkupContent(documentation.ParameterDescription(paramName)) }; var signatureLabel = $"{methodDecl.Item.QualifiedName.Name} {argTuple.PrintArgumentTuple()}"; foreach (var f in functors) { if (f.IsAdjoint) { signatureLabel = $"{Keywords.qsAdjointFunctor.id} {signatureLabel}"; } if (f.IsControlled) { signatureLabel = $"{Keywords.qsControlledFunctor.id} {signatureLabel}"; } } var doc = documentation.PrintSummary(format == MarkupKind.Markdown).Trim(); var info = new SignatureInformation { Documentation = AsMarkupContent(doc), Label = signatureLabel, // Note: the label needs to be expressed in a way that the active parameter is detectable Parameters = callArgs.Select(d => d.Item2).Select(AsParameterInfo).ToArray() }; var precedingArgs = callArgs .TakeWhile(item => item.Item1 == null || BeforePosition(item.Item1)) // skip args that have already been typed or - in the case of inner items - are missing .Reverse().SkipWhile(item => item.Item1 == null); // don't count missing, i.e. not yet typed items, of the relevant inner argument tuple return(new SignatureHelp { Signatures = new[] { info }, // since we don't support overloading there is just one signature here ActiveSignature = 0, ActiveParameter = precedingArgs.Count() }); }
public abstract bool TryCreateTooltip(AggregateBoundAttributeDescription attributeDescriptionInfo, MarkupKind markupKind, [NotNullWhen(true)] out MarkupContent?tooltipContent);