generated from atc-net/atc-template-dotnet-package
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSource.cs
123 lines (110 loc) · 4.38 KB
/
Source.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
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable PropertyCanBeMadeInitOnly.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Atc.Wpf.Controls.Documents.TextFormatters.SourceCode.Format;
/// <summary>
/// Provides a base implementation for all code formatters.
/// </summary>
/// <remarks>
/// <para>
/// To display the formatted code on your website, the web page must
/// refer to a stylesheet that defines the formatting for the different
/// CSS classes generated by CSharpFormat:
/// .csharpcode, pre, .rem, .kwrd, .str, .op, .preproc, .alt, .lnum.
/// </para>
/// <para>
/// Note that if you have multi-line comments in your source code
/// (like /* ... */), the "line numbers" or "alternate line background"
/// options will generate code that is not strictly HTML 4.01 compliant.
/// The code will still look good with IE5+ or Mozilla 0.8+.
/// </para>
/// </remarks>
public abstract class Source
{
public const string FormattingMarker = "::::::";
/// <summary>
/// Initializes a new instance of the <see cref="Source"/> class.
/// </summary>
protected Source()
{
TabSpaces = 4;
LineNumbers = false;
Alternate = false;
EmbedStyleSheet = false;
}
/// <summary>
/// Gets or sets the tabs width.
/// </summary>
/// <value>The number of space characters to substitute for tab
/// characters. The default is <b>4</b>, unless overridden is a
/// derived class.</value>
public byte TabSpaces { get; set; }
/// <summary>
/// Enables or disables line numbers in output.
/// </summary>
/// <value>When <b>true</b>, line numbers are generated.
/// The default is <b>false</b>.</value>
public bool LineNumbers { get; set; }
/// <summary>
/// Enables or disables alternating line background.
/// </summary>
/// <value>When <b>true</b>, lines background is alternated.
/// The default is <b>false</b>.</value>
public bool Alternate { get; set; }
/// <summary>
/// Enables or disables the embedded CSS style sheet.
/// </summary>
/// <value>When <b>true</b>, the CSS <style> element is included
/// in the HTML output. The default is <b>false</b>.</value>
public bool EmbedStyleSheet { get; set; }
/// <summary>
/// The regular expression used to capture language tokens.
/// </summary>
protected Regex CodeRegex { get; set; } = new("^", RegexOptions.None, TimeSpan.FromSeconds(5));
/// <summary>
/// This is a List of Run's that can be added later to the string of code.
/// </summary>
[SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "OK.")]
protected IList<Run> CodeParagraphGlobal { get; set; } = new List<Run>();
/// <summary>
/// Transforms a source code string to HTML 4.01.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="themeMode">The ThemeMode.</param>
/// <returns>
/// A string containing the HTML formatted code.
/// </returns>
public Paragraph FormatCode(string source, ThemeMode themeMode)
{
return FormatCodeHelper(source, themeMode);
}
/// <summary>
/// Called to evaluate the HTML fragment corresponding to each
/// matching token in the code.
/// </summary>
/// <param name="match">The <see cref="Match" /> resulting from a
/// single regular expression match.</param>
/// <param name="themeMode">The ThemeMode.</param>
/// <returns>A string containing the HTML code fragment.</returns>
protected abstract string MatchEval(Match match, ThemeMode themeMode);
private Paragraph FormatCodeHelper(string source, ThemeMode themeMode)
{
var codeParagraph = new Paragraph();
var sb = new StringBuilder(source);
source = CodeRegex.Replace(sb.ToString(), match => MatchEval(match, themeMode));
string[] characters = [FormattingMarker];
var split = source.Split(characters, StringSplitOptions.None);
var currentChunk = 0;
foreach (var code in split)
{
currentChunk++;
var run = new Run(code);
codeParagraph.Inlines.Add(run);
if ((currentChunk - 1) < CodeParagraphGlobal.Count)
{
codeParagraph.Inlines.Add(CodeParagraphGlobal[currentChunk - 1]);
}
}
return codeParagraph;
}
}