• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

AnderssonPeter / PowerType / 5536473282

pending completion
5536473282

push

github

AnderssonPeter
Update DynamicSourceCache when executing specific commands

317 of 492 branches covered (64.43%)

Branch coverage included in aggregate %.

58 of 58 new or added lines in 6 files covered. (100.0%)

676 of 948 relevant lines covered (71.31%)

177.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/PowerType/PowerTypePredictor.cs
1
using PowerType.BackgroundProcessing;
2
using PowerType.Parsing;
3
using System.Diagnostics;
4
using System.Management.Automation.Language;
5
using System.Management.Automation.Subsystem.Prediction;
6

7
namespace PowerType;
8

9
public sealed class PowerTypePredictor : ICommandPredictor, IDisposable
10
{
11
    //Ugly hack to allow cmdlets access the instance after it has been created
12
    public static volatile PowerTypePredictor? Instance;
13

14
    internal ExecutionEngine ExecutionEngine { get; }
×
15
    internal PowerTypePredictionSummaryCollector PredictionSummaryCollector { get; }
×
16
    public string Description => "Provides suggestions for common command tools";
×
17

18
    public Guid Id => Identifier;
×
19

20
    internal static readonly Guid Identifier = new("2ceecb5e-697d-4d0f-a32f-261cd3635a9f");
×
21
    private readonly ICurrentWorkingDirectoryProvider currentWorkingDirectoryProvider;
22

23
    public string Name => "PowerType";
×
24

25
    public PowerTypePredictor(ICurrentWorkingDirectoryProvider currentWorkingDirectoryProvider, IEnumerable<string> dictionaryFiles)
×
26
    {
27
        ExecutionEngine = new ExecutionEngine();
×
28
        ExecutionEngine.Start();
×
29
        PredictionSummaryCollector = new PowerTypePredictionSummaryCollector();
×
30
        foreach (var dictionaryFile in dictionaryFiles)
×
31
        {
32
            ExecutionEngine.InitialDictionary(dictionaryFile);
×
33
        }
34

35
        this.currentWorkingDirectoryProvider = currentWorkingDirectoryProvider;
×
36
    }
×
37

38
    public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback) => feedback == PredictorFeedbackKind.CommandLineExecuted;
×
39

40
    private static string ConstructCommandPrefix(CommandAst commandAst)
41
    {
42
        if (commandAst?.Parent?.Parent is PipelineChainAst pipelineChainAst && pipelineChainAst.Operator == TokenKind.AndAnd)
×
43
        {
44
            return pipelineChainAst.LhsPipelineChain.ToString() + " && ";
×
45
        }
46
        return string.Empty;
×
47
    }
48

49
    public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken)
50
    {
51
        var when = DateTime.Now;
×
52
        var watch = Stopwatch.StartNew();
×
53
        Exception? exception = null;
×
54
        SuggestionPackage suggestionPackage = default;
×
55
        try
56
        {
57
            var relatedAsts = context.RelatedAsts;
×
58
            CommandAst? commandAst = null;
×
59

60
            for (var i = relatedAsts.Count - 1; i >= 0; --i)
×
61
            {
62
                if (relatedAsts[i] is CommandAst c)
×
63
                {
64
                    commandAst = c;
×
65
                    break;
×
66
                }
67
            }
68

69
            if (commandAst != null)
×
70
            {
71
                var commandName = commandAst.GetCommandName();
×
72
                var arguments = commandAst.CommandElements.Select(x => new PowerShellString(x));
×
73
                var prefix = ConstructCommandPrefix(commandAst);
×
74
                var dictionaryParsingContext = new DictionaryParsingContext(prefix, arguments);
×
75
                var result = GetSuggestions(dictionaryParsingContext).ToList();
×
76
                if (result.Count > 0)
×
77
                {
78
                    suggestionPackage = new SuggestionPackage(result);
×
79
                }
80
            }
81
        }
×
82
        catch (Exception ex)
83
        {
84
            exception = ex;
×
85
        }
×
86
        watch.Stop();
×
87
        if (exception != null || suggestionPackage.SuggestionEntries != null)
×
88
        {
89
            this.PredictionSummaryCollector.Add(when, context, exception, suggestionPackage, watch.Elapsed);
×
90
        }
91
        return suggestionPackage;
×
92
    }
