Markdownにまつわるもろもろ
有用なユーティリティコード
- TOP
- Old Archives
- Markdownにまつわるもろもろ
Markdownで書くということ
Markdownはもうだいぶ普及している形式だと思う。
様々なマークアップ言語や記法がこれまで発達してきた。 それは例えばWikiであったり、plain2だったり、textileだったり、 場合によってはRDocだったり。
しかしながら、そのいずれもそれほど普及しなかった。 だが、Markdown記法はもはやスタンダードとも言うべき普及を見せている。
PureDocは当初、Markdownのような形式をとっていた。 実際に正規表現パーサだった時期もあるし、もう少し発展してZshの内部DSLだった時代もある。
この目的はHTMLと印刷用フォーマットの両方を生成するドキュメントメタフォーマットで、 かつHTMLと比べ簡潔に記述できるフォーマットを求めていた。
その要求を満たしてくれるのだ。 現在はPureDocはReasonSetに特化した多彩な機能を持つためMarkdownに乗り換えるということはしないが、 多くの場合Markdownで事足りるのも事実だ。
Markdown Editor
Markdownは普及している分、専用のEditorが多く存在する。 単に強調表示や入力支援があるだけでなく、リアルタイムで表示を確認できる。
主要な候補となるのは
- Markdown#Editor(Windows)
- Remarkable(Linux)
- CuteMarkEd
- Haroopad
の4つであるようだ。
Markdown#Editorに関しては表示領域がマッチしないことが多く、 いまひとつ使いにくい。この問題はCuteMarkEdでも生じる。
Haroopadはクロスプラットフォームで、最初はフォントに違和感があったが、 CSSによってフォントを含め見栄えを指定することができる。
Haroopadの弱点は、改行を反映してしまうことだろう。 だが、全体にはスタイリッシュで見やすく使いやすい。 ドキュメントの動的なリロード機能がないのと、Donateのバルーンがちょっとしつこいのは残念。 だが、Windowsではこれを使っている。 基本的に表示位置は狭い画面ではエディタ側の入力位置を上のほうにもってくると適切に表示してくれる。
Haroopadの欠点として、Fcitxで入力できなくなることが結構あるというのもある。 この対応として、入力のない、空のHaroopadを立ち上げておくと入力できるようだ。
RemarkableはUbuntu的なUIを持つ。 使いやすいといえば使いやすいが、D&Dによって開くことができないため、ファイル操作がちょっと面倒。
おもしろいのが、Remarkableはビューワがめいっぱい上までスクロールすると下にループする。下はしない。
またエクスポート機能もあり、CSSにも対応する。 今のところ最も安定しているということもあり、LinuxではRemarkableを使用している。
Remarkableで記述する場合は、エディタの記述部分を上のほうになるようにするか、めいいっぱい下にすると適切に表示される。 当然ながら、中途半端で適切に表示されない位置はどうしても生じる。
だが、なるべくならどのエディタも最も下に書いていくのが良いようだ。
Markdownで既存のテキストを引用する
HTMLを含め引用はpre
されるべきではないかと思うのだが、そうなっていない。
プレーンなテキストを引用するには、次のようにすると良いようだ。
sed -i "s/\(.*\)/> \1\n> /" file
sedの出力は改行を伴うので最後には改行はいらない。 段落を分けてもらう必要があるため、空行を入れておく。 ちょっと複雑だ。
MarkdownをPureBuilderに取り込み
Markdownのほうが楽に、適切に書けるケースが多いようなので、MarkdownをPureBuilderの一部として取り込んでみた。
とりあえずblog用で、変換にはpandocを使う。 これはいずれPureBuilderの一部となる。
ちなみに、今回コードの埋め込みは次のようにした。
sed "s/\(.*\)/\t\1/" ~/local/devel/reasonset_builder02/scripts/md_processor.rb >| ~/tmp/out
主な動作としては、PureDoc同様のヘッダの取り扱いと、
pandocからbody
だけを切り出すことである。
#!/usr/bin/ruby
# -*- mode: ruby; coding: UTF-8 -*-
require 'yaml'
module YEK
class ReasonBuild
#=NAME
#
#ReasonBuild MD Processor - PureBuilder script for Markdown file.
#=SYNOPSIS
#
# md_processor.rb [ _file_ ] [ -- _pandocoptions_ ... ]
#
#=DESCRIPTION
#
#MD Processor reads ARGF and process with pandoc.
#
#If +-s+ any _file_ given, MD Processor understands header with same style as PureDoc,
#modify timestamp, and write out to given _file_.
#
#If pandoc options given, MD Processor invoke pandoc with these options.
#Otherwise, MD Processor invoke pandoc
#
# pandoc -t -s -p
#
class MDProceessor
def proc_header(file=nil)
@file_content ||= ARGF.read
# Any file given?
if file && @file_content =~ /^##--.*$/ && $' =~ /^##--.*$/
begin
yax = $`.each_line.map {|i| i.sub(/^# /, "") }.join
header_meta = YAML.load(yax) || Hash.new
# Is Header missing last-update or since?
if ( ! header_meta.key?("last-update") ) || ( ! header_meta.key?("since") )
now = Time.now
modsince, modupdate = nil, nil
# Set to since
if ! header_meta.key?("since")
modsince = true
header_meta["since"] = now
end
# Set to last-update.
if ! header_meta.key?("last-update")
modupdate = true
end
# OK, Header is ready.
# Open the file!
File.open(file.first, "r+") do |f|
content = f.gets(nil)
if content.sub!(/^##--.*?^##--.*?$/m) {
el = $&.each_line.to_a # Get header texts.
el.insert(1, "# since : #{now.strftime '%Y-%m-%d %H:%M:%S %:z'}\n") if modsince # Add since if since was not exist.
# Update last update time if last-upadte is not set or last-update is older than mtime.
el.insert(1, "# last-update : #{File.mtime(file.first).strftime '%Y-%m-%d %H:%M:%S %:z'}\n") if modupdate# Add last update timestamp
el.join
}
# Write to file if updated.
f.seek(0)
f.truncate(0)
f.write( content )
end
end # Close file.
end # Missing header
rescue # YAML or IO Rescue.
STDOUT.puts $!
end
end # file given.
end #proc_header
# Invoke pandoc, format, and out.
def pandoc(options)
outstr = nil
# filter pandoc.
IO.popen(( ["pandoc"] + options ), "w+") do |io|
io.write @file_content
io.close_write
outstr = io.gets(nil)
end
# subscribe content
flag = false
outstr = outstr.each_line.select do |line|
if line =~ /^<\/body>$/
flag = false
end
if line =~ /^<body>$/
flag = true
next false
end
flag
end.join
return outstr
end
def initialize
pandoc_opt = nil
# Get pandoc options from argv.
if sep = ARGV.index("--")
pandoc_opt = ARGV[(sep + 1) .. -1]
ARGV.pop
else
pandoc_opt = [ "-t", "html", "-s", "-p" ]
end
proc_header( ( ARGV.empty? ? nil : ARGV.dup ) )
doc = pandoc(pandoc_opt)
print doc
end
end #MDProceessor
end
end
YEK::ReasonBuild::MDProceessor.new