class Txt2Html

Public Class Methods

new(f) click to toggle source
# File misc/txt2html.rb, line 265
def initialize(f)
        @@done ||= []
        return if @@done.include? f
        @@done << f

        raise 'bad path' if (f.split('/') & ['.', '..']).first

        outf = outfilename(f)
        puts "compiling #{outf}..." if $VERBOSE

        @pathfix = outf.split('/')[0...-1].map { '../' }.join
        out = compile(File.open(f, 'rb') { |fd| fd.read }.gsub("\r", '') + "\n\n")
        File.open(outf, 'wb') { |fd| fd.write out.to_s.gsub("\r", '').gsub("\n", "\r\n") }
end

Public Instance Methods

compile(raw) click to toggle source
# File misc/txt2html.rb, line 284
def compile(raw)
        prev = ''
        state = {}
        anchors = {}
        out = Html::Page.new
        out.head << Html::Stylesheet.new(@pathfix + 'style.css')
        flush = lambda {
                out.body << Html::P.new(compile_string(prev)) if prev.length > 0
                [:pre, :list, :par].each { |f| state.delete f }
                prev = ''
        }
        raw.each_line { |l|
                case l = l.chomp
                when /^([=#*-])\1{3,}$/
                        if prev.length > 0
                                # title
                                if    not state[:h1] or state[:h1] == $1
                                        state[:h1] = $1
                                        e = 'h1'
                                elsif not state[:h2] or state[:h2] == $1
                                        state[:h2] = $1
                                        e = 'h2'
                                elsif not state[:h3] or state[:h3] == $1
                                        state[:h3] = $1
                                        e = 'h3'
                                else raise "unknown title level after #{prev.inspect}"
                                end
                                str = compile_string(prev)
                                state[:title] ||= str if e == 'h1'
                                if id = prev[/[a-z]\w+/i]
                                        id = id.downcase
                                        id += '_' while anchors[id]
                                        anchors[id] = true
                                        attr = { 'id' => id }
                                end
                                out.body << Html::Elem.new(e, attr).add(str)
                                prev = ''
                                flush[]
                        else
                                # horizontal rule
                                out.body << Html::Hr.new
                                flush[]
                        end
                when /^([*-]+)\s+(.*)/
                        # list
                        bullet = $1
                        text = $2
                        if lst = state[:list] && state[:list][bullet]
                                state[:list].delete_if { |k, v| k.length > bullet.length }
                        else
                                flush[] if not state[:list]
                                state[:list] ||= {}
                                state[:list].delete_if { |k, v| k.length > bullet.length }
                                lst = state[:list][bullet] = Html::List.new
                                if pl = state[:list][bullet.chop]
                                        pl.content.last.content << lst
                                else
                                        out.body << lst
                                end
                        end
                        lst.add_line compile_string(text)

                when /^\s+(\S.*)$/
                        # preformatted text
                        if not pre = state[:pre]
                                flush[]
                                pre = state[:pre] = Html::Elem.new('pre')
                                out.body << pre
                        end
                        pre.add compile_string(l) + ["\n"]
                when /^\s*$/
                        flush[]
                else
                        if state[:list]
                                lst = state[:list].sort.last[1]
                                lst.content.last.content << ' ' << compile_string(l)
                        else
                                prev << ' ' if prev.length > 0
                                prev << l
                        end
                end
        }
        flush[]
        out.head << Html::Elem.new('title').add(state[:title]) if state[:title]
        out
end
compile_string(str) click to toggle source

handle *bold_words* italic `fixed` <links> **bold__word__with__underscore**

# File misc/txt2html.rb, line 372
def compile_string(str)
        o = [str]
        on = []
        o.each { |s|
                while s.kind_of? String and o1 = s.index('**') and o2 = s.index('**', o1+2) and not s[o1..o2].index(' ')
                        on << s[0...o1] << Html::Elem.new('b').add(s[o1+2...o2].tr('_', ' ').gsub('  ', '_'))
                        s = s[o2+2..-1]
                end
                on << s
        }
        o = on
        on = []
        o.each { |s|
                while s.kind_of? String and o1 = s.index('*') and o2 = s.index('*', o1+1) and not s[o1..o2].index(' ')
                        on << s[0...o1] << Html::Elem.new('i').add(s[o1+1...o2].tr('_', ' ').gsub('  ', '_'))
                        s = s[o2+1..-1]
                end
                on << s
        }
        o = on
        on = []
        o.each { |s|
                while s.kind_of? String and o1 = s.index('`') and o2 = s.index('`', o1+1)
                        on << s[0...o1] << Html::Span.new('quote').add(s[o1+1...o2])
                        s = s[o2+1..-1]
                end
                on << s
        }
        o = on
        on = []
        o.each { |s|
                while s.kind_of? String and o1 = s.index('<') and o2 = s.index('>', o1+1) and not s[o1..o2].index(' ')
                        on << s[0...o1]
                        lnk = s[o1+1...o2]
                        s = s[o2+1..-1]
                        if File.exist? lnk
                                case lnk[/\.(\w+)$/, 1]
                                when 'txt'
                                        tg = outfilename(lnk)
                                        Txt2Html.new(lnk)
                                        on << Html::A.new(@pathfix + tg, File.basename(lnk, '.txt').tr('_', ' ').gsub('  ', '_'))
                                when 'jpg', 'png'
                                        on << Html::Img.new(lnk)
                                end
                        else
                                on << Html::A.new(lnk, lnk)
                                if lnk =~ /\.txt$/
                                        @@seen_nofile ||= []
                                        if not @@seen_nofile.include? lnk
                                                @@seen_nofile << lnk
                                                puts "reference to missing #{lnk.inspect}"
                                        end
                                        on.last.hclass('brokenlink')
                                end
                        end
                end
                on << s
        }
        o = on
end
outfilename(f) click to toggle source
# File misc/txt2html.rb, line 280
def outfilename(f)
        f.sub(/\.txt$/, '') + '.html'
end