MongoExtensions / src / InteractiveReadLine / Formatting / CommonFormatters.cs
Code · 74 lines · 3157 bytes
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
using System.Security.Cryptography;
using System.Text;
using LineFormatter = System.Func<InteractiveReadLine.LineState, InteractiveReadLine.Formatting.LineDisplayState>;
using TokenFormatter = System.Func<InteractiveReadLine.Tokenizing.TokenizedLine, InteractiveReadLine.Formatting.LineDisplayState>;

#nullable disable

namespace InteractiveReadLine.Formatting
{
    public static class CommonFormatters
    {
        /// <summary>
        /// Provides a formatter that displays a fixed prompt in front of the input line, or wraps another
        /// formatter overwriting its prefix with the supplied prompt
        /// </summary>
        /// <param name="prompt">the prompt text to display</param>
        /// <param name="formatter"></param>
        public static LineFormatter FixedPrompt(FormattedText prompt, LineFormatter formatter = null)
        {
            return state =>
            {
                if (formatter == null)
                    return new LineDisplayState(prompt, state.Text, string.Empty, state.Cursor);
                var result = formatter.Invoke(state);
                return new LineDisplayState(prompt, result.LineBody, result.Suffix, result.Cursor);
            };
        }

        /// <summary>
        /// A formatter that blanks out the entered characters, and has no prefix or suffix
        /// </summary>
        public static LineFormatter PasswordBlank => 
            state => new LineDisplayState(string.Empty, string.Empty, string.Empty, 0);

        /// <summary>
        /// A formatter that puts out a variable length bar based on the 1st and 10th bytes in a SHA256 hash
        /// of the entered password. Provides repeatable visual feedback without revealing anything about the
        /// password itself
        /// </summary>
        public static LineFormatter PasswordBar =>
            state =>
            {
                var hash = SHA256.Create();
                var result = hash.ComputeHash(Encoding.ASCII.GetBytes(state.Text));
                var l1 = (int) Math.Round(20.0 * result[0] / 255.0);
                var l2 = (int) Math.Round(20.0 * result[10] / 255.0);
                var builder = new StringBuilder("[");
                for (var i = 0; i < 20; i++)
                    if (i < l1 && i < l2 || i > l1 && i > l2)
                        builder.Append(' ');
                    else
                        builder.Append('=');

                builder.Append(']');

                return new LineDisplayState(string.Empty, builder.ToString(), string.Empty, builder.Length);
            };


        /// <summary>
        /// A formatter that converts the password characters to stars
        /// </summary>
        public static LineFormatter PasswordStars =>
            state => new LineDisplayState(string.Empty, new string('*', state.Text.Length), string.Empty, state.Cursor);


        /// <summary>
        /// Adds a fixed prompt to the given formatter, overwriting the prefix
        /// </summary>
        public static LineFormatter WithFixedPrompt(this LineFormatter formatter, FormattedText prompt) => FixedPrompt(prompt, formatter);
        
    }
}