Initial commit
This commit is contained in:
		
							parent
							
								
									fb5cb0daab
								
							
						
					
					
						commit
						02ec1efe6d
					
				|  | @ -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 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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    | ||||
| --- | ||||
| 
 | ||||
|  | ||||
| > 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…
	
		Reference in New Issue