1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <gendoc/html/HtmlSourceCodeWriter.hpp>
  7 #include <sngxml/dom/CharacterData.hpp>
  8 
  9 namespace gendoc { namespace html {
 10 
 11 HtmlSourceCodeWriter::HtmlSourceCodeWriter() : lineElement(nullptr)inlineLineElement(nullptr)currentPos(0)inlineCurrentPos(0)
 12 {
 13 }
 14 
 15 void HtmlSourceCodeWriter::WriteToElement(sngxml::dom::Element* elementconst std::u32string& text)
 16 {
 17     for (char32_t c : text)
 18     {
 19         if (c == ' ')
 20         {
 21             element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"nbsp")));
 22         }
 23         else
 24         {
 25             element->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::Text(std::u32string(1c))));
 26         }
 27     }
 28 }
 29 
 30 void HtmlSourceCodeWriter::MoveTo(const Span& span)
 31 {
 32     if (currentPos < span.start)
 33     {
 34         int length = span.start - currentPos;
 35         WriteSpaceKind(lengthWriteKind::line);
 36     }
 37     if (inlineCurrentPos < span.start)
 38     {
 39         int length = span.start - inlineCurrentPos;
 40         WriteSpaceKind(lengthWriteKind::inlineLine);
 41     }
 42 }
 43 
 44 void HtmlSourceCodeWriter::WriteLineNumberKind(const std::u32string& lineNumberWriteKind kind)
 45 {
 46     std::unique_ptr<sngxml::dom::Element> lineNumberElement(new sngxml::dom::Element(U"span"));
 47     lineNumberElement->SetAttribute(U"class"U"lineNumber");
 48     WriteToElement(lineNumberElement.get()lineNumber);
 49     if ((kind & WriteKind::inlineLine) != WriteKind::none)
 50     {
 51         if (inlineLineElement)
 52         {
 53             inlineLineElement->AppendChild(lineNumberElement->CloneNode(true));
 54             inlineCurrentPos += lineNumber.length();
 55         }
 56     }
 57     if ((kind & WriteKind::line) != WriteKind::none)
 58     {
 59         lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(lineNumberElement.release()));
 60         currentPos += lineNumber.length();
 61     }
 62 }
 63 void HtmlSourceCodeWriter::WriteLineNumber(const std::u32string& lineNumber)
 64 {
 65     WriteLineNumberKind(lineNumberWriteKind::both);
 66 }
 67 
 68 void HtmlSourceCodeWriter::WriteLineComment(const std::u32string& comment)
 69 {
 70     std::u32string line;
 71     for (char32_t c : comment)
 72     {
 73         if (c != '\r' && c != '\n')
 74         {
 75             line.append(1c);
 76         }
 77     }
 78     std::unique_ptr<sngxml::dom::Element> commentElement(new sngxml::dom::Element(U"span"));
 79     commentElement->SetAttribute(U"class"U"comment");
 80     WriteToElement(commentElement.get()line);
 81     if (inlineLineElement)
 82     {
 83         inlineLineElement->AppendChild(commentElement->CloneNode(true));
 84         inlineCurrentPos += comment.length();
 85     }
 86     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(commentElement.release()));
 87     currentPos += line.length();
 88 }
 89 
 90 void HtmlSourceCodeWriter::WriteBlockComment(const std::u32string& comment)
 91 {
 92     std::unique_ptr<sngxml::dom::Element> commentElement(new sngxml::dom::Element(U"span"));
 93     commentElement->SetAttribute(U"class"U"comment");
 94     WriteToElement(commentElement.get()comment);
 95     if (inlineLineElement)
 96     {
 97         inlineLineElement->AppendChild(commentElement->CloneNode(true));
 98         inlineCurrentPos += comment.length();
 99     }
100     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(commentElement.release()));
101     currentPos += comment.length();
102 }
103 
104 void HtmlSourceCodeWriter::WriteKeyword(const std::u32string& keyword)
105 {
106     std::unique_ptr<sngxml::dom::Element> keywordElement(new sngxml::dom::Element(U"span"));
107     keywordElement->SetAttribute(U"class"U"kw");
108     WriteToElement(keywordElement.get()keyword);
109     if (inlineLineElement)
110     {
111         inlineLineElement->AppendChild(keywordElement->CloneNode(true));
112         inlineCurrentPos += keyword.length();
113     }
114     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(keywordElement.release()));
115     currentPos += keyword.length();
116 }
117 
118 void HtmlSourceCodeWriter::WriteIdentifier(const std::u32string& identifier)
119 {
120     std::unique_ptr<sngxml::dom::Element> identifierElement(new sngxml::dom::Element(U"span"));
121     identifierElement->SetAttribute(U"class"U"identifier");
122     WriteToElement(identifierElement.get()identifier);
123     if (inlineLineElement)
124     {
125         inlineLineElement->AppendChild(identifierElement->CloneNode(true));
126         inlineCurrentPos += identifier.length();
127     }
128     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(identifierElement.release()));
129     currentPos += identifier.length();
130 }
131 
132 void HtmlSourceCodeWriter::WriteLink(const std::u32string& identifierconst std::u32string& ref)
133 {
134     if (ref.empty())
135     {
136         std::unique_ptr<sngxml::dom::Element> identifierElement(new sngxml::dom::Element(U"span"));
137         identifierElement->SetAttribute(U"class"U"identifier");
138         WriteToElement(identifierElement.get()identifier);
139         lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(identifierElement.release()));
140         currentPos += identifier.length();
141     }
142     else
143     {
144         std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
145         linkElement->SetAttribute(U"href"ref);
146         WriteToElement(linkElement.get()identifier);
147         lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
148         currentPos += identifier.length();
149     }
150 }
151 
152 void HtmlSourceCodeWriter::WriteInlineLink(const std::u32string& identifierconst std::u32string& ref)
153 {
154     if (inlineLineElement)
155     {
156         if (ref.empty())
157         {
158             std::unique_ptr<sngxml::dom::Element> identifierElement(new sngxml::dom::Element(U"span"));
159             identifierElement->SetAttribute(U"class"U"identifier");
160             WriteToElement(identifierElement.get()identifier);
161             inlineLineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(identifierElement.release()));
162             inlineCurrentPos += identifier.length();
163         }
164         else
165         {
166             std::unique_ptr<sngxml::dom::Element> linkElement(new sngxml::dom::Element(U"a"));
167             linkElement->SetAttribute(U"href"ref);
168             WriteToElement(linkElement.get()identifier);
169             inlineLineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(linkElement.release()));
170             inlineCurrentPos += identifier.length();
171         }
172     }
173 }
174 
175 void HtmlSourceCodeWriter::WriteType(const std::u32string& type)
176 {
177     std::unique_ptr<sngxml::dom::Element> typeElement(new sngxml::dom::Element(U"span"));
178     typeElement->SetAttribute(U"class"U"type");
179     WriteToElement(typeElement.get()type);
180     if (inlineLineElement)
181     {
182         inlineLineElement->AppendChild(typeElement->CloneNode(true));
183         inlineCurrentPos += type.length();
184     }
185     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeElement.release()));
186     currentPos += type.length();
187 }
188 
189 void HtmlSourceCodeWriter::WritePP(const std::u32string& pp)
190 {
191     std::unique_ptr<sngxml::dom::Element> ppElement(new sngxml::dom::Element(U"span"));
192     ppElement->SetAttribute(U"class"U"pp");
193     WriteToElement(ppElement.get()pp);
194     if (inlineLineElement)
195     {
196         inlineLineElement->AppendChild(ppElement->CloneNode(true));
197         inlineCurrentPos += pp.length();
198     }
199     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(ppElement.release()));
200     currentPos += pp.length();
201 }
202 
203 void HtmlSourceCodeWriter::WriteChar(const std::u32string& chars)
204 {
205     WriteString(chars);
206 }
207 
208 void HtmlSourceCodeWriter::WriteString(const std::u32string& string)
209 {
210     std::unique_ptr<sngxml::dom::Element> stringElement(new sngxml::dom::Element(U"span"));
211     stringElement->SetAttribute(U"class"U"string");
212     WriteToElement(stringElement.get()string);
213     if (inlineLineElement)
214     {
215         inlineLineElement->AppendChild(stringElement->CloneNode(true));
216         inlineCurrentPos += string.length();
217     }
218     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(stringElement.release()));
219     currentPos += string.length();
220 }
221 
222 void HtmlSourceCodeWriter::WriteSpaceKind(int numSpacesWriteKind kind)
223 {
224     if ((kind & WriteKind::line) != WriteKind::none)
225     {
226         for (int i = 0; i < numSpaces; ++i)
227         {
228             lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"nbsp")));
229         }
230         currentPos += numSpaces;
231     }
232     if (inlineLineElement)
233     {
234         if ((kind & WriteKind::inlineLine) != WriteKind::none)
235         {
236             for (int i = 0; i < numSpaces; ++i)
237             {
238                 inlineLineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(new sngxml::dom::EntityReference(U"nbsp")));
239             }
240             inlineCurrentPos += numSpaces;
241         }
242     }
243 }
244 
245 void HtmlSourceCodeWriter::WriteSpace(int numSpaces)
246 {
247     WriteSpaceKind(numSpacesWriteKind::both);
248 }
249 
250 void HtmlSourceCodeWriter::WriteSpaces(const std::u32string& spaces)
251 {
252     int numSpaces = 0;
253     for (char32_t c : spaces)
254     {
255         if (c == '\t')
256         {
257             numSpaces += 4;
258         }
259         else if (c == ' ')
260         {
261             ++numSpaces;
262         }
263     }
264     WriteSpace(numSpaces);
265 }
266 
267 void HtmlSourceCodeWriter::WriteNumber(const std::u32string& number)
268 {
269     WriteOther(number);
270 }
271 
272 void HtmlSourceCodeWriter::WriteOther(const std::u32string& other)
273 {
274     std::unique_ptr<sngxml::dom::Element> otherElement(new sngxml::dom::Element(U"span"));
275     otherElement->SetAttribute(U"class"U"other");
276     WriteToElement(otherElement.get()other);
277     if (inlineLineElement)
278     {
279         inlineLineElement->AppendChild(otherElement->CloneNode(true));
280         inlineCurrentPos += other.length();
281     }
282     lineElement->AppendChild(std::unique_ptr<sngxml::dom::Node>(otherElement.release()));
283     currentPos += other.length();
284 }
285 
286 } } // namespace gendoc::html