Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Рыбин Леонид #236

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions cs/Markdown/Markdown.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
30 changes: 30 additions & 0 deletions cs/Markdown/Md.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Text;
using Markdown.Token;

namespace Markdown;

public static class Md
{
public static string Render(string text)
{
var parser = new TagParser();
return GenerateHtml(text, parser.GetTokens(text));

This comment was marked as resolved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну если про GetTokens говорить, то он возращает, что-то такое:
"# ", <h1>, position = 0
"_", <em>, position = 8
А GenerateHtml пробегает по тексту и меняет в нужной позиции символы на HTML тэги, при этом у него может быть глобальный сдвиг, чтобы позиции символов оставались актуальными

}

private static string GenerateHtml(string text, List<IToken> tokens)
{
var currentTokens = tokens.OrderBy(t => t.Position).ToList();
int position = 0;
var sb = new StringBuilder();
foreach (var token in currentTokens)
{
sb.Append(text[position..token.Position]);
sb.Append(token.ConvertedText);
position = token.Position + token.SourceText.Length > text.Length ? text.Length : token.Position + token.SourceText.Length;
}

sb.Append(text[position..text.Length]);

return sb.ToString();
}
}
3 changes: 3 additions & 0 deletions cs/Markdown/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using Markdown;

Console.WriteLine(Md.Render("some text"));
94 changes: 94 additions & 0 deletions cs/Markdown/Rules/BoldRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using Markdown.Tags;

namespace Markdown.Rules;

public class BoldRule : IRule
{
private readonly ITag tag = new BoldTag();
private List<Token.Token> tokens = new();
private bool isItalicInStart;
private bool isItalicInMiddle;
private bool isTagClosed;
private readonly int[] italicStartsInBoldState = [10, 12];
private readonly int boldStartsInItalicState = 9;
private int currentState;

public TagKind MoveByRule(char ch, int position)
{
var symbol = SymbolStatusParser.ParseSymbolStatus(ch);

if (!tag.UsedSymbols.Contains(symbol))
{
symbol = SymbolStatus.anotherSymbol;
}

currentState = tag.States[currentState][symbol];

if (currentState == 0)
{
ClearTokens();
}

if (currentState == tag.InputStateNumber)
{
tokens.Add(new Token.Token(tag.MdView, tag.Head, position - (tag.MdView.Length - 1)));
}
else if (currentState == tag.OutputStateNumber)
{
if (symbol == SymbolStatus.eof)
{
tokens.Add(new Token.Token(tag.MdView, tag.Tail, position - (tag.MdView.Length - 1)));
}
else
{
tokens.Add(new Token.Token(tag.MdView, tag.Tail, position - tag.MdView.Length));
}

isTagClosed = true;
}
else if (currentState == boldStartsInItalicState)
{
if (isItalicInMiddle)
{
isItalicInStart = false;
isItalicInMiddle = false;
isTagClosed = false;
currentState = 0;
tokens.Clear();
}
else
{
isItalicInStart = !isItalicInStart;
}
}
else if (italicStartsInBoldState.Contains(currentState))
{
if (isItalicInStart)
{
isItalicInStart = false;
isItalicInMiddle = false;
isTagClosed = false;
currentState = 0;
tokens.Clear();
}
else
{
isItalicInMiddle = !isItalicInMiddle;
}

}

if (isTagClosed && (!isItalicInMiddle && !isItalicInStart || symbol == SymbolStatus.eof))
{
isTagClosed = false;
currentState = 0;
return TagKind.Close;
}

return TagKind.None;
}

public List<Token.Token> GetTokens() { return tokens; }

public void ClearTokens() { tokens.Clear(); }
}
40 changes: 40 additions & 0 deletions cs/Markdown/Rules/EscapeRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Markdown.Tags;

namespace Markdown.Rules;

public class EscapeRule : IRule
{
private readonly ITag tag = new EscapeTag();
private List<Token.Token> tokens = new();
private int currentState;

public TagKind MoveByRule(char ch, int position)
{
var symbol = SymbolStatusParser.ParseSymbolStatus(ch);

if (!tag.UsedSymbols.Contains(symbol))
{
symbol = SymbolStatus.anotherSymbol;
}

currentState = tag.States[currentState][symbol];

if (currentState == tag.InputStateNumber)
{
tokens.Add(new Token.Token(tag.MdView, tag.Head, position - (tag.MdView.Length - 1)));
return TagKind.Open;
}
else if (currentState == tag.OutputStateNumber)
{
tokens.Add(new Token.Token(ch.ToString(), ch.ToString(), position - (tag.MdView.Length - 1)));
currentState = 0;
return TagKind.Close;
}

return TagKind.None;
}

public List<Token.Token> GetTokens() { return tokens; }

public void ClearTokens() { tokens.Clear(); }
}
47 changes: 47 additions & 0 deletions cs/Markdown/Rules/H1Rule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Markdown.Tags;

