|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
using Microsoft.TemplateEngine.Core.Contracts;
namespace Microsoft.TemplateEngine.Core.Operations
{
public class SetFlag : IOperationProvider
{
public static readonly string OperationName = "flags";
private readonly bool _initialState;
public SetFlag(string? name, ITokenConfig on, ITokenConfig off, ITokenConfig onNoEmit, ITokenConfig offNoEmit, string? id, bool initialState, bool? @default = null)
{
Name = name;
On = on;
Off = off;
OnNoEmit = onNoEmit;
OffNoEmit = offNoEmit;
Default = @default;
Id = id;
_initialState = initialState;
}
public string? Id { get; }
public string? Name { get; }
public ITokenConfig On { get; }
public ITokenConfig Off { get; }
public bool? Default { get; }
public ITokenConfig OnNoEmit { get; }
public ITokenConfig OffNoEmit { get; }
public IOperation GetOperation(Encoding encoding, IProcessorState processorState)
{
IToken[] tokens = new[]
{
On.ToToken(encoding),
Off.ToToken(encoding),
OnNoEmit.ToToken(encoding),
OffNoEmit.ToToken(encoding)
};
if (Default.HasValue)
{
processorState.Config.Flags[Name!] = Default.Value;
}
return new Implementation(this, tokens, Id, _initialState);
}
private class Implementation : IOperation
{
private readonly SetFlag _owner;
public Implementation(SetFlag owner, IReadOnlyList<IToken> tokens, string? id, bool initialState)
{
_owner = owner;
Tokens = tokens;
Id = id;
IsInitialStateOn = string.IsNullOrEmpty(id) || initialState;
}
public IReadOnlyList<IToken> Tokens { get; }
public string? Id { get; }
public bool IsInitialStateOn { get; }
public int HandleMatch(IProcessorState processor, int bufferLength, ref int currentBufferPosition, int token)
{
if (!processor.Config.Flags.TryGetValue(OperationName, out bool flagsOn))
{
flagsOn = true;
}
bool emit = token < 2 || !flagsOn;
bool turnOn = (token % 2) == 0;
int written = 0;
if (emit)
{
processor.WriteToTarget(Tokens[token].Value, Tokens[token].Start, Tokens[token].Length);
written = Tokens[token].Length;
}
else
{
// consume the entire line when not emitting. Otherwise the newlines on the flag tokens get emitted
processor.SeekSourceForwardUntil(processor.EncodingConfig.LineEndings, ref bufferLength, ref currentBufferPosition, consumeToken: true);
}
//Only turn the flag in question back on if it's the "flags" flag.
// Yes, we still need to emit it as the common case is for this
// to be done in the template definition file
if (flagsOn)
{
processor.Config.Flags[_owner.Name!] = turnOn;
}
else if (_owner.Name == SetFlag.OperationName && turnOn)
{
processor.Config.Flags[SetFlag.OperationName] = true;
}
return written;
}
}
}
}
|