WSLのEmacsの常用はやめました

WSLのEmacsは知らない間にタスクバーからアイコンが消えているので常用するのはやめました。ちょっと前までは本当にクラッシュしていたみたいなのですが、最近は落ちなくなったようで、新しくEmacsを起動すると2つ起動している状態になるようになりました。なので、新しくEmacsを起動して、すぐに終了させるということを繰り返していたのですが、バカバカしくなりました。これはとりあえずWindowsのgVimで書いています。

ただ、WSLのEmacsをやめようと思うと代わりになにを使うかが悩ましいです。WindowsのVimのシェルは使ったことがないんですよね。NTEmacsでシェルという手もありますが、Diredはあまり使い心地がよくないんでなるべく使いたくないです。Cygwinのシェルからtmux経由でVimというのが慣れているし使い心地もよいのですが、𝕏とかの文字をまともに扱えないんです。どうやらtmuxを使わなければ𝕏の表示の問題はなさそうなので、CygwinのシェルからWindowsのVimを起動するというのもありかな?でも、これだとVimを選択してタブを選択という手間がめんどうです。まあ、Emacsでも同じなんだけど。CygwinでGNU Screenという手もあるけど、プレフィックスが柔軟に設定できないみたいなのであまり使いたくないんですよね。WSLからWindowsのVimやNTEmacsという手もあるか。アプリを複数使うと直接指定できて便利なんですよね。そもそもWSLのVimでもいいのか?でもこれはWindowsのクリップボードを使えないのか。

うーん、選択肢が多いわりに利点欠点が様々で頭がこんがらがるな。でも書いたらだいぶスッキリした。とりあえずWSLからVimやWindowsのアプリを起動するやりかたで問題点がないか確認してみるか。

∨ Source markdown
WSLのEmacsの常用はやめました

WSLのEmacsは知らない間にタスクバーからアイコンが消えているので常用するのはやめました。
ちょっと前までは本当にクラッシュしていたみたいなのですが、最近は落ちなくなったようで、新しくEmacsを起動すると2つ起動している状態になるようになりました。
なので、新しくEmacsを起動して、すぐに終了させるということを繰り返していたのですが、バカバカしくなりました。
これはとりあえずWindowsのgVimで書いています。

ただ、WSLのEmacsをやめようと思うと代わりになにを使うかが悩ましいです。
WindowsのVimのシェルは使ったことがないんですよね。
NTEmacsでシェルという手もありますが、Diredはあまり使い心地がよくないんでなるべく使いたくないです。
Cygwinのシェルからtmux経由でVimというのが慣れているし使い心地もよいのですが、𝕏とかの文字をまともに扱えないんです。
どうやらtmuxを使わなければ𝕏の表示の問題はなさそうなので、CygwinのシェルからWindowsのVimを起動するというのもありかな?
でも、これだとVimを選択してタブを選択という手間がめんどうです。
まあ、Emacsでも同じなんだけど。
CygwinでGNU Screenという手もあるけど、プレフィックスが柔軟に設定できないみたいなのであまり使いたくないんですよね。
WSLからWindowsのVimやNTEmacsという手もあるか。
アプリを複数使うと直接指定できて便利なんですよね。
そもそもWSLのVimでもいいのか?
でもこれはWindowsのクリップボードを使えないのか。

うーん、選択肢が多いわりに利点欠点が様々で頭がこんがらがるな。
でも書いたらだいぶスッキリした。
とりあえずWSLからVimやWindowsのアプリを起動するやりかたで問題点がないか確認してみるか。
∨ 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!('&', "&amp;")
    s.gsub!('<', "&lt;")
    s.gsub!('>', "&gt;")
    "<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('&', "&amp;")
      buffer.gsub!('<', "&lt;")
      buffer.gsub!('>', "&gt;")
      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!('&', "&amp;")
      line.gsub!('<', "&lt;")
      line.gsub!('>', "&gt;")
      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

コメント

このブログの人気の投稿

五十音配列付き新下駄配列

WSLでの親指シフトはどうやらMozcで実現可能と気がつくまで

親指シフト新下駄配列の可能性