93

94
    private IEnumerable<PredictiveSuggestion> GetSuggestions(DictionaryParsingContext dictionaryParsingContext)
95
    {
96
        if (!dictionaryParsingContext.HasValue)
×
97
        {
98
            yield break;
×
99
        }
100
        var commandName = dictionaryParsingContext.CurrentArgument;
×
101
        if (dictionaryParsingContext.Arguments.Count == 1)
×
102
        {
103
            foreach (var result in GetDictrionaryPredictons(commandName))
×
104
            {
105
                yield return result;
×
106
            }
107
        }
108
        if (TryGetSuggester(commandName, out var key, out var suggester))
×
109
        {
110
            dictionaryParsingContext.Command = new Parsing.Command(key, suggester.Dictionary);
×
111
            ExecutionEngine.Cache(suggester.Dictionary, currentWorkingDirectoryProvider.CurrentWorkingDirectory);
×
112
            foreach (var result in suggester.GetPredictions(dictionaryParsingContext))
×
113
            {
114
                yield return result;
×
115
            }
116
        }
117
    }
×
118

119
    private bool TryGetSuggester(PowerShellString command, out string key, out DictionarySuggester suggester)
120
    {
121
        var suggesters = ExecutionEngine.GetSuggesters();
×
122
        foreach (var innerSuggester in suggesters)
×
123
        {
124
            foreach (var suggesterKey in innerSuggester.Keys)
×
125
            {
126
                if (suggesterKey.Equals(command.RawValue, StringComparison.OrdinalIgnoreCase))
×
127
                {
128
                    key = suggesterKey;
×
129
                    suggester = innerSuggester;
×
130
                    return true;
×
131
                }
132
            }
133
        }
134
        key = null!;
×
135
        suggester = null!;
×
136
        return false;
×
137
    }
×
138

139
    private IEnumerable<PredictiveSuggestion> GetDictrionaryPredictons(PowerShellString commandName)
140
    {
141
        var suggesters = ExecutionEngine.GetSuggesters();
×
142
        foreach (var suggester in suggesters)
×
143
        {
144
            var key = suggester.Keys.FirstOrDefault(x => x.Contains(commandName.RawValue, StringComparison.OrdinalIgnoreCase));
×
145
            if (key != null)
×
146
            {
147
                yield return new PredictiveSuggestion(key, suggester.Description);
×
148
            }
149
        }
150
    }
×
151

152
    public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history)
153
    {
154
        //This input is not needed
155
    }
×
156

157
    public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success)
158
    {
159
        //This input is not needed
160
        //We should use this to update sources!
161
        if (success)
×
162
        {
163
            var parts = commandLine.Split(' ', 2);
×
164
            if (parts.Length == 2)
×
165
            {
166
                var dictinaryIdentifer = PowerShellString.FromRawSmart(parts[0]);
×
167
                var command = parts[1];
×
168
                if (TryGetSuggester(dictinaryIdentifer, out string _, out var suggester))
×
169
                {
170
                    ExecutionEngine.CommandExecuted(suggester.Dictionary, currentWorkingDirectoryProvider.CurrentWorkingDirectory, command);
×
171
                }
172
            }
173
        }
174
    }
×
175

176
    public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion)
177
    {
178
        //This input is not needed
179
    }
×
180

181
    public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex)
182
    {
183
        //This input is not needed
184
    }
×
185

186
    public void Dispose()
187
    {
188
        ExecutionEngine.Stop();
×
189
        currentWorkingDirectoryProvider.Dispose();
×
190
    }
×
191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc