@@ -912,6 +912,38 @@ template newLeaf(s: string): PRstNode = newRstLeaf(s)
912
912
proc newLeaf (p: var RstParser ): PRstNode =
913
913
result = newLeaf (currentTok (p).symbol)
914
914
915
+ proc validRefnamePunct (x: string ): bool =
916
+ # # https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names
917
+ x.len == 1 and x[0 ] in {'-' , '_' , '.' , ':' , '+' }
918
+
919
+ func getRefnameIdx (p: RstParser , startIdx: int ): int =
920
+ # # Gets last token index of a refname ("word" in RST terminology):
921
+ # #
922
+ # # reference names are single words consisting of alphanumerics plus
923
+ # # isolated (no two adjacent) internal hyphens, underscores, periods,
924
+ # # colons and plus signs; no whitespace or other characters are allowed.
925
+ # #
926
+ # # Refnames are used for:
927
+ # # - reference names
928
+ # # - role names
929
+ # # - directive names
930
+ # # - footnote labels
931
+ # #
932
+ # TODO : use this func in all other relevant places
933
+ var j = startIdx
934
+ if p.tok[j].kind == tkWord:
935
+ inc j
936
+ while p.tok[j].kind == tkPunct and validRefnamePunct (p.tok[j].symbol) and
937
+ p.tok[j+ 1 ].kind == tkWord:
938
+ inc j, 2
939
+ result = j - 1
940
+
941
+ func getRefname (p: RstParser , startIdx: int ): (string , int ) =
942
+ let lastIdx = getRefnameIdx (p, startIdx)
943
+ result [1 ] = lastIdx
944
+ for j in startIdx.. lastIdx:
945
+ result [0 ].add p.tok[j].symbol
946
+
915
947
proc getReferenceName (p: var RstParser , endStr: string ): PRstNode =
916
948
var res = newRstNode (rnInner)
917
949
while true :
@@ -1011,7 +1043,10 @@ proc match(p: RstParser, start: int, expr: string): bool =
1011
1043
var last = expr.len - 1
1012
1044
while i <= last:
1013
1045
case expr[i]
1014
- of 'w' : result = p.tok[j].kind == tkWord
1046
+ of 'w' :
1047
+ let lastIdx = getRefnameIdx (p, j)
1048
+ result = lastIdx >= j
1049
+ if result : j = lastIdx
1015
1050
of ' ' : result = p.tok[j].kind == tkWhite
1016
1051
of 'i' : result = p.tok[j].kind == tkIndent
1017
1052
of 'I' : result = p.tok[j].kind in {tkIndent, tkEof}
@@ -1058,7 +1093,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) =
1058
1093
proc whichRole (p: RstParser , sym: string ): RstNodeKind =
1059
1094
result = whichRoleAux (sym)
1060
1095
if result == rnUnknownRole:
1061
- rstMessage (p, mwUnsupportedLanguage, p.s.currRole )
1096
+ rstMessage (p, mwUnsupportedLanguage, sym )
1062
1097
1063
1098
proc toInlineCode (n: PRstNode , language: string ): PRstNode =
1064
1099
# # Creates rnInlineCode and attaches `n` contents as code (in 3rd son).
@@ -1078,6 +1113,11 @@ proc toInlineCode(n: PRstNode, language: string): PRstNode =
1078
1113
lb.add newLeaf (s)
1079
1114
result .add lb
1080
1115
1116
+ proc toUnknownRole (n: PRstNode , roleName: string ): PRstNode =
1117
+ let newN = newRstNode (rnInner, n.sons)
1118
+ let newSons = @ [newN, newLeaf (roleName)]
1119
+ result = newRstNode (rnUnknownRole, newSons)
1120
+
1081
1121
proc parsePostfix (p: var RstParser , n: PRstNode ): PRstNode =
1082
1122
var newKind = n.kind
1083
1123
var newSons = n.sons
@@ -1102,17 +1142,15 @@ proc parsePostfix(p: var RstParser, n: PRstNode): PRstNode =
1102
1142
result = newRstNode (newKind, newSons)
1103
1143
elif match (p, p.idx, " :w:" ):
1104
1144
# a role:
1105
- let roleName = nextTok (p).symbol
1145
+ let ( roleName, lastIdx) = getRefname (p, p.idx + 1 )
1106
1146
newKind = whichRole (p, roleName)
1107
1147
if newKind == rnUnknownRole:
1108
- let newN = newRstNode (rnInner, n.sons)
1109
- newSons = @ [newN, newLeaf (roleName)]
1110
- result = newRstNode (newKind, newSons)
1148
+ result = n.toUnknownRole (roleName)
1111
1149
elif newKind == rnInlineCode:
1112
1150
result = n.toInlineCode (language= roleName)
1113
1151
else :
1114
1152
result = newRstNode (newKind, newSons)
1115
- inc p.idx, 3
1153
+ p.idx = lastIdx + 2
1116
1154
else :
1117
1155
if p.s.currRoleKind == rnInlineCode:
1118
1156
result = n.toInlineCode (language= p.s.currRole)
@@ -1139,10 +1177,6 @@ proc parseSmiley(p: var RstParser): PRstNode =
1139
1177
result .text = val
1140
1178
return
1141
1179
1142
- proc validRefnamePunct (x: string ): bool =
1143
- # # https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names
1144
- x.len == 1 and x[0 ] in {'-' , '_' , '.' , ':' , '+' }
1145
-
1146
1180
proc isUrl (p: RstParser , i: int ): bool =
1147
1181
result = p.tok[i+ 1 ].symbol == " :" and p.tok[i+ 2 ].symbol == " //" and
1148
1182
p.tok[i+ 3 ].kind == tkWord and
@@ -1373,14 +1407,18 @@ proc parseInline(p: var RstParser, father: PRstNode) =
1373
1407
var n = newRstNode (rnInlineLiteral)
1374
1408
parseUntil (p, n, " ``" , false )
1375
1409
father.add (n)
1376
- elif match (p, p.idx, " :w:" ) and p.tok[p.idx+ 3 ].symbol == " `" :
1377
- let roleName = nextTok (p).symbol
1410
+ elif match (p, p.idx, " :w:" ) and
1411
+ (var lastIdx = getRefnameIdx (p, p.idx + 1 );
1412
+ p.tok[lastIdx+ 2 ].symbol == " `" ):
1413
+ let (roleName, _) = getRefname (p, p.idx+ 1 )
1378
1414
let k = whichRole (p, roleName)
1379
1415
var n = newRstNode (k)
1380
- inc p.idx, 3
1416
+ p.idx = lastIdx + 2
1381
1417
if k == rnInlineCode:
1382
1418
n = n.toInlineCode (language= roleName)
1383
1419
parseUntil (p, n, " `" , false ) # bug #17260
1420
+ if k == rnUnknownRole:
1421
+ n = n.toUnknownRole (roleName)
1384
1422
father.add (n)
1385
1423
elif isInlineMarkupStart (p, " `" ):
1386
1424
var n = newRstNode (rnInterpretedText)
@@ -1438,25 +1476,28 @@ proc parseInline(p: var RstParser, father: PRstNode) =
1438
1476
else : discard
1439
1477
1440
1478
proc getDirective (p: var RstParser ): string =
1441
- if currentTok (p).kind == tkWhite and nextTok (p).kind == tkWord:
1442
- var j = p.idx
1443
- inc p.idx
1444
- result = currentTok (p).symbol
1445
- inc p.idx
1446
- while currentTok (p).kind in {tkWord, tkPunct, tkAdornment, tkOther}:
1447
- if currentTok (p).symbol == " ::" : break
1448
- result .add (currentTok (p).symbol)
1449
- inc p.idx
1450
- if currentTok (p).kind == tkWhite: inc p.idx
1451
- if currentTok (p).symbol == " ::" :
1452
- inc p.idx
1453
- if currentTok (p).kind == tkWhite: inc p.idx
1454
- else :
1455
- p.idx = j # set back
1456
- result = " " # error
1457
- else :
1458
- result = " "
1459
- result = result .toLowerAscii ()
1479
+ result = " "
1480
+ if currentTok (p).kind == tkWhite:
1481
+ let (name, lastIdx) = getRefname (p, p.idx + 1 )
1482
+ let afterIdx = lastIdx + 1
1483
+ if name.len > 0 :
1484
+ if p.tok[afterIdx].symbol == " ::" :
1485
+ result = name
1486
+ p.idx = afterIdx + 1
1487
+ if currentTok (p).kind == tkWhite:
1488
+ inc p.idx
1489
+ elif currentTok (p).kind != tkIndent:
1490
+ rstMessage (p, mwRstStyle,
1491
+ " whitespace or newline expected after directive " & name)
1492
+ result = result .toLowerAscii ()
1493
+ elif p.tok[afterIdx].symbol == " :" :
1494
+ rstMessage (p, mwRstStyle,
1495
+ " double colon :: may be missing at end of '" & name & " '" ,
1496
+ p.tok[afterIdx].line, p.tok[afterIdx].col)
1497
+ elif p.tok[afterIdx].kind == tkPunct and p.tok[afterIdx].symbol[0 ] == ':' :
1498
+ rstMessage (p, mwRstStyle,
1499
+ " too many colons for a directive (should be ::)" ,
1500
+ p.tok[afterIdx].line, p.tok[afterIdx].col)
1460
1501
1461
1502
proc parseComment (p: var RstParser ): PRstNode =
1462
1503
case currentTok (p).kind
0 commit comments