OSDN Git Service

proceed implimentation
[blackquill/BlackQuill.git] / src / main / scala / org / blackquill / engine / BQParser.scala
1 package org.blackquill.engine
2
3 // BlackQuill Copyright (C) 2013 set.minami<set.minami@gmail.com>
4 // License MIT see also LISENCE.txt
5 // BQParser.
6
7 import org.apache.commons.logging._
8 import scala.collection.immutable.List
9 import scala.collection.mutable.LinkedHashMap
10 import scala.collection.mutable.Stack
11 import scala.collection.mutable.ListMap
12 import scala.collection.SortedSet
13 import scala.util.matching.Regex
14 import scala.xml._
15
16 import org.blackquill.engine._
17
18 class BQParser {
19         private val log:Log = LogFactory.getLog(classOf[BQParser])
20
21         private val Syntax = LinkedHashMap(
22         "^(.*?\\\\,)((>.*?\\\\,)+?)\\\\,(.*?)$$" -> ("blockquote",surroundByBlockquoteTAG _),
23         "^(.*?\\\\,)>(.*?)\\\\,\\\\,(.*?)$$" -> ("blockquote",surroundByGeneralTAG _),
24         "^(.*?)((\\s+\\d+?\\.\\s.+?\\\\,\\s*?)+?)(.*?)$$" -> ("ol",surroundByListTAG _),
25         "^(.*?)((\\s+(?:\\*|\\+|\\-)\\s.+?\\\\,\\s*?)+?)(.*?)$$" -> ("ul",surroundByListTAG _),
26         "^(.*?)\\*\\*(.+?)\\*\\*(.*?)$$" -> ("em",surroundByGeneralTAG _),
27         "^(.*?)\\*(.+?)\\*(.*?)$$" -> ("i",surroundByGeneralTAG _),
28         "^(.*\\\\,)(.*?)\\\\,(\\-+|=+)\\s*\\\\,(.*)$$" -> ("h",surroundByHeadTAGUnderlineStyle _),
29         "^(.*?)(#{1,6})\\s(.+?)(\\s#{1,6}?){0,1}\\\\,(.*?)$$" -> ("h",surroundByHeadTAG _)
30         //"^(.*?)(\\\\,.+?\\\\,)(.*?)$$" -> ("p",surroundByAbstructTAG _)
31         )
32         
33         private def surroundByBlockquoteTAG(doc:String, regex:String, TAG:String):String = {
34           val p = new Regex(regex, "before","inTAG","midInTag","following")
35           val m = p findFirstMatchIn(doc)
36           
37           var bef = ""
38           var fol = ""
39           var contentStr = ""
40           if(m != None){
41             val mid = m.get.group("inTAG")
42             log info "***-->" + mid
43
44             if(m.get.group("before") != None){bef = m.get.group("before")}else{bef = ""}
45                 if(m.get.group("following") != None){fol = m.get.group("following")}else{fol = ""}
46                 
47                 log info "=>" + mid
48                 if(mid != ""){
49                   val mat = """(>(.+?\\,))+?""".r.findAllMatchIn(mid)
50                   
51                   for(mt <- mat){
52                     contentStr += mt.group(2)
53                     log info "^^^" + mt
54                   }
55                 }
56
57                 log info "-->" + contentStr
58                 return surroundByBlockquoteTAG(bef, regex, TAG) + 
59                                 "<blockquote>" + contentStr + "</blockquote>" + surroundByBlockquoteTAG(fol, regex, TAG)
60           }
61           doc
62         }
63
64         private def surroundByListTAG(doc:String, regex:String, TAG:String):String = {
65                 val p = new Regex(regex, "before","elements","element","following")
66                 val m = p findFirstMatchIn(doc)
67                 var s = ""
68                 var bef = ""
69                 var fol = ""
70
71                 if(m != None){
72                         if(m.get.group("before") != None){bef = m.get.group("before")}else{bef = ""}
73                         if(m.get.group("following") != None){fol = m.get.group("following")}else{fol = ""}
74                         s = m.get.group("elements")
75                 }else{
76                   return doc
77                 }
78
79                 
80                 var sign = ""
81                 var sp = ""
82                 val indentWidth = 4
83                 var styles:((Int) => String) = null
84                 
85                 TAG match{
86               case "ul"=>
87                 sp = TAG
88                 styles = (index:Int) => {
89                           (index/indentWidth)%3 match{
90                                 case 1 => "disc"
91                                 case 2 => "circle"
92                                 case 0 => "square"
93                                 case _ => "---"
94                           }
95                 }
96                 sign = "[\\*|\\+|\\-]"
97               case "ol"=>
98                 sp = TAG
99                 styles = (index:Int) => {
100                           (index/indentWidth)%4 match{
101                             case 1 => "decimal"
102                             case 2 => "decimal-leading-zero"
103                             case 3 => "upper-latin"
104                             case 0 => "lower-latin"                         
105                             case _ => "---"
106                           }
107                 }
108                 sign = "\\d+?\\."
109             }
110                 
111                 var docList = List[String]()
112                 for(elem <- s"""(\\s+?$sign\\s.+?\\\\,)+?""".r.findAllMatchIn(s)){                               
113                         docList = elem.group(1)::docList
114                 }
115
116
117                 
118                 def _surroundByListTAG(doc:List[String],TAG:String,indent:Int):TreeNode[String] = {     
119                         var tree = new TreeNode[String]("")
120                     if(doc.isEmpty){return tree}                                                
121                 
122                         tree.add(new TreeNode("<" + sp + s""" style=\"list-style-type:${styles(indent)}\">"""))
123                                                                         var i = indent
124                         var list = List.empty[Tuple3[String,Int,String]]
125                         for(elem <- doc){
126                           val m = s"""((\\s+?)$sign\\s(.+?)\\,)""".r.findFirstMatchIn(elem)
127                           list = (m.get.group(1),m.get.group(2).size,m.get.group(3))::list
128                         }
129
130                         var restStr = List[String]()
131                         if(list.isEmpty){return new TreeNode("")
132                         }else{for(e <- list.reverse.tail){restStr = e._1::restStr}}
133                         
134                         restStr = restStr.reverse
135                         for(elem <- list.reverse){                      
136                                 if(elem._2 > i){                           
137                                         tree.add(new TreeNode("<" + sp + s""" style=\"list-style-type:${styles(elem._2)}\">"""))
138                                 }else if(elem._2 < i){                                  
139                                         tree.add(new TreeNode[String](s"</$sp>"*((i - elem._2)/indentWidth)))
140                                 }
141                                 tree.add(new TreeNode[String](s"<$TAG>" + elem._3 + s"</$TAG>\\,"))     
142                                 
143                                 
144                                 if(restStr.isEmpty){
145                                         restStr = List[String]("")                                
146                                 }else{
147                                         restStr = restStr.tail
148                                 }
149                                 i = elem._2
150                         }
151                 tree.add(new TreeNode(s"</$sp>"*((i - indent)/indentWidth + 1)))
152                 return tree
153           }
154                 val r1 = s"""(\\s*)${sign}.*?\\,""".r
155                 val wS1 = r1.findFirstMatchIn(s)
156                 var str = ""
157                 val r2 = s"""(\\s*)${sign}.*(\\\\,<br />.*?</blockquote>\\\\,)""".r
158                 val wS2 = r2.findFirstMatchIn(s)
159                 log debug "===>" + s
160                 
161                 var wS:Option[Regex.Match] = null
162                 if(wS2 != None){wS = wS2}else if(wS1 != None){wS = wS1}
163                 if(wS != None){
164                         for(e <- _surroundByListTAG(docList.reverse,"li",wS.get.group(1).size)){
165                           str += e.toString()
166                         }
167                   if(wS == wS2){str += wS.get.group(2)}
168                   
169                   log debug "---->" + str
170                   surroundByListTAG(bef,regex,TAG) + str + surroundByListTAG(fol,regex,TAG)
171                 }else{doc}
172         }
173         
174         private def surroundByHeadTAGUnderlineStyle(doc:String, regex:String, TAG:String):String = {
175           if(doc == ""){return doc}
176           
177           log debug "-->" + doc
178           val p = new Regex(regex, "before","inTAG","style","following")
179           val m = p findFirstMatchIn(doc)
180           var bef = ""
181           var fol = ""
182           var contentStr = ""
183           var headSign = TAG
184           if(m != None){
185             if(m.get.group("before") != None){bef = m.get.group("before")}else{bef = ""}
186             if(m.get.group("following") != None){fol = m.get.group("following")}else{fol = ""}
187             contentStr = m.get.group("inTAG")
188           
189             if(m.get.group("style").contains("-")){
190               headSign += "2"
191             }else{
192               headSign += "1"
193             }
194           
195             return surroundByHeadTAGUnderlineStyle(bef, regex, TAG) +
196                           s"<$headSign>$contentStr</$headSign>\\," + surroundByHeadTAGUnderlineStyle(fol, regex, TAG)
197           }
198           doc
199         }
200         
201         private def surroundByHeadTAG(doc:String, regex:String, TAG:String):String = {
202                 if(doc == ""){return doc}
203                 
204                 log debug "--> " + doc
205                 val p = new Regex(regex, "before","startHead","inTAG","endHead","following")
206                 val m = p findFirstMatchIn(doc)
207                 var contentStr = ""
208                 if(m != None){
209               var bef = ""
210               var fol = ""
211               
212                   if(m.get.group("before") != None){bef = m.get.group("before")}else{bef = ""}
213               if(m.get.group("following") != None){fol = m.get.group("following")}else{fol = ""}
214               contentStr = m.get.group("inTAG")
215               
216                   val headSize = m.get.group("startHead").size
217                   val endHead = m.get.group("endHead")
218                   log debug "-->" + endHead
219                   val headTAG = TAG + headSize
220                   if(endHead != null){
221                     val m2 = """^\s(#+?)$$""".r("wantSize").findFirstMatchIn(endHead)
222                     if(m2 != None){
223                       val size = m2.get.group("wantSize")
224                       if(size.size != headSize){
225                         contentStr += " " + size
226                         log warn "Curious header expression was found. " + 
227                         s" BlackQuill represents this <$headTAG>$contentStr</$headTAG> ."
228                       }
229                     }
230                   }
231                   
232                   return surroundByHeadTAG(bef,regex,TAG) +
233                                   s"<${headTAG}>$contentStr</${headTAG}>\\," +
234                                   surroundByHeadTAG(fol,regex,TAG)
235                 }
236           doc
237         }
238         
239         private def surroundByGeneralTAG(doc:String, regex:String, TAG:String):String = {
240           if(doc == ""){return doc}
241           log debug doc
242           val p = new Regex(regex,"before","inTAG","following")
243           val m = p findFirstMatchIn(doc)
244           if(m != None){
245               var bef = ""
246               var fol = ""
247                   if(m.get.group("before") != None){bef = m.get.group("before")}else{bef = ""}
248               if(m.get.group("following") != None){fol = m.get.group("following")}else{fol = ""}
249                   return surroundByGeneralTAG(bef,regex,TAG) + 
250                                   s"<${TAG}>" + m.get.group("inTAG") + s"</${TAG}>" +
251                           surroundByGeneralTAG(fol,regex,TAG)
252           }
253           doc
254         }
255         
256         private def constructHEADER(doc:String):String = {
257           val headTAG = "head"
258           val titleTAG = "title"
259           var title = "NO TITLE"
260           
261           val p = new Regex("""(?i)#{1,6}\s(.+?)\\,""")
262           val m = p findFirstMatchIn(doc)
263           if(m != None){title = m.get.group(1)}
264           
265           s"<${headTAG}>\n<${titleTAG}>${title}</${titleTAG}>\n</${headTAG}>"
266         }
267         
268         def toHTML(markdown:String):String = {
269                 val docType = "<!DOCTYPE html>"
270                 val bodyTAG = "body"
271                 val htmlTAG = "html"
272                 var md = markdown
273                 for(k <- Syntax keys){
274                  md = Syntax(k)._2(md, k, Syntax(k)._1)
275                 }
276                 val header = constructHEADER(markdown)
277                 s"${docType}\n${header}\n<${htmlTAG}>\n<${bodyTAG}>\n${md}\n</${bodyTAG}>\n</${htmlTAG}>"
278         }
279         
280         
281 }