1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 | --
-- Copyright (C) 2021-2023, AdaCore
--
-- SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
--
with VSS.Characters;
with VSS.Regular_Expressions;
package body Markdown.Implementation.Fenced_Code_Blocks is
Fence_Pattern : constant Wide_Wide_String :=
"^( | | |)(?:(``(?:`+)) *([^`]*)|(~~(?:~+)) *([^\f]*))$";
-- 1 2 3 4 5 <- group index
Fence : VSS.Regular_Expressions.Regular_Expression;
-- Regexp of Fence_Pattern
-----------------
-- Append_Line --
-----------------
overriding procedure Append_Line
(Self : in out Fenced_Code_Block;
Input : Input_Position;
CIP : Can_Interrupt_Paragraph;
Ok : in out Boolean)
is
pragma Unreferenced (CIP);
use type VSS.Characters.Virtual_Character;
Match : constant VSS.Regular_Expressions.Regular_Expression_Match :=
Fence.Match (Input.Line.Expanded, Input.First);
Cursor : VSS.Strings.Character_Iterators.Character_Iterator;
begin
if Self.Closed then
Ok := False;
return;
elsif Match.Has_Match
-- Closing fences cannot have info string
and then Match.Captured (3).Is_Empty
and then Match.Captured (5).Is_Empty
then
Self.Closed := Match.Marker (if Self.Is_Tick_Fence then 2 else 4).
Character_Length >= Self.Fence_Length;
end if;
if Self.Closed then
for J in 1 .. Self.Blank loop
Self.Lines.Append (VSS.Strings.Empty_Virtual_String);
end loop;
else
Cursor.Set_At (Input.First);
if Cursor.Has_Element then
-- Try to skip indent spaces
for J in 1 .. Self.Indent loop
exit when Cursor.Element /= ' ' or else not Cursor.Forward;
end loop;
end if;
if Cursor.Has_Element then
for J in 1 .. Self.Blank loop
Self.Lines.Append (VSS.Strings.Empty_Virtual_String);
end loop;
Self.Lines.Append (Input.Line.Unexpanded_Tail (Cursor));
Self.Blank := 0;
else
Self.Blank := Self.Blank + 1;
end if;
end if;
Ok := True;
end Append_Line;
------------
-- Create --
------------
overriding function Create
(Input : not null access Input_Position) return Fenced_Code_Block
is
Match : constant VSS.Regular_Expressions.Regular_Expression_Match :=
Fence.Match (Input.Line.Expanded, Input.First);
begin
pragma Assert (Match.Has_Match);
return Result : Fenced_Code_Block do
Result.Indent := Match.Marker (1).Character_Length;
Result.Is_Tick_Fence := Match.Has_Capture (2);
if Result.Is_Tick_Fence then
Result.Fence_Length := Match.Marker (2).Character_Length;
Result.Info_String := Match.Captured (3);
else
Result.Fence_Length := Match.Marker (4).Character_Length;
Result.Info_String := Match.Captured (5);
end if;
-- Shift Input.First to end-of-line
Input.First.Set_After_Last (Input.Line.Expanded);
end return;
end Create;
--------------
-- Detector --
--------------
procedure Detector
(Input : Input_Position;
Tag : in out Ada.Tags.Tag;
CIP : out Can_Interrupt_Paragraph)
is
Match : VSS.Regular_Expressions.Regular_Expression_Match;
begin
if not Fence.Is_Valid then -- Construct Fence regexp
Fence := VSS.Regular_Expressions.To_Regular_Expression
(VSS.Strings.To_Virtual_String (Fence_Pattern));
end if;
Match := Fence.Match (Input.Line.Expanded, Input.First);
if Match.Has_Match then
Tag := Fenced_Code_Block'Tag;
CIP := False;
end if;
end Detector;
----------
-- Text --
----------
function Text
(Self : Fenced_Code_Block)
return VSS.String_Vectors.Virtual_String_Vector
is
First : Positive := 1;
Last : Natural := 0;
begin
for J in 1 .. Self.Lines.Length loop
First := J;
exit when not Self.Lines (J).Is_Empty;
end loop;
for J in reverse 1 .. Self.Lines.Length loop
Last := J;
exit when not Self.Lines (J).Is_Empty;
end loop;
if First = 1 and Last = Self.Lines.Length then
return Self.Lines;
else
-- Drop leading and trailing empty lines
return Result : VSS.String_Vectors.Virtual_String_Vector do
for J in First .. Last loop
Result.Append (Self.Lines (J));
end loop;
end return;
end if;
end Text;
end Markdown.Implementation.Fenced_Code_Blocks;
|