パソコンでブログを書く環境再考
- リンクを取得
- ×
- メール
- 他のアプリ
ちょっと前まではエディタをWSLのEmacsだけでやっていくつもりでいたのですが、知らない間に落ちていることが頻発したのでやめました。それまでは、当然その環境で書いていたので、その環境が無くなることでブログを書くことから遠ざかってしまいました。ということで、どうするのか考えながらブログも書いていきます。
この文章はとりあえずgVimで書いています。SNSへの投稿の下書きファイルをgVimで開きっぱなしにしていたので、それに間借りする感じです。しかし、Vimのタブ間の移動は不便ですよね。gtは両方とも人差し指だし、tはそもそも押しにくいし。
でも、tはaの左にも設定したので、かなり押しやすくなりました。このtをaの左に持ってきて、bは親指で押すシステムにしたら、とても手首が楽になりました。row staggeredなキーボードのbとか頭おかしいのかと思うような位置ですよね。column staggeredなキーボードで親指で押すのが正解です。
ただ、atがとても打ちにくくなってしまいました。元の位置のtは別のキーを割り当てて、なにか別の便利なものを割り当てようと思っていたのですが、これは残したほうがよいかな?
キーボードはいずれ詳しく書くことにして、ここではここまで。ブログの量産体制ができればたくさん書くはず。とはいえ、ブログを書く環境はキーボードと密接に関係しているんですけどね。
ブログを集中して一気に書き上げるならなんでもいいんですよ。でも、だいたいいくつも書きかけが開きっぱなしになると思うんですよね。そうなるとタブの選択がめんどくさいかな?そうでもないかな?めんどくさいならエディタを分けてしまえばいいんですよね。アプリならWin+数字キーで一発で移動できますから。でも、その方法では10までしか選択できないんですよね。すぐに10以上になってしまうから、あまり増やしたくない。となるとgVimで全部やるかな?それがいい気がしてきた。gVimもあんまり使ってこなかったから勉強がてらやるかな?
でも、時代はNeovimという話もあるんですよね。ぐぐるとVSCodeと比べる記事とかもあるんですよね。そんなにごてごて機能を追加しているのか?こっちも使ってみないとな。VSCodeももうちょっと使いたいし。
Emacsだとmarkdown-preview-modeとかもあるんですよね。でも、パソコンでブログを書くときにはおれおれマークダウンなので使えないかな?
ファイルの開き方も悩みどころです。ファイルエクスプローラーから開くのか、Cygwinから開くのかですね。WSLに統一してCygwinは消してしまおうかとも思ったんですが、やっぱりCygwinは便利なんですよね。ファイルシステムがWindowsと一体ですし、jumpコマンドでよく使うディレクトリには簡単に行けるし。WSLでもできる?ファイルエクスプローラのいい点は直感的なわかりやすさかな?あんまりないか。既存のgVimの操作無しに、ファイルの一覧からタブを追加できるところはいいか?使ってみないとわからないな。
結論としては、とりあえずgVimを使ってみるかな?
パソコンでブログを書く環境再考
ちょっと前まではエディタをWSLのEmacsだけでやっていくつもりでいたのですが、知らない間に落ちていることが頻発したのでやめました。それまでは、当然その環境で書いていたので、その環境が無くなることでブログを書くことから遠ざかってしまいました。ということで、どうするのか考えながらブログも書いていきます。
この文章はとりあえずgVimで書いています。SNSへの投稿の下書きファイルをgVimで開きっぱなしにしていたので、それに間借りする感じです。しかし、Vimのタブ間の移動は不便ですよね。gtは両方とも人差し指だし、tはそもそも押しにくいし。
でも、tはaの左にも設定したので、かなり押しやすくなりました。このtをaの左に持ってきて、bは親指で押すシステムにしたら、とても手首が楽になりました。row staggeredなキーボードのbとか頭おかしいのかと思うような位置ですよね。column staggeredなキーボードで親指で押すのが正解です。
ただ、atがとても打ちにくくなってしまいました。元の位置のtは別のキーを割り当てて、なにか別の便利なものを割り当てようと思っていたのですが、これは残したほうがよいかな?
キーボードはいずれ詳しく書くことにして、ここではここまで。ブログの量産体制ができればたくさん書くはず。とはいえ、ブログを書く環境はキーボードと密接に関係しているんですけどね。
ブログを集中して一気に書き上げるならなんでもいいんですよ。でも、だいたいいくつも書きかけが開きっぱなしになると思うんですよね。そうなるとタブの選択がめんどくさいかな?そうでもないかな?めんどくさいならエディタを分けてしまえばいいんですよね。アプリならWin+数字キーで一発で移動できますから。でも、その方法では10までしか選択できないんですよね。すぐに10以上になってしまうから、あまり増やしたくない。となるとgVimで全部やるかな?それがいい気がしてきた。gVimもあんまり使ってこなかったから勉強がてらやるかな?
でも、時代はNeovimという話もあるんですよね。ぐぐるとVSCodeと比べる記事とかもあるんですよね。そんなにごてごて機能を追加しているのか?こっちも使ってみないとな。VSCodeももうちょっと使いたいし。
Emacsだとmarkdown-preview-modeとかもあるんですよね。でも、パソコンでブログを書くときにはおれおれマークダウンなので使えないかな?
ファイルの開き方も悩みどころです。ファイルエクスプローラーから開くのか、Cygwinから開くのかですね。WSLに統一してCygwinは消してしまおうかとも思ったんですが、やっぱりCygwinは便利なんですよね。ファイルシステムがWindowsと一体ですし、jumpコマンドでよく使うディレクトリには簡単に行けるし。WSLでもできる?ファイルエクスプローラのいい点は直感的なわかりやすさかな?あんまりないか。既存のgVimの操作無しに、ファイルの一覧からタブを追加できるところはいいか?使ってみないとわからないな。
結論としては、とりあえずgVimを使ってみるかな?
# 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
- リンクを取得
- ×
- メール
- 他のアプリ
コメント
コメントを投稿