1- # GFM table, non-standard
1+ # GFM table, https://github.github.com/gfm/#tables-extension-
22import re
33
44from .state_block import StateBlock
1010
1111
1212def getLine (state : StateBlock , line : int ):
13- pos = state .bMarks [line ] + state .blkIndent
13+ pos = state .bMarks [line ] + state .tShift [ line ]
1414 maximum = state .eMarks [line ]
1515
1616 # return state.src.substr(pos, max - pos)
@@ -21,48 +21,35 @@ def escapedSplit(string):
2121 result = []
2222 pos = 0
2323 max = len (string )
24- escapes = 0
24+ isEscaped = False
2525 lastPos = 0
26- backTicked = False
27- lastBackTick = 0
26+ current = ""
2827 ch = charCodeAt (string , pos )
2928
3029 while pos < max :
31- if ch == 0x60 : # /* ` */
32- if backTicked :
33- # make \` close code sequence, but not open it;
34- # the reason is: `\` is correct code block
35- backTicked = False
36- lastBackTick = pos
37- elif escapes % 2 == 0 :
38- backTicked = True
39- lastBackTick = pos
40- # /* | */
41- elif ch == 0x7C and (escapes % 2 == 0 ) and not backTicked :
42- result .append (string [lastPos :pos ])
43- lastPos = pos + 1
44-
45- if ch == 0x5C : # /* \ */
46- escapes += 1
47- else :
48- escapes = 0
30+ if ch == 0x7C : # /* | */
31+ if not isEscaped :
32+ # pipe separating cells, '|'
33+ result .append (current + string [lastPos :pos ])
34+ current = ""
35+ lastPos = pos + 1
36+ else :
37+ # escaped pipe, '\|'
38+ current += string [lastPos : pos - 1 ]
39+ lastPos = pos
4940
41+ isEscaped = ch == 0x5C # /* \ */
5042 pos += 1
5143
52- # If there was an un-closed backtick, go back to just after
53- # the last backtick, but as if it was a normal character
54- if pos == max and backTicked :
55- backTicked = False
56- pos = lastBackTick + 1
57-
5844 ch = charCodeAt (string , pos )
5945
60- result .append (string [lastPos :])
46+ result .append (current + string [lastPos :])
6147
6248 return result
6349
6450
6551def table (state : StateBlock , startLine : int , endLine : int , silent : bool ):
52+ tbodyLines = None
6653
6754 # should have at least two lines
6855 if startLine + 2 > endLine :
@@ -129,17 +116,28 @@ def table(state: StateBlock, startLine: int, endLine: int, silent: bool):
129116 return False
130117 if state .sCount [startLine ] - state .blkIndent >= 4 :
131118 return False
132- columns = escapedSplit (enclosingPipesRe .sub ("" , lineText ))
119+ columns = escapedSplit (lineText )
120+ if columns and columns [0 ] == "" :
121+ columns .pop (0 )
122+ if columns and columns [- 1 ] == "" :
123+ columns .pop ()
133124
134125 # header row will define an amount of columns in the entire table,
135- # and align row shouldn't be smaller than that (the rest of the rows can)
126+ # and align row should be exactly the same (the rest of the rows can differ )
136127 columnCount = len (columns )
137- if columnCount > len (aligns ):
128+ if columnCount == 0 or columnCount != len (aligns ):
138129 return False
139130
140131 if silent :
141132 return True
142133
134+ oldParentType = state .parentType
135+ state .parentType = "table"
136+
137+ # use 'blockquote' lists for termination because it's
138+ # the most similar to tables
139+ terminatorRules = state .md .block .ruler .getRules ("blockquote" )
140+
143141 token = state .push ("table_open" , "table" , 1 )
144142 token .map = tableLines = [startLine , 0 ]
145143
@@ -151,43 +149,60 @@ def table(state: StateBlock, startLine: int, endLine: int, silent: bool):
151149
152150 for i in range (len (columns )):
153151 token = state .push ("th_open" , "th" , 1 )
154- token .map = [startLine , startLine + 1 ]
155152 if aligns [i ]:
156153 token .attrs = [["style" , "text-align:" + aligns [i ]]]
157154
158155 token = state .push ("inline" , "" , 0 )
159- token .content = columns [i ].strip ()
156+ # note in markdown-it this map was removed in v12.0.0 however, we keep it,
157+ # since it is helpful to propagate to children tokens
160158 token .map = [startLine , startLine + 1 ]
159+ token .content = columns [i ].strip ()
161160 token .children = []
162161
163162 token = state .push ("th_close" , "th" , - 1 )
164163
165164 token = state .push ("tr_close" , "tr" , - 1 )
166165 token = state .push ("thead_close" , "thead" , - 1 )
167166
168- token = state .push ("tbody_open" , "tbody" , 1 )
169- token .map = tbodyLines = [startLine + 2 , 0 ]
170-
171167 nextLine = startLine + 2
172168 while nextLine < endLine :
173169 if state .sCount [nextLine ] < state .blkIndent :
174170 break
175171
172+ terminate = False
173+ for i in range (len (terminatorRules )):
174+ if terminatorRules [i ](state , nextLine , endLine , True ):
175+ terminate = True
176+ break
177+
178+ if terminate :
179+ break
176180 lineText = getLine (state , nextLine ).strip ()
177- if "|" not in lineText :
181+ if not lineText :
178182 break
179183 if state .sCount [nextLine ] - state .blkIndent >= 4 :
180184 break
181- columns = escapedSplit (enclosingPipesRe .sub ("" , lineText ))
185+ columns = escapedSplit (lineText )
186+ if columns and columns [0 ] == "" :
187+ columns .pop (0 )
188+ if columns and columns [- 1 ] == "" :
189+ columns .pop ()
190+
191+ if nextLine == startLine + 2 :
192+ token = state .push ("tbody_open" , "tbody" , 1 )
193+ token .map = tbodyLines = [startLine + 2 , 0 ]
182194
183195 token = state .push ("tr_open" , "tr" , 1 )
196+ token .map = [nextLine , nextLine + 1 ]
197+
184198 for i in range (columnCount ):
185199 token = state .push ("td_open" , "td" , 1 )
186- token .map = [nextLine , nextLine + 1 ]
187200 if aligns [i ]:
188201 token .attrs = [["style" , "text-align:" + aligns [i ]]]
189202
190203 token = state .push ("inline" , "" , 0 )
204+ # note in markdown-it this map was removed in v12.0.0 however, we keep it,
205+ # since it is helpful to propagate to children tokens
191206 token .map = [nextLine , nextLine + 1 ]
192207 try :
193208 token .content = columns [i ].strip () if columns [i ] else ""
@@ -201,9 +216,13 @@ def table(state: StateBlock, startLine: int, endLine: int, silent: bool):
201216
202217 nextLine += 1
203218
204- token = state .push ("tbody_close" , "tbody" , - 1 )
219+ if tbodyLines :
220+ token = state .push ("tbody_close" , "tbody" , - 1 )
221+ tbodyLines [1 ] = nextLine
222+
205223 token = state .push ("table_close" , "table" , - 1 )
206224
207- tableLines [1 ] = tbodyLines [1 ] = nextLine
225+ tableLines [1 ] = nextLine
226+ state .parentType = oldParentType
208227 state .line = nextLine
209228 return True
0 commit comments