forked from microsoft/qsharp-compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUtils.cs
155 lines (137 loc) · 6.18 KB
/
Utils.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Quantum.QsCompiler;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Newtonsoft.Json.Linq;
namespace Microsoft.Quantum.QsLanguageServer
{
public static class Utils
{
// language server tools -
// wrapping these into a try .. catch .. to make sure errors don't go unnoticed as they otherwise would
public static T TryJTokenAs<T>(JToken arg) where T : class =>
QsCompilerError.RaiseOnFailure(
() => arg == null ? throw new ArgumentNullException(nameof(arg)) : arg.ToObject<T>(),
"could not cast given JToken");
private static ShowMessageParams AsMessageParams(string text, MessageType severity) =>
text == null ? null : new ShowMessageParams { Message = text, MessageType = severity };
/// <summary>
/// Shows the given text in the editor.
/// Throws an ArgumentNullException if either the server or the text to display is null.
/// </summary>
internal static void ShowInWindow(this QsLanguageServer server, string text, MessageType severity)
{
var message = AsMessageParams(text, severity);
QsCompilerError.Verify(server != null && message != null, "cannot show message - given server or text was null");
if (server == null)
{
throw new ArgumentNullException(nameof(server));
}
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
_ = server.NotifyClientAsync(Methods.WindowShowMessageName, message);
}
/// <summary>
/// Logs the given text in the editor.
/// Throws an ArgumentNullException if either the server or the text to display is null.
/// </summary>
internal static void LogToWindow(this QsLanguageServer server, string text, MessageType severity)
{
var message = AsMessageParams(text, severity);
QsCompilerError.Verify(server != null && message != null, "cannot log message - given server or text was null");
if (server == null)
{
throw new ArgumentNullException(nameof(server));
}
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
_ = server.NotifyClientAsync(Methods.WindowLogMessageName, message);
}
// tools related to project loading and file watching
/// <summary>
/// Attempts to apply the given mapper to each element in the given sequence.
/// Returns a new sequence consisting of all mapped elements for which the mapping succeeded as out parameter,
/// as well as a bool indicating whether the mapping succeeded for all elements.
/// The returned out parameter is non-null even if the mapping failed on some elements.
/// </summary>
internal static bool TryEnumerate<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> mapper,
out ImmutableArray<TResult> mapped)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (mapper == null)
{
throw new ArgumentNullException(nameof(mapper));
}
var succeeded = true;
var enumerator = source.GetEnumerator();
T Try<T>(Func<T> getRes, T fallback)
{
try
{
return getRes();
}
catch
{
succeeded = false;
return fallback;
}
}
bool TryMoveNext() => Try(enumerator.MoveNext, false);
(bool, TResult) ApplyToCurrent() => Try(() => (true, mapper(enumerator.Current)), (false, default(TResult)));
var values = ImmutableArray.CreateBuilder<TResult>();
while (TryMoveNext())
{
var evaluated = ApplyToCurrent();
if (evaluated.Item1)
{
values.Add(evaluated.Item2);
}
}
mapped = values.ToImmutable();
return succeeded;
}
/// <summary>
/// Attempts to enumerate the given sequence.
/// Returns a new sequence consisting of all elements which could be accessed,
/// as well as a bool indicating whether the enumeration succeeded for all elements.
/// The returned out parameter is non-null even if access failed on some elements.
/// </summary>
internal static bool TryEnumerate<TSource>(this IEnumerable<TSource> source, out ImmutableArray<TSource> enumerated) =>
source.TryEnumerate(element => element, out enumerated);
/// <summary>
/// The given log function is applied to all errors and warning
/// raised by the ms build routine an instance of this class is given to.
/// </summary>
internal class MSBuildLogger : Logger
{
private readonly Action<string, MessageType> logToWindow;
internal MSBuildLogger(Action<string, MessageType> logToWindow) =>
this.logToWindow = logToWindow;
public override void Initialize(IEventSource eventSource)
{
eventSource.ErrorRaised += (sender, args) =>
this.logToWindow?.Invoke(
$"MSBuild error in {args.File}({args.LineNumber},{args.ColumnNumber}): {args.Message}",
MessageType.Error);
eventSource.WarningRaised += (sender, args) =>
this.logToWindow?.Invoke(
$"MSBuild warning in {args.File}({args.LineNumber},{args.ColumnNumber}): {args.Message}",
MessageType.Warning);
}
}
}
}