1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <BasCodeTagger.hxx>
12 LibXmlTreeWalker::LibXmlTreeWalker( xmlDocPtr doc
)
15 throw BasicCodeTagger::NULL_DOCUMENT
;
16 m_pCurrentNode
= xmlDocGetRootElement( doc
);
17 if ( m_pCurrentNode
== nullptr )
18 throw BasicCodeTagger::EMPTY_DOCUMENT
;
19 else if ( m_pCurrentNode
->xmlChildrenNode
!= nullptr )
20 m_Queue
.push_back( m_pCurrentNode
->xmlChildrenNode
);
24 void LibXmlTreeWalker::nextNode()
28 if ( m_pCurrentNode
->next
== nullptr )
30 m_pCurrentNode
= m_Queue
.front();
34 m_pCurrentNode
= m_pCurrentNode
->next
;
35 //queue children if they exist
36 if ( m_pCurrentNode
->xmlChildrenNode
!= nullptr )
37 m_Queue
.push_back( m_pCurrentNode
->xmlChildrenNode
);
40 void LibXmlTreeWalker::ignoreCurrNodesChildren()
42 if ( m_pCurrentNode
->xmlChildrenNode
!= nullptr )
46 bool LibXmlTreeWalker::end()
48 return m_pCurrentNode
->next
== nullptr && m_Queue
.empty();
52 BasicCodeTagger::BasicCodeTagger( xmlDocPtr rootDoc
):
53 m_Highlighter(HighlighterLanguage::Basic
)
55 if ( rootDoc
== nullptr )
57 m_pDocument
= rootDoc
;
58 m_pXmlTreeWalker
= nullptr;
59 m_bTaggingCompleted
= false;
63 BasicCodeTagger::~BasicCodeTagger()
65 if ( m_pXmlTreeWalker
!= nullptr )
66 delete m_pXmlTreeWalker
;
68 //!Gathers all the <bascode> tag nodes from xml tree.
70 * Assumes m_pDocument is valid. Handles m_pXmlTreeWalker and m_BasicCodeContainerTags members.
72 void BasicCodeTagger::getBasicCodeContainerNodes()
74 xmlNodePtr currentNode
;
76 m_BasicCodeContainerTags
.clear();
78 if ( m_pXmlTreeWalker
!= nullptr )
79 delete m_pXmlTreeWalker
;
80 m_pXmlTreeWalker
= new LibXmlTreeWalker( m_pDocument
);
82 currentNode
= m_pXmlTreeWalker
->currentNode();
83 if ( !( xmlStrcmp( currentNode
->name
, reinterpret_cast<const xmlChar
*>("bascode") ) ) )
85 m_BasicCodeContainerTags
.push_back( currentNode
); //it goes to the end of the list
87 while ( !m_pXmlTreeWalker
->end() )
89 m_pXmlTreeWalker
->nextNode();
90 if ( !( xmlStrcmp( m_pXmlTreeWalker
->currentNode()->name
, reinterpret_cast<const xmlChar
*>("bascode") ) ) )
92 m_BasicCodeContainerTags
.push_back( m_pXmlTreeWalker
->currentNode() ); //it goes to the end of the list
93 m_pXmlTreeWalker
->ignoreCurrNodesChildren();
98 //! Extracts Basic Codes contained in <bascode> tags.
100 * For each <bascode> this method iterates through it's <paragraph> tags and "inserts" <item> tags according
101 * to the Basic code syntax found in that paragraph.
103 void BasicCodeTagger::tagBasCodeParagraphs()
106 xmlNodePtr currBascodeNode
;
107 xmlNodePtr currParagraph
;
108 while ( !m_BasicCodeContainerTags
.empty() )
110 currBascodeNode
= m_BasicCodeContainerTags
.front();
111 currParagraph
= currBascodeNode
->xmlChildrenNode
; //first <paragraph>
112 while ( currParagraph
!= nullptr )
114 tagParagraph( currParagraph
);
115 currParagraph
=currParagraph
->next
;
117 m_BasicCodeContainerTags
.pop_front(); //next element
121 //! Used by tagBasCodeParagraphs(). It does the work on the current paragraph containing Basic code.
122 void BasicCodeTagger::tagParagraph( xmlNodePtr paragraph
)
124 //1. get paragraph text
125 xmlChar
* codeSnippet
;
126 codeSnippet
= xmlNodeListGetString( m_pDocument
, paragraph
->xmlChildrenNode
, 1 );
127 if ( codeSnippet
== nullptr )
129 return; //no text, nothing more to do here
131 //2. delete every child from paragraph (except attributes)
132 xmlNodePtr curNode
= paragraph
->xmlChildrenNode
;
134 while ( curNode
!= nullptr )
136 sibling
= curNode
->next
;
137 xmlUnlinkNode( curNode
);
138 xmlFreeNode( curNode
);
142 //3. create new paragraph content
143 OUString
strLine( reinterpret_cast<const sal_Char
*>(codeSnippet
),
144 strlen(reinterpret_cast<const char*>(codeSnippet
)),
145 RTL_TEXTENCODING_UTF8
);
146 std::vector
<HighlightPortion
> portions
;
147 m_Highlighter
.getHighlightPortions( strLine
, portions
);
148 for (std::vector
<HighlightPortion
>::iterator
i(portions
.begin());
149 i
!= portions
.end(); ++i
)
151 OString
sToken(OUStringToOString(strLine
.copy(i
->nBegin
, i
->nEnd
-i
->nBegin
), RTL_TEXTENCODING_UTF8
));
152 xmlNodePtr text
= xmlNewText(reinterpret_cast<const xmlChar
*>(sToken
.getStr()));
153 if ( i
->tokenType
!= TokenType::Whitespace
)
155 xmlChar
* typeStr
= getTypeString( i
->tokenType
);
156 curNode
= xmlNewTextChild( paragraph
, nullptr, reinterpret_cast<xmlChar
const *>("item"), nullptr );
157 xmlNewProp( curNode
, reinterpret_cast<xmlChar
const *>("type"), typeStr
);
158 xmlAddChild( curNode
, text
);
162 xmlAddChild( paragraph
, text
);
164 xmlFree( codeSnippet
);
167 //! Manages tagging process.
169 * This is the "main" function of BasicCodeTagger.
171 void BasicCodeTagger::tagBasicCodes()
173 if ( m_bTaggingCompleted
)
175 //gather <bascode> nodes
178 getBasicCodeContainerNodes();
180 catch (TaggerException
&ex
)
182 std::cout
<< "BasCodeTagger error occurred. Error code:" << ex
<< std::endl
;
185 //tag basic code paragraphs in <bascode> tag
186 tagBasCodeParagraphs();
187 m_bTaggingCompleted
= true;
190 //! Converts SyntaxHighlighter's TokenTypes enum to a type string for <item type=... >
191 xmlChar
* BasicCodeTagger::getTypeString( TokenType tokenType
)
196 case TokenType::Unknown
:
199 case TokenType::Identifier
:
202 case TokenType::Whitespace
:
205 case TokenType::Number
:
208 case TokenType::String
:
211 case TokenType::EOL
:
214 case TokenType::Comment
:
217 case TokenType::Error
:
220 case TokenType::Operator
:
223 case TokenType::Keywords
:
226 case TokenType::Parameter
:
233 return xmlCharStrdup( str
);
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */