diff --git a/markdown.rb b/markdown.rb
new file mode 100644
index 0000000..cb3d380
--- /dev/null
+++ b/markdown.rb
@@ -0,0 +1,217 @@
+## Filter-based Markdown translator.
+#
+module Markdown
+ ## Superclass that defines behaviour of all translators
+ # @abstract Don't use directly - it only defins the ability to chain translators
+ class AbstractTranslator
+ attr_accessor :input
+ attr_accessor :output
+ def initialize()
+ @chain = []
+ end
+ def +(nextTranslator)
+ @chain.append nextTranslator
+ return self
+ end
+ def to_html
+ output = @output
+ @chain.each { |x|
+ x = x.new(output) if x.class == Class
+ x.to_html
+ output = x.output
+ }
+ return output
+ end
+ end
+ module_function
+ def html_highlighter; @html_highlighter end
+ def html_highlighter= v; @html_highlighter = v end
+ ## Translator for linear tags in Markdown.
+ # A linear tag is any tag that starts anywhere on the line, and closes on the same exact line.
+ class LinearTagTranslator < AbstractTranslator
+ def initialize(text)
+ @input = text
+ @output = text
+ super()
+ end
+ def to_html
+ @output = @input
+ # Newline
+ .sub(/\s{2}[\n\r]/,"
")
+ # Inline code (discord style)
+ .gsub(/(?#{code.gsub /[*`~_!\[]/,"\\\\\\0"}"
+ }
+ # Inline code (Markdown style)
+ .gsub(/(?#{code.gsub /[*`~_!\[]/,"\\\\\\0"}"
+ }
+ # Bold-italics
+ .gsub(/(?\\1")
+ # Bold
+ .gsub(/(?\\1")
+ # Italics
+ .gsub(/(?\\1")
+ # Strikethrough
+ .gsub(/(?\\1")
+ # Underline
+ .gsub(/(?\\1")
+ # Image
+ .gsub(/(?")
+ # Link
+ .gsub(/(?\\1")
+ super
+ end
+ end
+ ## Translator for linear leftmost tags.
+ # Leftmost linear tags open on the leftmost end of the string, and close once the line ends. These tags do not need to be explicitly closed.
+ class LeftmostTagTranslator < AbstractTranslator
+ def initialize(text)
+ @input = text
+ @output = text
+ super()
+ end
+ def to_html
+ # Headers
+ @output = @input.split("\n").map do |x|
+ x.gsub(/^(?"+content+""
+ }.gsub(/^\-{3,}/,"
#{code.gsub /[|#*`~_!\[]/,"\\\\\\0"}
"
+ }
+ super()
+ end
+ end
+ ## Translator for quotes in Markdown.
+ # These deserve their own place in hell. As if the "yaml with triangle brackets instead of spaces" syntax wasn't horrible enough, each quote is its own markdown context.
+ class QuoteTranslator < AbstractTranslator
+ def initialize(text)
+ if text.is_a? Array then
+ @lines = text
+ elsif text.is_a? String then
+ @lines = text.split("\n")
+ end
+ @output = text
+ super()
+ end
+ def input= (v)
+ @lines = v.split("\n")
+ @output = v
+ end
+ def input
+ @lines.join("\n")
+ end
+ def to_html
+ stack = []
+ range = []
+ @lines.each_with_index { |x,index|
+ if x.match /^\s*> ?/ then
+ range[0] = index if not range[0]
+ range[1] = index
+ else
+ stack.append(range[0]..range[1]) if range[0] and range[1]
+ range = []
+ end
+ }
+ stack.append(range[0]..range[1]) if range[0] and range[1]
+ stack.reverse.each { |r|
+ @lines[r.begin] = "\n"+@lines[r.begin] + @lines[r.end] = @lines[r.end]+"\n" + @lines[r] = @lines[r].map { |line| + line.sub /^(\s*)> ?/,"\\1 " + } + @lines[r] = QuoteTranslator.new(@lines[r]).to_html + } + @output = @lines.join("\n") + super + end + end + + ## Table parser + # translates tables from a format in markdown to an html table + class TableTranslator < AbstractTranslator + def initialize(text) + @input = text + @output = text + super() + end + def to_html + lines = @output.split("\n") + table_testline = -1 + table_start = -1 + table_column_count = 0 + tables = [] + cur_table = [] + lines.each_with_index { |line,index| + if (table_start != -1) and (line.match /^\s*\|([^\|]*\|){#{table_column_count-1}}$/) then + if (table_testline == -1) then + if (line.match /^\s*\|(\-*\|){#{table_column_count-1}}$/) then + table_testline = 1 + else + table_start = -1 + cur_table = [] + end + else + cur_table.push (line.split("|").filter_map { |x| x.strip if x.match /\S+/ }) + end + elsif (table_start != -1) then + obj = {table: cur_table, start: table_start, end: index} + tables.push(obj) + table_start = -1 + cur_table = [] + table_testline = -1 + table_column_count = 0 + end + if (table_start == -1) and (line.start_with? /\s*\|/ ) and (line.match /^\s*\|.*\|/) then + table_start = index + table_column_count = line.count "|" + cur_table.push (line.split("|").filter_map { |x| x.strip if x.match /\S+/ }) + end + } + if cur_table != [] then + obj = {table: cur_table, start:table_start, end: lines.count-1} + tables.push(obj) + end + tables.reverse.each { |x| + lines[x[:start]..x[:end]] = (x[:table].map do |a2d| + (a2d.map { |x| (x.start_with? "#") ? "
Quote begins
+>
+> yea
+> # header btw
+> > nextlevel quote
+> > more quote
+> > those are quotes
+> > yes
+> > > third level quote
+> > > yes
+> > second level again
+> > > third level again
+> > second level oioioi
+> >
+> > > third
+> > >
+> > >
+> > >
+>
+>
+>
+> fin
+CODE
+ ).to_html
+
+puts Markdown::CodeBlockTranslator.new(< Here's a bunch of shit i guess lmao idk
+```markdown
+test
+test
+test
+|1|2|3|
+|-|-|-|
+|a|b|c|
+
+| uneven rows | test | yes |
+|-|-|-|
+| sosiska | dinozavri | suda pihaem |
+| sosiska 2 | vitalya 2 | brat 2 |
+*** test ***
+piss
+cock
+__cock__
+# hi
+```
+> ok
+> here i go pissing
+> ***time to take a piss***
+> > pissing
+> > "what the hell are you doing"
+> > i'm taking a pieeees
+> > "why areyou not jomping at me thats what yourshupposed to do
+> > I might do it focking later
+> > ok
+> # bug
+> __cum__
+__mashup__
+
+| # sosiska | sosiska | suda pihaem |
+|-|-|-|
+| # 2 | chuvak ya ukral tvayu sardelku ))0)))0))))))) | __blya ((9((9((9)__ |
+| # azazaz lalka sasI | test | test |
+TEXT
+ )+Markdown::QuoteTranslator+Markdown::LeftmostTagTranslator+Markdown::LinearTagTranslator+Markdown::TableTranslator+Markdown::BackslashTranslator)
+ .to_html
+write = File.new("/tmp/test.html","w")
+write.write(test)
+write.close