H1
- H8
tags, which it finds in the document. Simply tears them out, finds the topmost level of the header (for example, for Habr it is H3
), and makes the corresponding lists using nested UL
and LI
elements. This is not very safe, but such a simple expression is used to search for headers:var r = new Regex( "<h([^<]+)>(.+)</h.>" );<br/>
private static string GenerateToc([NotNull] string text, ConversionOptions options, out int minLevel)<br/>
{<br/>
List<HeadingEntry> entries = new List<HeadingEntry>();<br/>
var r = new Regex( "<h([^<]+)>(.+)</h.>" );<br/>
var matches = r.Matches(text);<br/>
int count = 0;<br/>
foreach (Match m in matches)<br/>
{<br/>
int n;<br/>
if ( int .TryParse(m.Groups[1].Value, out n))<br/>
{<br/>
HeadingEntry he = new HeadingEntry(n, m.Groups[2].Value);<br/>
// set tag text if clash
bool bFound = false ;<br/>
foreach (HeadingEntry h in entries)<br/>
if (h.SuggestedTagText == he.SuggestedTagText)<br/>
bFound = true ;<br/>
he.TagText = he.SuggestedTagText + (bFound ? (count++).ToString() : string .Empty);<br/>
entries.Add(he);<br/>
// replace only first occurence
//text = text.Replace(m.Groups[0].Value,
// string.Format("<h{0}><a name=\"{2}\"></a>{1}</h{0}>", n, he.Text, he.TagText));
int idx = text.IndexOf(m.Groups[0].Value);<br/>
string emptyLink = options.UseImageHeadings ? string .Empty :<br/>
string .Format( "<a name=\"{0}\"></a>" , he.TagText);<br/>
text = text.Remove(idx, m.Groups[0].Value.Length).Insert(idx,<br/>
string .Format( "<h{0}>{2}{1}</h{0}>" , n, he.Text, emptyLink));<br/>
}<br/>
}<br/>
minLevel = int .MaxValue;<br/>
if (entries.Count > 0)<br/>
{<br/>
var hb = new HtmlBuilder();<br/>
// all are, essentially, ULs
int lastLevel = -1;<br/>
foreach (HeadingEntry he in entries)<br/>
{<br/>
// if this level > last, open a new UL
if (he.Level > lastLevel)<br/>
hb.AppendLine( "<ul>" ).Indent();<br/>
if (he.Level < lastLevel)<br/>
{<br/>
int diff = lastLevel - he.Level;<br/>
while (--diff >= 0)<br/>
hb.Unindent().AppendLine( "</ul>" );<br/>
}<br/>
hb.AppendLine( string .Format( "<li><a href=\"#{0}\">{1}</a></li>" , he.TagText, he.Text));<br/>
minLevel = Math.Min(minLevel, he.Level);<br/>
lastLevel = he.Level;<br/>
}<br/>
// close out all indent levels
while (hb.IndentLevel > 0)<br/>
hb.Unindent().AppendLine( "</ul>" );<br/>
if (! string .IsNullOrEmpty(options.TocLabel))<br/>
hb.Insert( string .Format( "<h{0}>{1}</h{0}>{2}" , minLevel,<br/>
HttpUtility.HtmlEncode(options.TocLabel), Environment.NewLine), 0);<br/>
// at this point, hb contains the TOC, so
if (! string .IsNullOrEmpty(options.TocAfterToken))<br/>
{<br/>
int idx = text.IndexOf(options.TocAfterToken);<br/>
if (idx >= 0)<br/>
return text.Substring(0, idx + options.TocAfterToken.Length) +<br/>
hb + text.Substring(idx + options.TocAfterToken.Length);<br/>
}<br/>
hb.Append(text);<br/>
return hb.ToString();<br/>
}<br/>
return text;<br/>
}<br/>
[ ]
. Each footnote is assigned the number [ 1 ] in the order of the meeting in the file, and then they are neatly grouped at the end of the document.PRE
section. Therefore, “catching” square brackets is real only in the process of traversing a file (by letter) with a transformer. Yes, yes, this is the same transformer, which makes beautiful dashes and quotes.[{Hello, World!}]
And the system responds to this:MYAPI RECT MeasureCropArea( BYTE * src, int width, int height, int stride, int color)<br/>
{<br/>
Pixel& bgr = * reinterpret_cast <Pixel*>(&color);<br/>
RECT result;<br/>
// find the first non-conforming row of pixels
for ( int y = 0; y < height; ++y) <br/>
{<br/>
int y_offset = y * stride;<br/>
for ( int x = 0; x < width; ++x)<br/>
{<br/>
int offset = x * sizeof (Pixel) + y_offset;<br/>
Pixel& s = * reinterpret_cast <Pixel*>(src + offset);<br/>
// if this pixel is non-conforming, so is the row
if (s != bgr)<br/>
{<br/>
result.top = y;<br/>
// cause soft eject
x = width;<br/>
y = height;<br/>
}<br/>
}<br/>
}<br/>
// find the last non-conforming row of pixels
for ( int y = height - 1; y >= 0; --y) <br/>
{<br/>
int y_offset = y * stride;<br/>
for ( int x = 0; x < width; ++x)<br/>
{<br/>
int offset = x * sizeof (Pixel) + y_offset;<br/>
Pixel& s = * reinterpret_cast <Pixel*>(src + offset);<br/>
// if this pixel is non-conforming, so is the row
if (s != bgr)<br/>
{<br/>
result.bottom = y;<br/>
// cause soft eject
x = width;<br/>
y = -1;<br/>
}<br/>
}<br/>
}<br/>
// find the first non-conforming column of pixels
for ( int x = 0; x < width; ++x)<br/>
{<br/>
for ( int y = 0; y < height; ++y) <br/>
{<br/>
int offset = x * sizeof (Pixel) + y * stride;<br/>
Pixel& s = * reinterpret_cast <Pixel*>(src + offset);<br/>
// if this pixel is non-conforming, so is the column
if (s != bgr)<br/>
{<br/>
result.left = x;<br/>
// cause soft eject
x = width;<br/>
y = height;<br/>
}<br/>
}<br/>
}<br/>
// find the last non-conforming column of pixels
for ( int x = width - 1; x >= 0; --x)<br/>
{<br/>
for ( int y = 0; y < height; ++y) <br/>
{<br/>
int offset = x * sizeof (Pixel) + y * stride;<br/>
Pixel& s = * reinterpret_cast <Pixel*>(src + offset);<br/>
// if this pixel is non-conforming, so is the column
if (s != bgr)<br/>
{<br/>
result.right = x;<br/>
// cause soft eject
x = -1;<br/>
y = height;<br/>
}<br/>
}<br/>
}<br/>
int w = result.right - result.left;<br/>
int h = result.bottom - result.top;<br/>
if (w < 1) { result.left = 0; result.right = 1; }<br/>
if (h < 1) { result.top = 0; result.bottom = 1; }<br/>
return result;<br/>
}<br/>
This code was highlighted with CodeSyntaxHighlighter
. This is inadequate.{{ }}
and the backlight will work. Code examples are right in this post :)edge basic advanced<br/>
edge advanced TOC`generation<br/>
edge advanced Text- as -image`generation<br/>
edge advanced Graph`generation<br/>
edge Heading`substitution<br/>
edge TOC`generation Heading`substitution<br/>
edge Heading`substitution Migration`from`FlowDocument`to`Direct2D<br/>
edge Text- as -image`generation Heading`substitution<br/>
edge Graph`generation Subpixel`hinting`(future)<br/>
edge
directive turns into a real call to the edge method. Here is the parser of these commands:public void AddInstruction( string line)<br/>
{<br/>
if ( string .IsNullOrEmpty(line)) return ;<br/>
foreach (Match m in Regex.Matches(line, "([\"'])(?:\\\\\\1|.)*?\\1" ))<br/>
line = line.Replace(m.Value, m.Value.Replace( ' ' , '`' ));<br/>
string [] parts = line.Split( ' ' ).Select(p => p.Replace( '`' , ' ' ).Unquote()).ToArray();<br/>
if (parts.Length < 1) return ;<br/>
// having acquired the parts, see if there's a matching method
MethodInfo mi = null ;<br/>
if (cachedMethodInfo.ContainsKey( new KeyValuePair< string , int >(parts[0], parts.Length - 1)))<br/>
mi = cachedMethodInfo[ new KeyValuePair< string , int >(parts[0], parts.Length - 1)];<br/>
else <br/>
{<br/>
var methods = GetType().GetMethods().Where(m => m.Name.ToLower() == parts[0]<br/>
&& m.GetParameters().Length == (parts.Length - 1));<br/>
if (methods.Any())<br/>
{<br/>
mi = methods.First();<br/>
cachedMethodInfo.Add( new KeyValuePair< string , int >(mi.Name, parts.Length - 1), mi);<br/>
}<br/>
}<br/>
if (mi != null )<br/>
{<br/>
var pars = mi.GetParameters();<br/>
object [] ps = new object [0];<br/>
if (pars.Length == parts.Length - 1)<br/>
{<br/>
// try building a parameter array
ps = new object [pars.Length];<br/>
for ( int i = 0; i < pars.Length; i++)<br/>
{<br/>
var par = pars[i];<br/>
var source = parts[i + 1];<br/>
ps[i] = ConvertString(source, par.ParameterType);<br/>
}<br/>
}<br/>
// parameters ready - call it
try { mi.Invoke( this , ps); }<br/>
catch (Exception ex) { }<br/>
}<br/>
}<br/>
Source: https://habr.com/ru/post/72527/
All Articles