namespace Markdown.Rules;

public class H1Rule : IRule
{
private readonly ITag tag = new H1Tag();
private List<Token.Token> tokens = new();
private int currentState;

public TagKind MoveByRule(char ch, int position)
{
var symbol = SymbolStatusParser.ParseSymbolStatus(ch);

if (!tag.UsedSymbols.Contains(symbol))
{
symbol = SymbolStatus.anotherSymbol;
}

currentState = tag.States[currentState][symbol];

if (currentState == tag.InputStateNumber)
{
tokens.Add(new Token.Token(tag.MdView, tag.Head, position - (tag.MdView.Length - 1)));
}
else if (currentState == tag.OutputStateNumber)
{
if (symbol == SymbolStatus.eof)
{
tokens.Add(new Token.Token("", tag.Tail, position + 1));
}
else
{
tokens.Add(new Token.Token("", tag.Tail, position));
}

currentState = 0;
return TagKind.Close;
}

return TagKind.None;
}

public List<Token.Token> GetTokens() { return tokens; }

public void ClearTokens() { tokens.Clear(); }
}
12 changes: 12 additions & 0 deletions cs/Markdown/Rules/IRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Markdown.Tags;

namespace Markdown.Rules;

public interface IRule
{
public TagKind MoveByRule(char ch, int position);

public List<Token.Token> GetTokens();

public void ClearTokens();
}
95 changes: 95 additions & 0 deletions cs/Markdown/Rules/ItalicRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Markdown.Tags;

namespace Markdown.Rules;

public class ItalicRule : IRule
{
private readonly ITag tag = new ItalicTextTag();
private List<Token.Token> tokens = new();
private bool isBoldInMiddle;
private bool isBoldInStart;
private bool isTagClosed;
private readonly int anotherStartState = 18;
private readonly int italicStartsInBoldState = 7;
private readonly int boldStartsInItalicState = 10;
private int currentState;

public TagKind MoveByRule(char ch, int position)
{

var symbol = SymbolStatusParser.ParseSymbolStatus(ch);

if (!tag.UsedSymbols.Contains(symbol))
{
symbol = SymbolStatus.anotherSymbol;
}

currentState = tag.States[currentState][symbol];

if (currentState == 0)
{
ClearTokens();
}

if (currentState == tag.InputStateNumber || currentState == anotherStartState)
{
tokens.Add(new Token.Token(tag.MdView, tag.Head, position - tag.MdView.Length));
}
else if (currentState == tag.OutputStateNumber)
{
if (symbol == SymbolStatus.eof)
{
tokens.Add(new Token.Token(tag.MdView, tag.Tail, position));
}
else
{
tokens.Add(new Token.Token(tag.MdView, tag.Tail, position - tag.MdView.Length));
}
isTagClosed = true;
}
else if (currentState == boldStartsInItalicState)
{
if (isBoldInMiddle)
{
isBoldInMiddle = false;
isBoldInStart = false;
isTagClosed = false;
currentState = 0;
tokens.Clear();
}
else
{
isBoldInStart = !isBoldInStart;
}
}
else if (currentState == italicStartsInBoldState)
{
if (isBoldInStart)
{
isBoldInMiddle = false;
isBoldInStart = false;
isTagClosed = false;
currentState = 0;
tokens.Clear();

}
else
{
isBoldInMiddle = !isBoldInMiddle;
}
}

if (isTagClosed && (!isBoldInMiddle || symbol == SymbolStatus.eof))
{
isTagClosed = false;
currentState = 0;
return TagKind.Close;
}

return TagKind.None;
}

public List<Token.Token> GetTokens() { return tokens; }

public void ClearTokens() { tokens.Clear(); }
}
15 changes: 15 additions & 0 deletions cs/Markdown/SymbolStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Markdown;

public enum SymbolStatus

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По код-стайлу обычно enum-чики с большой буквы именуются
Даже в каких-нить системных майкрософтовских либах так сделано

{
text,
digit,
underscore,
backslash,
eof,
newline,
space,
sharp,
anotherSymbol,
none
}
25 changes: 25 additions & 0 deletions cs/Markdown/SymbolStatusParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Markdown;

public static class SymbolStatusParser
{
public static SymbolStatus ParseSymbolStatus(char symbol)
{
if (char.IsLetter(symbol))
return SymbolStatus.text;
if (char.IsDigit(symbol))
return SymbolStatus.digit;
if (symbol == ' ')
return SymbolStatus.space;
if (symbol == '_')
return SymbolStatus.underscore;
if (symbol == '\\')
return SymbolStatus.backslash;
if (symbol == '\n')
return SymbolStatus.newline;
if (symbol == '\0')
return SymbolStatus.eof;
if (symbol == '#')
return SymbolStatus.sharp;
return SymbolStatus.none;
}
}
Loading