arti_mark 0.0.1.beta4 → 0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +2 -2
- data/Rakefile +10 -0
- data/arti_mark.gemspec +4 -2
- data/lib/arti_mark/block_image_parser.rb +2 -2
- data/lib/arti_mark/{context.rb → html/context.rb} +6 -1
- data/lib/arti_mark/html/generator.rb +159 -0
- data/lib/arti_mark/html/header_writer.rb +32 -0
- data/lib/arti_mark/html/result.rb +27 -0
- data/lib/arti_mark/html/tag_writer.rb +110 -0
- data/lib/arti_mark/html/util.rb +12 -0
- data/lib/arti_mark/html/writer_selector.rb +24 -0
- data/lib/arti_mark/parser.kpeg +97 -0
- data/lib/arti_mark/parser.kpeg.rb +2533 -0
- data/lib/arti_mark/parser.rb +31 -0
- data/lib/arti_mark/version.rb +1 -1
- data/lib/arti_mark.rb +10 -21
- data/spec/arti_mark_spec.rb +108 -218
- metadata +40 -17
- data/lib/arti_mark/result.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62679290ba21c0b408d4fff89c820958fa789ff6
|
4
|
+
data.tar.gz: a16462606130c072726ce1d86bb0e677ce267ed3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33bdc6ff8f9b6bf47352876b60fbac750a6ea4f616c9f85197af9ce9a08d9773ac33ef6450ee4f63b33ac6bb6696eefa03a7f394c6d46243eb9ced1cc8977122
|
7
|
+
data.tar.gz: 946a6ef094042486ab500081851c7d8d19e613ae356d5fe0fc98c67eeb3780fe9dd271543f98f6a0cb2f9655849b6976d195126f02c6c951b9efd79c3c555e1c
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# version 0.1beta1 (pre NoraText)
|
2
|
+
|
3
|
+
* Totally rewrite using kpeg.
|
4
|
+
* degrage : toc feature removed (for the old toc feature is so poor)
|
5
|
+
* degrade : removed custom BlockParser. Instead of the feature, easy and powerful customization will be introduced in NoraText 0.1)
|
6
|
+
* markup change: alternate block notation starting with 'd{---' has removed
|
7
|
+
* markup change: inline image notation is changed form [img(alt-text){src}] to [img(src, alt)]
|
8
|
+
|
9
|
+
* will change the name from ArtiMark to NoraText on next release 0.1rc1
|
10
|
+
|
11
|
+
|
12
|
+
|
data/README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
ArtiMark is a simple text markup language. It is designed to create XHTML files for EPUB books. It is optimized for Japanese text for the present.
|
4
4
|
|
5
|
-
**CAUTION This is very early alpha version, so it's not stable at all
|
5
|
+
**CAUTION This is very early alpha version, so it's not stable at all.**
|
6
6
|
|
7
|
-
|
7
|
+
Reimplemented new version will be released on the end of Feb. 2014. Some syntax will be changed on the new version. The name of the library may change.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
data/Rakefile
CHANGED
@@ -1,2 +1,12 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
rule(/\.kpeg\.rb/ => proc {|task_name| task_name.sub(/kpeg\.rb$/, 'kpeg')}) do
|
5
|
+
|t|
|
6
|
+
system "kpeg -f #{t.prerequisites[0]}"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "run rspec"
|
10
|
+
task :test => ["lib/arti_mark/parser.kpeg.rb"] do
|
11
|
+
system 'rspec'
|
12
|
+
end
|
data/arti_mark.gemspec
CHANGED
@@ -15,6 +15,8 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = ArtiMark::VERSION
|
17
17
|
|
18
|
-
gem.
|
19
|
-
gem.
|
18
|
+
gem.required_ruby_version = '>= 2.0.0'
|
19
|
+
gem.add_dependency "kpeg"
|
20
|
+
gem.add_development_dependency "rspec", "~> 2.14"
|
21
|
+
gem.add_development_dependency "nokogiri", "~> 1.6.0"
|
20
22
|
end
|
@@ -19,8 +19,8 @@ module ArtiMark
|
|
19
19
|
|
20
20
|
r << "<div#{ids_string(lexed[:ids])}#{class_string(lexed[:cls])}>"
|
21
21
|
r << "<p>#{caption}</p>" if !caption.nil? && caption.size > 0 && caption_before
|
22
|
-
r << "<img src='#{src}' alt='#{alt}' />"
|
23
|
-
r << "<p>#{caption}</p>" if !caption.nil? && caption.size > 0 && !caption_before
|
22
|
+
r << "<img src='#{src}' alt='#{escape_html alt}' />"
|
23
|
+
r << "<p>#{escape_html caption}</p>" if !caption.nil? && caption.size > 0 && !caption_before
|
24
24
|
r << "</div>\n"
|
25
25
|
end
|
26
26
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module ArtiMark
|
2
|
+
module Html
|
2
3
|
class Context
|
3
4
|
attr_accessor :title, :head_inserters, :toc, :lang, :stylesheets, :enable_pgroup
|
4
5
|
def initialize(param = {})
|
@@ -25,7 +26,10 @@ module ArtiMark
|
|
25
26
|
ret
|
26
27
|
end
|
27
28
|
end
|
28
|
-
|
29
|
+
def chop_last_space
|
30
|
+
@pages.last.sub!(/[[:space:]]+$/, '')
|
31
|
+
end
|
32
|
+
|
29
33
|
def head_inserter(&block)
|
30
34
|
head_inserters << block
|
31
35
|
end
|
@@ -91,3 +95,4 @@ module ArtiMark
|
|
91
95
|
end
|
92
96
|
end
|
93
97
|
end
|
98
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'arti_mark/html/util'
|
3
|
+
require 'arti_mark/html/result'
|
4
|
+
require 'arti_mark/html/context'
|
5
|
+
require 'arti_mark/html/tag_writer'
|
6
|
+
require 'arti_mark/html/header_writer'
|
7
|
+
require 'arti_mark/html/writer_selector'
|
8
|
+
module ArtiMark
|
9
|
+
module Html
|
10
|
+
class Generator
|
11
|
+
include Util
|
12
|
+
attr_reader :context
|
13
|
+
def initialize(param = {})
|
14
|
+
@context = Context.new(param)
|
15
|
+
article_writer = TagWriter.create('article', self)
|
16
|
+
link_writer = TagWriter.create('a', self, trailer: '',
|
17
|
+
item_preprocessor: proc do |item|
|
18
|
+
(item[:attrs] ||= {}).merge!({:href => [ item[:args][0] ]})
|
19
|
+
item
|
20
|
+
end)
|
21
|
+
|
22
|
+
header_writer = HeaderWriter.new self
|
23
|
+
|
24
|
+
@writers = {
|
25
|
+
:paragraph =>
|
26
|
+
TagWriter.create('p', self, chop_last_space: true,
|
27
|
+
item_preprocessor: proc do |item|
|
28
|
+
add_class(item, 'noindent') if item[:children][0] =~/^(「|『|()/ # TODO: should be plaggable}
|
29
|
+
item
|
30
|
+
end
|
31
|
+
),
|
32
|
+
:paragraph_group =>
|
33
|
+
TagWriter.create("div", self,
|
34
|
+
item_preprocessor: proc do |item|
|
35
|
+
add_class item, 'pgroup'
|
36
|
+
item[:no_tag] = true unless @context.enable_pgroup
|
37
|
+
item
|
38
|
+
end
|
39
|
+
),
|
40
|
+
|
41
|
+
:block =>
|
42
|
+
WriterSelector.new(self,
|
43
|
+
{
|
44
|
+
'd' => TagWriter.create('div', self),
|
45
|
+
'art' => article_writer,
|
46
|
+
'article' => article_writer
|
47
|
+
}),
|
48
|
+
:line_command =>
|
49
|
+
WriterSelector.new(self,
|
50
|
+
{
|
51
|
+
'image' =>
|
52
|
+
TagWriter.create('div', self,
|
53
|
+
item_preprocessor: proc do |item|
|
54
|
+
add_class_if_empty item, 'img-wrap'
|
55
|
+
item
|
56
|
+
end,
|
57
|
+
write_body_preprocessor: proc do |item|
|
58
|
+
src = item[:args][0].strip
|
59
|
+
alt = (item[:args][1] || '').strip
|
60
|
+
caption_before = item[:named_args][:caption_before]
|
61
|
+
if caption_before && children_not_empty(item)
|
62
|
+
output "<p>"; write_children item; output "</p>"
|
63
|
+
end
|
64
|
+
output "<img src='#{src}' alt='#{escape_html alt}' />"
|
65
|
+
if !caption_before && children_not_empty(item)
|
66
|
+
output "<p>"; write_children item; output "</p>"
|
67
|
+
end
|
68
|
+
:done
|
69
|
+
end
|
70
|
+
),
|
71
|
+
'newpage' =>
|
72
|
+
TagWriter.create('div', self,
|
73
|
+
item_preprocessor: proc do |item|
|
74
|
+
item[:no_tag] = true
|
75
|
+
item
|
76
|
+
end,
|
77
|
+
write_body_preprocessor: proc do |item|
|
78
|
+
title = nil
|
79
|
+
if item[:args].size > 0 && item[:args][0].size > 0
|
80
|
+
title = escape_html item[:args].first
|
81
|
+
end
|
82
|
+
@context.start_html(title)
|
83
|
+
:done
|
84
|
+
end
|
85
|
+
),
|
86
|
+
|
87
|
+
}),
|
88
|
+
:inline =>
|
89
|
+
WriterSelector.new(self,
|
90
|
+
{
|
91
|
+
'link' => link_writer,
|
92
|
+
'l' => link_writer,
|
93
|
+
's' => TagWriter.create('span', self),
|
94
|
+
'img' =>
|
95
|
+
TagWriter.create('img', self,
|
96
|
+
item_preprocessor: proc do |item|
|
97
|
+
item[:no_body] = true #TODO : it is not just an item's attribute, 'img_inline' has no body. maybe should specify in parser.{rb|kpeg}
|
98
|
+
(item[:attrs] ||= {}).merge!({:src => [item[:args][0] ]})
|
99
|
+
item[:attrs].merge!({:alt => [ escape_html(item[:args][1].strip)]}) if (item[:args].size > 1 && item[:args][1].size > 0)
|
100
|
+
item
|
101
|
+
end) ,
|
102
|
+
'tcy' =>
|
103
|
+
TagWriter.create('span', self,
|
104
|
+
item_preprocessor: proc do |item|
|
105
|
+
add_class item, 'tcy'
|
106
|
+
item
|
107
|
+
end),
|
108
|
+
'ruby' =>
|
109
|
+
TagWriter.create('ruby', self,
|
110
|
+
write_body_preprocessor: proc do |item|
|
111
|
+
write_children item
|
112
|
+
output "<rp>(</rp><rt>#{escape_html item[:args][0].strip}</rt><rp>)</rp>"
|
113
|
+
:done
|
114
|
+
end),
|
115
|
+
|
116
|
+
},
|
117
|
+
trailer_default:''
|
118
|
+
),
|
119
|
+
:ol => TagWriter.create('ol', self),
|
120
|
+
:ul => TagWriter.create('ul', self),
|
121
|
+
:li => TagWriter.create('li', self),
|
122
|
+
:dl => TagWriter.create('dl', self),
|
123
|
+
:dtdd =>
|
124
|
+
TagWriter.create('', self, chop_last_space: true, item_preprocessor: proc do |item| item[:no_tag] = true; item end,
|
125
|
+
write_body_preprocessor: proc do |item|
|
126
|
+
output "<dt>"; write_array item[:args][0]; output "</dt>"
|
127
|
+
output "<dd>"; write_array item[:args][1]; output "</dd>"
|
128
|
+
:done
|
129
|
+
end),
|
130
|
+
# headers
|
131
|
+
:stylesheets => header_writer,
|
132
|
+
:title => header_writer,
|
133
|
+
:lang => header_writer,
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def convert(parsed_result)
|
138
|
+
parsed_result.each {
|
139
|
+
|item|
|
140
|
+
to_html(item)
|
141
|
+
}
|
142
|
+
@context.result
|
143
|
+
end
|
144
|
+
def to_html(item)
|
145
|
+
if item.is_a? String
|
146
|
+
@context << escape_html(item)
|
147
|
+
else
|
148
|
+
writer = @writers[item[:type]]
|
149
|
+
if writer.nil?
|
150
|
+
warn "can't find html generator for \"#{item}\""
|
151
|
+
@context << escape_html(item[:raw_text])
|
152
|
+
else
|
153
|
+
writer.write(item)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
module Html
|
3
|
+
class HeaderWriter
|
4
|
+
include Util
|
5
|
+
def initialize(generator)
|
6
|
+
@generator = generator
|
7
|
+
@context = generator.context
|
8
|
+
@writers = {
|
9
|
+
:stylesheets => proc do |item|
|
10
|
+
@context.stylesheets.concat( item[:stylesheets].map do
|
11
|
+
|s|
|
12
|
+
if s =~ /^(.+?\.css):\((.+?)\)$/
|
13
|
+
[$1, $2]
|
14
|
+
else
|
15
|
+
s
|
16
|
+
end
|
17
|
+
end)
|
18
|
+
end,
|
19
|
+
:title => proc do |item|
|
20
|
+
@context.title = escape_html item[:title].strip
|
21
|
+
end,
|
22
|
+
:lang => proc do |item|
|
23
|
+
@context.lang = escape_html item[:lang].strip
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
def write(item)
|
28
|
+
@writers[item[:type]].call item
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
module Html
|
3
|
+
class Context
|
4
|
+
class Result < Array
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def write_as_files(prefix, format='%03d')
|
10
|
+
self.each_with_index {
|
11
|
+
|converted, i|
|
12
|
+
File.open("#{prefix}_#{format%(i+1)}.xhtml", 'w+') {
|
13
|
+
|file|
|
14
|
+
file << converted
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
def write_as_single_file(filename)
|
19
|
+
File.open(filename, 'w+') {
|
20
|
+
|file|
|
21
|
+
file << self[0]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
module Html
|
3
|
+
class TagWriter
|
4
|
+
include Util
|
5
|
+
attr_accessor :trailer, :item_preprocessors, :write_body_preprocessors
|
6
|
+
|
7
|
+
def self.create(tag_name, generator, item_preprocessor: nil, write_body_preprocessor: nil, trailer: "\n", chop_last_space: false)
|
8
|
+
instance = TagWriter.new(tag_name, generator, chop_last_space: chop_last_space)
|
9
|
+
instance.item_preprocessors << item_preprocessor unless item_preprocessor.nil?
|
10
|
+
instance.write_body_preprocessors << write_body_preprocessor unless write_body_preprocessor.nil?
|
11
|
+
instance.trailer = trailer
|
12
|
+
yield instance if block_given?
|
13
|
+
instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(tag_name, generator, **param)
|
17
|
+
@tag_name = tag_name
|
18
|
+
@generator = generator
|
19
|
+
@context = generator.context
|
20
|
+
@trailer = trailer
|
21
|
+
@item_preprocessors = []
|
22
|
+
@write_body_preprocessors = []
|
23
|
+
@param = param
|
24
|
+
end
|
25
|
+
|
26
|
+
def attr_string(attrs)
|
27
|
+
attrs.map do
|
28
|
+
|name, vals|
|
29
|
+
if vals.size == 0
|
30
|
+
''
|
31
|
+
else
|
32
|
+
" #{name}='#{vals.join(' ')}'"
|
33
|
+
end
|
34
|
+
end.join('')
|
35
|
+
end
|
36
|
+
|
37
|
+
def class_string(cls_array)
|
38
|
+
attr_string({'class' => cls_array})
|
39
|
+
end
|
40
|
+
|
41
|
+
def ids_string(ids_array)
|
42
|
+
attr_string({'id' => ids_array})
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_class(item, cls)
|
46
|
+
(item[:classes] ||= []) << cls
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_class_if_empty(item, cls)
|
50
|
+
add_class(item, cls) if item[:classes].nil? || item[:classes].size == 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def tag_start(item)
|
54
|
+
return if item[:no_tag]
|
55
|
+
ids = item[:ids] || []
|
56
|
+
classes = item[:classes] || []
|
57
|
+
attr = item[:attrs] || {}
|
58
|
+
tag_name = @tag_name || item[:name]
|
59
|
+
@context << "<#{tag_name}#{ids_string(ids)}#{class_string(classes)}#{attr_string(attr)}"
|
60
|
+
if item[:no_body]
|
61
|
+
@context << " />"
|
62
|
+
else
|
63
|
+
@context << ">"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def output(string)
|
68
|
+
@context << string
|
69
|
+
end
|
70
|
+
|
71
|
+
def tag_end(item)
|
72
|
+
return if item[:no_tag]
|
73
|
+
tag_name = @tag_name || item[:name]
|
74
|
+
@context << "</#{tag_name}>#{@trailer}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def write(item)
|
78
|
+
@item_preprocessors.each { |x| item = instance_exec item.dup, &x }
|
79
|
+
@context.enable_pgroup, saved_ep = !(item[:args].include?('wo-pgroup') || !@context.enable_pgroup), @context.enable_pgroup
|
80
|
+
tag_start item
|
81
|
+
write_body item if !item[:no_body]
|
82
|
+
tag_end item if !item[:no_body]
|
83
|
+
@context.enable_pgroup = saved_ep
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_body(item)
|
87
|
+
@write_body_preprocessors.each {
|
88
|
+
|x|
|
89
|
+
return if instance_exec(item, &x) == :done
|
90
|
+
}
|
91
|
+
write_children item
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_children(item)
|
95
|
+
write_array(item[:children])
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_array(array)
|
99
|
+
return if array.nil? || array.size == 0
|
100
|
+
array.each { |x| @generator.to_html x }
|
101
|
+
@generator.context.chop_last_space if (@param[:chop_last_space])
|
102
|
+
end
|
103
|
+
|
104
|
+
def children_not_empty(item)
|
105
|
+
!item[:children].nil? && item[:children].size > 0 && item[:children].select { |x| (x.is_a? String) ? x.size >0 : !x.nil? }.size > 0
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ArtiMark
|
2
|
+
module Html
|
3
|
+
class WriterSelector
|
4
|
+
def initialize(generator, tag_writers = {}, trailer_default: "\n" )
|
5
|
+
@generator = generator
|
6
|
+
@common_tag_writer = TagWriter.create(nil, @generator, trailer: trailer_default)
|
7
|
+
@tag_writers = tag_writers
|
8
|
+
if !trailer_default.nil?
|
9
|
+
@tag_writers.each { |k, t|
|
10
|
+
if t.is_a? TagWriter
|
11
|
+
t.trailer = trailer_default
|
12
|
+
end
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def write(item)
|
19
|
+
writer = @tag_writers[item[:name]] || @common_tag_writer
|
20
|
+
writer.write(item)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
%% name = ArtiMark::Parser
|
2
|
+
|
3
|
+
# literals
|
4
|
+
eof = !.
|
5
|
+
space = ' ' | '\t'
|
6
|
+
eof_comment = lh space* "#" (!eof .)*
|
7
|
+
comment = lh space* "#" (!nl .)* nl
|
8
|
+
|
9
|
+
- = ( space | comment )*
|
10
|
+
empty_line = lh - nl
|
11
|
+
nl = /\r?\n/
|
12
|
+
lh = /^/
|
13
|
+
le = nl | /$/
|
14
|
+
word = < /[\w0-9]/ ( '-' | /[\w0-9]/ )* > { text }
|
15
|
+
num = < [0-9]+ > { text.to_i }
|
16
|
+
|
17
|
+
#common syntax
|
18
|
+
classname = '.' word:classname { classname }
|
19
|
+
classnames = (classname)*:classnames { classnames }
|
20
|
+
idname = '#' word:idname { idname }
|
21
|
+
idnames = (idname)*:idnames { idnames }
|
22
|
+
|
23
|
+
commandname = word:name idnames?:idnames classnames?:classes { {:name => name, :ids => idnames, :classes => classes} }
|
24
|
+
parameter = < ( /[^,)]/* | '"' /[^"]/* '"' | "'" /[^']/* "'" ) > { text }
|
25
|
+
parameters = < parameter (',' parameter)* > { text }
|
26
|
+
command = commandname:commandname ('(' - parameters:arg - ')')? { arg ||= ''; commandname.merge({ :args => arg.split(',') }) }
|
27
|
+
|
28
|
+
# paragraph
|
29
|
+
implicit_paragraph = < (!paragraph_delimiter - documentline - ):paragraph > { create_item(:paragraph, nil, paragraph, raw: text) }
|
30
|
+
paragraph = explicit_paragraph | implicit_paragraph
|
31
|
+
|
32
|
+
# paragraph_group
|
33
|
+
paragraph_group = < (paragraph nl | paragraph )+:paragraphs empty_line* > { create_item(:paragraph_group, nil, paragraphs, raw: text) }
|
34
|
+
|
35
|
+
# explicit block
|
36
|
+
blockhead = lh - command:command - '{' - le { command }
|
37
|
+
blockend = lh - '}' - le
|
38
|
+
blockbody = (!blockend block)+:body { body }
|
39
|
+
explicit_block = < blockhead:head blockbody:body blockend > { create_item(:block, head, body, raw: text) }
|
40
|
+
|
41
|
+
# inline command
|
42
|
+
inline = img_inline | common_inline
|
43
|
+
common_inline = < '[' command:command '{' documentcontent_except('}'):content '}' ']' > { create_item(:inline, command, content, raw: text) }
|
44
|
+
|
45
|
+
#img inline
|
46
|
+
img_command = command:command &{ command[:name] == 'img' && command[:args].size == 2}
|
47
|
+
img_inline = < '[' img_command:command ']' > { create_item(:inline, command, nil, raw: text) }
|
48
|
+
|
49
|
+
# special line commands
|
50
|
+
# newpage
|
51
|
+
newpage = line_command:item &{ item[:name] == 'newpage' }
|
52
|
+
# explicit paragraph
|
53
|
+
explicit_paragraph_command = command:command &{ command[:name] == 'p' }
|
54
|
+
explicit_paragraph = < lh - explicit_paragraph_command:command ':' documentcontent?:content le > { create_item(:paragraph, command, content, raw:text) }
|
55
|
+
|
56
|
+
# unordered list
|
57
|
+
unordered_list = < unordered_item+:items > { create_item(:ul, nil, items, raw: text) }
|
58
|
+
unordered_item = < lh '*:' documentcontent:content le > { create_item(:li, nil, content, raw: text) }
|
59
|
+
|
60
|
+
# ordered list
|
61
|
+
ordered_list = < ordered_item+:items > { create_item(:ol, nil, items, raw: text) }
|
62
|
+
ordered_item = < lh num ':' documentcontent:content le > { create_item(:li, nil, content, raw: text) }
|
63
|
+
|
64
|
+
# definition list
|
65
|
+
definition_list = < definition_item+:items > { create_item(:dl, nil, items, raw: text) }
|
66
|
+
definition_item = < lh ';:' - documentcontent_except(':'):term ':' - documentcontent:definition le > { create_item(:dtdd, {:args => [term, definition]}, nil, raw: text) }
|
67
|
+
|
68
|
+
items_list = unordered_list | ordered_list | definition_list
|
69
|
+
|
70
|
+
|
71
|
+
# generic line command
|
72
|
+
line_command = < lh - (!explicit_paragraph_command command):command ':' documentcontent?:content le > { create_item(:line_command, command, content, raw: text) }
|
73
|
+
|
74
|
+
# blocks
|
75
|
+
block = items_list | line_command | explicit_block | paragraph_group | empty_line+
|
76
|
+
block_delimiter = blockhead | blockend | newpage
|
77
|
+
paragraph_delimiter = block | block_delimiter
|
78
|
+
|
79
|
+
# texts
|
80
|
+
char = < /[[:print:]]/ > { text }
|
81
|
+
charstring = < char* > { text }
|
82
|
+
char_except(e) = char:c &{ c != e }
|
83
|
+
charstring_except(e) = < char_except(e)* > { text }
|
84
|
+
documentcontent_except(e) = (inline | !inline char_except(e))+:content ~parse_text(content)
|
85
|
+
documentcontent = (inline | !inline char)+:content ~parse_text(content)
|
86
|
+
documentline = lh documentcontent:content /$/ { content }
|
87
|
+
|
88
|
+
#header
|
89
|
+
stylesheets = < lh - 'stylesheets:' (!le charstring):stylesheets le > { create_item(:stylesheets, {:stylesheets => stylesheets.split(',').map(&:strip)}, nil, raw:text) }
|
90
|
+
title = < lh - 'title:' (!le charstring):title le > { create_item(:title, {:title => title }, nil, raw:text) }
|
91
|
+
lang = < lh - 'lang:' (!le charstring):lang le > { create_item(:lang, {:lang => lang }, nil, raw:text) }
|
92
|
+
header = stylesheets | title | lang
|
93
|
+
|
94
|
+
#root
|
95
|
+
root = header*:headers block*:blocks eof_comment? eof { headers + blocks }
|
96
|
+
|
97
|
+
|