Browse Source

Initial commit

master
Yessiest 1 year ago
parent
commit
02ec1efe6d
  1. 217
      markdown.rb
  2. 118
      test.rb

217
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]/,"<br/>")
# Inline code (discord style)
.gsub(/(?<!\\)``(.*?[^\\])``/) {
code = Regexp.last_match[1]
"<code>#{code.gsub /[*`~_!\[]/,"\\\\\\0"}</code>"
}
# Inline code (Markdown style)
.gsub(/(?<!\\)`(.*?[^\\])`/) {
code = Regexp.last_match[1]
"<code>#{code.gsub /[*`~_!\[]/,"\\\\\\0"}</code>"
}
# Bold-italics
.gsub(/(?<!\\)\*\*\*(.*?[^\\])\*\*\*/,"<i><b>\\1</b></i>")
# Bold
.gsub(/(?<!\\)\*\*(.*?[^\\])\*\*/,"<b>\\1</b>")
# Italics
.gsub(/(?<!\\)\*(.*?[^\\])\*/,"<i>\\1</i>")
# Strikethrough
.gsub(/(?<!\\)~~(.*?[^\\])~~/,"<s>\\1</s>")
# Underline
.gsub(/(?<!\\)__(.*?[^\\])__/,"<span style=\"text-decoration: underline\">\\1</span>")
# Image
.gsub(/(?<!\\)!\[(.*)\]\((.*)\)/,"<img src=\"\\2\" alt=\"\\1\" />")
# Link
.gsub(/(?<!\\)\[(.*)\]\((.*)\)/,"<a href=\"\\2\">\\1</a>")
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(/^(?<!\\)(\#{1,4})([^\n\r]*)/) {
level,content = Regexp.last_match[1..2]
"<h#{level.length}>"+content+"</h#{level.length}>"
}.gsub(/^\-{3,}/,"<hr>")
end.join("\n")
super
end
end
## Translator for code blocks in markdown
# Code blocks can have syntax highlighting. This class implements an attribute for providing a syntax highlighter, one handler per requested output.
class CodeBlockTranslator < AbstractTranslator
def initialize(text)
@input = text
@output = text
super()
end
def to_html
@output = @input.gsub(/(?:\n|^)```([\w_-]*)([\s\S]+?)```/) {
language,code = Regexp.last_match[1..2]
code = Markdown::html_highlighter.call(language,code) if Markdown::html_highlighter
"<pre><code>#{code.gsub /[|#*`~_!\[]/,"\\\\\\0"}</code></pre>"
}
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] = "<blockquote>\n"+@lines[r.begin]
@lines[r.end] = @lines[r.end]+"\n</blockquote>"
@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? "#") ? " <th>"+x.sub(/^#\s+/,"")+"</th>" : " <td>"+x+"</td>"}).prepend(" <tr>").append(" </tr>")
end).flatten.prepend("<table>").append("</table>")
}
@output = lines.join("\n")
super()
end
end
# Backslash cleaner
# Cleans excessive backslashes after the translation
class BackslashTranslator < AbstractTranslator
def initialize(text)
@input = text
@output = text
end
def to_html
@output = @input.gsub(/\\(.)/,"\\1")
end
end
end

118
test.rb

@ -0,0 +1,118 @@
require_relative "markdown"
puts Markdown::LinearTagTranslator.new(<<CODE
*Italics*
**Bold**
***Bolitalics***
__underline__
__underline plus ***bolitalics***__
___invalid underline___
~~strikethrough ~~
`code that ignores ***all*** __Markdown__ [tags](https://nevergonnagiveyouup)`
me: google en passant
them: [holy hell!](https://google.com/q?=en+passant)
CODE
).to_html
puts Markdown::LeftmostTagTranslator.new(<<CODE
# Header v1
## Header v2
### Header v3
#### Header v4
##### Invalid header
#### Not a header
*** Also #### Not a header ***
CODE
).to_html
puts Markdown::QuoteTranslator.new(<<CODE
> 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(<<CODE
```markdown
shmarkshmark
# pee pee
# piss
**ass**
__cock__
cock__
piss__
`shmark shmark`
```
CODE
).to_html
test = (Markdown::CodeBlockTranslator.new(<<TEXT
# Markdown garbage gallery
## Header level 2
### Header level 3
#### Header level 4
__[Underlined Link](https://google.com)__
__**unreal shitworks**__
split
---
![Fucking image idk](https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse3.explicit.bing.net%2Fth%3Fid%3DOIP.qX1HmpFNHyaTfXv-SLnAJgHaDD%26pid%3DApi&f=1&ipt=dc0e92fdd701395eda76714338060dcf91c7ff9e228f108d8af6e1ba3decd1c2&ipo=images)
> 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
Loading…
Cancel
Save