メモの統合

ブログを書くコツはなんでもかんでもブログを書くていで始めることかな?とここまで書いて「この話題はこの1行を𝕏に書いて終わりでいいんじゃないか?」と思った。でも、せっかくなので考えを進める。

書き始めはどこに上げるのか決めないで書き始めるのがいいのかな?SNSに書くときも下書きに書いているから、できることはできるけど。そうなると、書きかけがたくさん溜まって、どれを上げたのかわからなくなるな。上げたやつは上げたマークを付けておけばいいかな?逆に上げてないマークがいいか?今は下書きに書いてから𝕏, Mastodon, Blueskyのどれに上げるか決めているから、どこに上げたのか書いておくのもいいかもな。となると上げたマークと上げた場所のマークだな。

ブログの下書きは迷っているのでいろいろな所に分散している。docs/blog/blog.mdとして下書きをまとめているやつと、個別のタイトルが付いているものがある。SNSの下書きはdocs/memo/todo.txtにあるので、そこから切り出したやつはdocs/memo/にタイトル付きであったりする。todo.txtなのは後で見返す用だった名残り。見返さないやつはmemo.txtだったが、全部見返す運用にした。ただし、見返していない。

おれおれマークダウンがproj/markdown/markdownにあるので、そこに移動してあったりもする。機能追加しながら書いていたのでこんな運用になっているが、fixして~/bin辺りに入れてしまうのがいいかな?docs/blogにリリースするのでもよいか。markdownが重なっているのはgitの使い方を間違えたから。これも早くなんとかしないと。

おれおれマークダウンの配下にメモを置いてしまえばいいような気もするが、バックアップの管理上ディレクトリを分けたい。

docs/blog/docs/memo/はまとめてしまうのがいいかな?けっきょく、上げる先が違うだけだからなあ。上げないものもあるな。後で見返せるようにカテゴリ別に分けたdropbox/xというのもある。上で挙げたディレクトリはパソコン用で、dropbox/はiPhone用。前はさくらのレンタルサーバに上げていたのだが、LiquidLogicで自動保存が効かないのでDropboxに移した。dropbox/tがiPhone用のtodo.txtdropbox/dという日記もある。日記はiPhoneから専用。1文字なのはLiquidLogicでタブがたくさん表示できるように。txも統合してしまうかな?

ttodo.txtも定期的にくっつけるか?パソコン用とiPhone用はコンフリクトするから分けないとな。

・書き始めはどこに上げるのか決めない・文字数も決めないという原則に従って決めるのがいいかな?そうなると、パソコン用はblog.mdtodo.txtに分かれているのはだめだな。iPhone用はtだけだからこれでいいか?でも、xとの使い分けがあいまいなんだよな。これも統合してしまうか。日記はさすがに別だよな。でも、日記もxの一部にしてしまえば検索でどうにかなるな。まあ、とりあえずいろいろ統合して試してみるか。

ブログのていで書くと、SNSと違って思考の一端を書いて終わりにならないところがいいな。メモとブログの境を無くしたから、今まで無意識のうちに140文字に縛られていたものが開放されて思考が捗るに違いない。

===

∨ Source markdown
メモの統合

ブログを書くコツはなんでもかんでもブログを書くていで始めることかな?
とここまで書いて「この話題はこの1行を𝕏に書いて終わりでいいんじゃないか?」と思った。
でも、せっかくなので考えを進める。

書き始めはどこに上げるのか決めないで書き始めるのがいいのかな?
SNSに書くときも下書きに書いているから、できることはできるけど。
そうなると、書きかけがたくさん溜まって、どれを上げたのかわからなくなるな。
上げたやつは上げたマークを付けておけばいいかな?
逆に上げてないマークがいいか?
今は下書きに書いてから𝕏, Mastodon, Blueskyのどれに上げるか決めているから、どこに上げたのか書いておくのもいいかもな。
となると上げたマークと上げた場所のマークだな。

ブログの下書きは迷っているのでいろいろな所に分散している。
`docs/blog/`に`blog.md`として下書きをまとめているやつと、個別のタイトルが付いているものがある。
SNSの下書きは`docs/memo/todo.txt`にあるので、そこから切り出したやつは`docs/memo/`にタイトル付きであったりする。
`todo.txt`なのは後で見返す用だった名残り。
見返さないやつは`memo.txt`だったが、全部見返す運用にした。
ただし、見返していない。

おれおれマークダウンが`proj/markdown/markdown`にあるので、そこに移動してあったりもする。
機能追加しながら書いていたのでこんな運用になっているが、fixして`~/bin`辺りに入れてしまうのがいいかな?
`docs/blog`にリリースするのでもよいか。
`markdown`が重なっているのはgitの使い方を間違えたから。
これも早くなんとかしないと。

おれおれマークダウンの配下にメモを置いてしまえばいいような気もするが、バックアップの管理上ディレクトリを分けたい。

`docs/blog/`と`docs/memo/`はまとめてしまうのがいいかな?
けっきょく、上げる先が違うだけだからなあ。
上げないものもあるな。
後で見返せるようにカテゴリ別に分けた`dropbox/x`というのもある。
上で挙げたディレクトリはパソコン用で、`dropbox/`はiPhone用。
前はさくらのレンタルサーバに上げていたのだが、LiquidLogicで自動保存が効かないのでDropboxに移した。
`dropbox/t`がiPhone用の`todo.txt`。
`dropbox/d`という日記もある。
日記はiPhoneから専用。
1文字なのはLiquidLogicでタブがたくさん表示できるように。
`t`と`x`も統合してしまうかな?

`t`と`todo.txt`も定期的にくっつけるか?
パソコン用とiPhone用はコンフリクトするから分けないとな。

・書き始めはどこに上げるのか決めない
・文字数も決めない
という原則に従って決めるのがいいかな?
そうなると、パソコン用は`blog.md`と`todo.txt`に分かれているのはだめだな。
iPhone用は`t`だけだからこれでいいか?
でも、`x`との使い分けがあいまいなんだよな。
これも統合してしまうか。
日記はさすがに別だよな。
でも、日記も`x`の一部にしてしまえば検索でどうにかなるな。
まあ、とりあえずいろいろ統合して試してみるか。

ブログのていで書くと、SNSと違って思考の一端を書いて終わりにならないところがいいな。
メモとブログの境を無くしたから、今まで無意識のうちに140文字に縛られていたものが開放されて思考が捗るに違いない。

===
∨ 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で実現可能と気がつくまで

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