おれおれマークダウンに元のマークダウンと変換スクリプトの埋め込み機能の追加
- リンクを取得
- ×
- メール
- 他のアプリ
おれおれマークダウンのスクリプトをスッキリさせたのだけど、元のマークダウンを埋め込む機能を入れたら、またごちゃごちゃになってしまいました。KISSの原則とか言うけど、このまま使い続けるかわからないコードまでは整理しないよね。自分しか使わないし。
ついでに変換のRubyコードもつっこんだ。大きくなりすぎるから悩んだけど、まあ大したことはないよね。ファイルを分割しないモチベーションが増えてしまった。
JavaScriptをひさびさにいじって楽しかった。昔には無かった便利機能がたくさんでかなり楽になっている。もうJavaScriptじゃないのか。
JavaScriptがからんでくるとアクセシビリティが気になってくるけど、まだそこまでいけてない。
そろそろ数学ネタもやらないとだな。まあ、思いついたところから。
自分の必要な機能をプログラミングするのは楽しいね。
∨ Source markdown
おれおれマークダウンに元のマークダウンと変換スクリプトの埋め込み機能の追加
おれおれマークダウンのスクリプトをスッキリさせたのだけど、元のマークダウンを埋め込む機能を入れたら、またごちゃごちゃになってしまいました。KISSの原則とか言うけど、このまま使い続けるかわからないコードまでは整理しないよね。自分しか使わないし。
ついでに変換のRubyコードもつっこんだ。大きくなりすぎるから悩んだけど、まあ大したことはないよね。ファイルを分割しないモチベーションが増えてしまった。
JavaScriptをひさびさにいじって楽しかった。昔には無かった便利機能がたくさんでかなり楽になっている。もうJavaScriptじゃないのか。
JavaScriptがからんでくるとアクセシビリティが気になってくるけど、まだそこまでいけてない。
そろそろ数学ネタもやらないとだな。まあ、思いついたところから。
自分の必要な機能をプログラミングするのは楽しいね。
∨ Source code
# coding: utf-8
require 'optparse'
require 'open3'
require 'strscan'
$lib = ""
class Context
attr_reader :state
def initialize
@block = Block.new
@list = List.new
@quote = Quote.new
@paragraph = Paragraph.new
@footnote = Footnote.new
@normal = Normal.new
@state = @normal
end
def change_state(state)
if @state != state then
@state.finish
@state = state
@state.start
end
end
def block?
@state.block?
end
def process(line)
@state.process(line)
end
def block(end_str, header)
@block.end_str = end_str
@block.header = header
change_state(@block)
end
def normal
change_state(@normal)
end
def list(content)
change_state(@list)
printf "<li>" << parse_line(content) << "</li>"
end
def quote(content)
change_state(@quote)
puts parse_line(content)
end
def paragraph(line)
change_state(@paragraph)
@paragraph.add_line(parse_line(line))
end
def footnote(tag, content)
change_state(@footnote)
printf "<li><a id='footnote_#{tag}'>[#{tag}]</a>:" << parse_line(content) << "</li>"
end
end
class State
def start
printf self.class::HEADER
end
def finish
if self.class::FOOTER.length > 0 then
printf "#{self.class::FOOTER}\n"
end
end
def block?
false
end
end
class Block < State
HEADER = ""
FOOTER = ""
attr_accessor :end_str
attr_accessor :header
attr_accessor :buffer
def initialize
@buffer = ""
end
def start
initialize
end
def process(line)
@buffer = @buffer << line << "\n"
end
def block?
true
end
end
class Normal < State
HEADER = ""
FOOTER = ""
end
class List < State
HEADER = "<ul>"
FOOTER = "</ul>"
end
class Quote < State
HEADER = "<blockquote style='font-size: medium; text-align: left; border-left: 5px solid #DDDDDD; padding-left: 10px; background: #F0F0F0'>"
FOOTER = "</blockquote>"
end
class Paragraph < State
PARAGRAPH_HEADER = "<p>"
PARAGRAPH_FOOTER = "</p>"
DESCRIPTION_LIST_HEADER = "<dl>"
DESCRIPTION_LIST_TERM_HEADER = "<dt>"
DESCRIPTION_LIST_TERM_FOOTER = "</dt>"
DESCRIPTION_LIST_VALUE_HEADER = "<dd>"
DESCRIPTION_LIST_VALUE_FOOTER = "</dd>"
DESCRIPTION_LIST_FOOTER = "</dl>"
def initialize
@lines = []
@mode = :paragraph
end
def start
initialize
end
def add_line(line)
if md = line.match(/^: (.*)/) then
@mode = :deflist
end
@lines.push(line)
end
def finish
if @mode == :paragraph then
print PARAGRAPH_HEADER
@lines.each do |line|
print line
end
puts PARAGRAPH_FOOTER
else
puts DESCRIPTION_LIST_HEADER
@lines.each do |line|
if md = line.match(/^: (.*)/) then
print DESCRIPTION_LIST_VALUE_HEADER
print md[1]
puts DESCRIPTION_LIST_VALUE_FOOTER
else
print DESCRIPTION_LIST_TERM_HEADER
print line
puts DESCRIPTION_LIST_TERM_FOOTER
end
end
puts DESCRIPTION_LIST_FOOTER
end
end
end
class Footnote < State
HEADER = "<ul>"
FOOTER = "</ul>"
end
mathjax = <<RUBY
<script>
MathJax = {
chtml: {
displayAlign: "left",
},
tex: {
inlineMath: [['$', '$']]
}
};
</script>
<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
</script>
RUBY
header = <<-RUBY
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script>
MathJax = {
chtml: {
displayAlign: "left",
},
tex: {
inlineMath: [['$', '$']]
}
};
</script>
<script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
</script>
<title>TITLE</title>
</head>
<body>
<h1>TITLE</h1>
RUBY
footer = <<RUBY
</body>
</html>
RUBY
opt = OptionParser.new
type = :html
opt.on('-b', '--blog', 'blog type output') do |v|
type = :blog
end
filename = ""
opt.parse!(ARGV)
if ARGV.size > 1 then
STDERR.puts "Too many argument: ARGV=#{ARGV}"
exit 1
end
filename = ARGV[0]
if !File.exists?(filename) then
STDERR.puts "File not exists: ARGV=#{ARGV}"
exit 1
end
def parse_line(line)
line.gsub!(/`([^`]*)`/) {
s = $1
s.gsub!('&', "&")
s.gsub!('<', "<")
s.gsub!('>', ">")
"<code style='padding: 2px 3px ; background: #FEFEFE; border: 1px solid #DDDDDD; border-radius: 5px'>#{s}</code>"
}
line.gsub!(/\[([^\]]*)\]\(([^\)]*)\)/) {
"<a href='#{$2}'>#{$1}</a>"
}
line.gsub!(/\[\^([^\]]*)\]/) {
"<a href='#footnote_#{$1}'><sup>[#{$1}]</sup></a>"
}
line
end
def parse_option(str)
lang = nil
name = nil
options = {"echo"=>true, "eval"=>true, "include"=>true}
s = StringScanner.new(str)
lang = s.scan(/\w+/)
s.scan(/\s+/)
name = s.scan(/\w+/)
while !s.eos?
s.scan(/ *, */)
option = s.scan(/\w+/)
s.scan(/ *= */)
value = s.scan(/\w+/)
if value.casecmp("false") == 0 then
options[option] = false
end
end
return lang, name, options
end
def process_block(block)
lang = nil
name = nil
options = {"echo"=>true, "eval"=>false, "include"=>true}
if md = block.header.match(/^ *([^{: ]+)(:([^ ]*))?/) then
lang = md[1]
name = md[3]
options = {"echo"=>true, "eval"=>false, "include"=>true}
elsif md = block.header.match(/^ *{(.*)}/) then
lang, name, options = parse_option(md[1])
end
if lang == "lib" then
$lib = $lib << "\n" << block.buffer
end
if options["include"] then
print '<div style="margin: 0 0 10px 0;">'
if options["echo"] then
if !name.nil? then
printf "<div style=\"border: 1px solid black;padding-left: 3px;margin-bottom: 0;\">#{name}</div>"
end
print '<pre style="overflow-x: scroll;padding: 1px 1px 1px 3px;border:1px solid black;margin: 0;"><code>'
buffer = block.buffer.gsub('&', "&")
buffer.gsub!('<', "<")
buffer.gsub!('>', ">")
puts buffer
puts "</code></pre>"
end
if options["eval"] then
print '<div style="overflow-x: scroll;padding: 1px 1px 1px 3px;border:1px solid black;margin-top: 0;">'
if lang == "math" then
print "$$"
print block.buffer
print "$$"
elsif lang == "ruby" then
print "<pre>"
print eval($lib + block.buffer)
print "</pre>"
elsif lang == "PlantUML" then
Open3.popen3("java -jar /mnt/d/app/plantuml.jar -pipe -svg -charset UTF-8") do |i, o, e, w|
i.write block.buffer
i.close
o.each do |l| puts l end
e.each do |l| printf("<!-- stderr: %s -->\n", l) end
printf("<!-- thread: %s -->\n", w.value)
end
end
print "</div>"
end
print '</div>'
end
end
def print_script
puts <<-RUBY
<script>
function toggleDisplay(e) {
if (e.style.display === "none") {
e.style.display = "block";
} else {
e.style.display = "none";
}
};
function toggleDisplayMark(e) {
str = e.innerText;
c = str.substring(0, 1);
if (c === "∨") {
e.innerText = "∧" + str.substring(1, str.length);
} else if (c === "∧") {
e.innerText = "∨" + str.substring(1, str.length);
}
}
</script>
RUBY
end
def print_code(filename, title)
puts %!<div onclick="toggleDisplayMark(this);toggleDisplay(this.nextElementSibling);" style="margin-top: 10px; border: 1px solid black;">∨ #{title}</div>!
print '<pre style="display: none;overflow-x: scroll;padding: 1px 1px 1px 3px;border:1px solid black;margin: 0;"><code>'
File.open(filename) do |f|
f.each_line do |line|
line.gsub!('&', "&")
line.gsub!('<', "<")
line.gsub!('>', ">")
puts line
end
puts "</code></pre>"
end
end
File.open(filename, "r") do |i|
context = Context.new
i.each_line do |line|
line.chomp!
if i.lineno == 1 then
if type == :html then
puts header.gsub(/TITLE/, line)
else
puts line
puts mathjax
end
elsif context.block? then
re = Regexp.new("^#{context.state.end_str}")
if line.match(re) then
process_block(context.state)
context.normal
else
context.process(line)
end
elsif md = line.match(/^(`{3,})(.*)/) then
end_str = md[1]
header = md[2]
context.block(end_str, header)
elsif md = line.match(/^(#+) *(.*)/) then
level = md[1].length + 1
printf("<h#{level}>%s</h#{level}>\n", md[2])
elsif md = line.match(/^[ \t]*$/) then
context.normal
elsif md = line.match(/^> (.*)/) then
context.quote(md[1])
elsif md = line.match(/^- (.*)/) then
context.list(md[1])
elsif md = line.match(/^\[\^([^\]]*)\]:(.*)/) then
context.footnote(md[1], md[2])
elsif md = line.match(/^! *include +(.*)/) then
context.normal
file = File.open(md[1])
puts file.read
else
context.paragraph(line)
end
end
context.normal
end
print_script
print_code filename, "Source markdown"
print_code __FILE__, "Source code"
if type == :html then
puts(footer)
end
- リンクを取得
- ×
- メール
- 他のアプリ
コメント
コメントを投稿