diff options
author | Dávid Vastag <davewwpublic@gmail.com> | 2013-02-11 16:49:40 +0100 |
---|---|---|
committer | Andras Timar <atimar@suse.com> | 2013-02-13 10:19:14 +0100 |
commit | d06c698b799e0e4ceaf3a3760c9589fe29dc29a9 (patch) | |
tree | 3bfb9ee128aa58f2dd0d436dba1ffe04df933bc4 /helpcompiler/source | |
parent | 089a9afc95acf7eeff242369fcddee0f5337df62 (diff) |
Basic code syntaxhighlighting added to LibreOffice help
Change-Id: Id47172d0386e7aa28d82178f04b5f626f0c441fe
Diffstat (limited to 'helpcompiler/source')
-rw-r--r-- | helpcompiler/source/BasCodeTagger.cxx | 251 | ||||
-rw-r--r-- | helpcompiler/source/HelpCompiler.cxx | 42 | ||||
-rw-r--r-- | helpcompiler/source/HelpLinker.cxx | 2 |
3 files changed, 289 insertions, 6 deletions
diff --git a/helpcompiler/source/BasCodeTagger.cxx b/helpcompiler/source/BasCodeTagger.cxx new file mode 100644 index 000000000000..858db824bbb1 --- /dev/null +++ b/helpcompiler/source/BasCodeTagger.cxx @@ -0,0 +1,251 @@ +#include <helpcompiler/BasCodeTagger.hxx> + +LibXmlTreeWalker::LibXmlTreeWalker( xmlDocPtr doc ) +{ + if ( doc == NULL ) + throw BasicCodeTagger::NULL_DOCUMENT; + m_pCurrentNode = xmlDocGetRootElement( doc ); + if ( m_pCurrentNode == NULL ) + throw BasicCodeTagger::EMPTY_DOCUMENT; + else if ( m_pCurrentNode->xmlChildrenNode != NULL ) + m_Queue.push_back( m_pCurrentNode->xmlChildrenNode ); + nextNode(); +} + +void LibXmlTreeWalker::nextNode() +{ + + //next node + if ( m_pCurrentNode->next == NULL ) + { + m_pCurrentNode = m_Queue.front(); + m_Queue.pop_front(); + } + else + m_pCurrentNode = m_pCurrentNode->next; + //queue chiledren if they exist + if ( m_pCurrentNode->xmlChildrenNode != NULL ) + m_Queue.push_back( m_pCurrentNode->xmlChildrenNode ); +} + +void LibXmlTreeWalker::ignoreCurrNodesChildren() +{ + if ( m_pCurrentNode->xmlChildrenNode != NULL ) + m_Queue.pop_back(); +} + +bool LibXmlTreeWalker::end() +{ + return m_pCurrentNode->next == NULL && m_Queue.empty(); +} + +xmlNodePtr LibXmlTreeWalker::currentNode() +{ + return m_pCurrentNode; +} + +//====================================================== + +BasicCodeTagger::BasicCodeTagger( xmlDocPtr rootDoc ) +{ + if ( rootDoc == NULL ) + throw NULL_DOCUMENT; + m_pDocument = rootDoc; + m_pXmlTreeWalker = NULL; + m_Highlighter.initialize( HIGHLIGHT_BASIC ); + m_bTaggingCompleted = false; + +} + +BasicCodeTagger::~BasicCodeTagger() +{ + if ( m_pXmlTreeWalker != NULL ) + delete m_pXmlTreeWalker; +} +//!Gathers all the <bascode> tag nodes from xml tree. +/*! + * Assumes m_pDocument is valid. Handles m_pXmlTreeWalker and m_BasicCodeContainerTags members. + */ +void BasicCodeTagger::getBasicCodeContainerNodes() +{ + xmlNodePtr currentNode; + + m_BasicCodeContainerTags.clear(); + + if ( m_pXmlTreeWalker != NULL ) + delete m_pXmlTreeWalker; + m_pXmlTreeWalker = new LibXmlTreeWalker( m_pDocument ); + + currentNode = m_pXmlTreeWalker->currentNode(); + if ( !( xmlStrcmp( currentNode->name, (const xmlChar*) "bascode" ) ) ) + { //Found <bascode> + m_BasicCodeContainerTags.push_back( currentNode ); //it goes to the end of the list + } + while ( !m_pXmlTreeWalker->end() ) + { + m_pXmlTreeWalker->nextNode(); + if ( !( xmlStrcmp( m_pXmlTreeWalker->currentNode()->name, (const xmlChar*) "bascode" ) ) ) + { //Found <bascode> + m_BasicCodeContainerTags.push_back( m_pXmlTreeWalker->currentNode() ); //it goes to the end of the list + m_pXmlTreeWalker->ignoreCurrNodesChildren(); + } + } +} + +//! Extracts Basic Codes containted in <bascode> tags. +/*! + * For each <bascode> this method iterates trough it's <paragraph> tags and "inserts" <item> tags according + * to the Basic code syntax found in that paragraph. + */ +void BasicCodeTagger::tagBasCodeParagraphs() +{ + //helper variables + xmlNodePtr currBascodeNode; + xmlNodePtr currParagraph; + while ( !m_BasicCodeContainerTags.empty() ) + { + currBascodeNode = m_BasicCodeContainerTags.front(); + currParagraph = currBascodeNode->xmlChildrenNode; //first <paragraph> + while ( currParagraph != NULL ) + { + tagParagraph( currParagraph ); + currParagraph=currParagraph->next; + } + m_BasicCodeContainerTags.pop_front(); //next element + } +} + +//! Used by tagBasCodeParagraphs(). It does the work on the current paragraph containing Basic code. +void BasicCodeTagger::tagParagraph( xmlNodePtr paragraph ) +{ + //1. get paragraph text + xmlChar* codeSnippet; + codeSnippet = xmlNodeListGetString( m_pDocument, paragraph->xmlChildrenNode, 1 ); + if ( codeSnippet == NULL ) + { + return; //no text, nothing more to do here + } + //2. delete every child from paragraph (except attributes) + xmlNodePtr curNode = paragraph->xmlChildrenNode; + xmlNodePtr sibling; + while ( curNode != NULL ) + { + sibling = curNode->next; + xmlUnlinkNode( curNode ); + xmlFreeNode( curNode ); + curNode = sibling; + } + + //3. create new paragraph content + String strLine( + OUString( + reinterpret_cast<const sal_Char*>(codeSnippet), + strlen( + reinterpret_cast<const char*>(codeSnippet) + ), + RTL_TEXTENCODING_UTF8 + ) + ) ; + m_Highlighter.notifyChange ( 0, 0, &strLine, 1 ); + HighlightPortions portions; + m_Highlighter.getHighlightPortions( 0, strLine, portions ); + xmlChar* subStr; + xmlChar* typeStr; + xmlNodePtr text; + for ( size_t i=0; i<portions.size(); i++ ) + { + HighlightPortion& r = portions[i]; + subStr = xmlStrsub( codeSnippet, r.nBegin, r.nEnd-r.nBegin ); + text = xmlNewText( subStr ); + if ( r.tokenType != TT_WHITESPACE ) + { + typeStr = getTypeString( r.tokenType ); + curNode = xmlNewTextChild( paragraph, 0, (xmlChar*)"item", 0 ); + xmlNewProp( curNode, (xmlChar*)"type", typeStr ); + xmlAddChild( curNode, text ); + xmlFree( typeStr ); + } + else + xmlAddChild( paragraph, text ); + xmlFree( subStr ); + } + xmlFree( codeSnippet ); +} + +//! Manages tagging process. +/*! + * This is the "main" function of BasicCodeTagger. + */ +void BasicCodeTagger::tagBasicCodes() +{ + if ( m_bTaggingCompleted ) + return; + //gather <bascode> nodes + try + { + getBasicCodeContainerNodes(); + } + catch (TaggerException ex) + { + std::cout << "Some kind of error occured." << std::endl; + } + + //tag basic code paragraphs in <bascode> tag + tagBasCodeParagraphs(); + m_bTaggingCompleted = true; +} + +//! Converts SyntaxHighlighter's TokenTypes enum to a type string for <item type=... > +xmlChar* BasicCodeTagger::getTypeString( TokenTypes tokenType ) +{ + const char* str; + switch ( tokenType ) + { + case TT_UNKNOWN : + str = "unknown"; + break; + case TT_IDENTIFIER : + str = "identifier"; + break; + case TT_WHITESPACE : + str = "whitespace"; + break; + case TT_NUMBER : + str = "number"; + break; + case TT_STRING : + str = "string"; + break; + case TT_EOL : + str = "eol"; + break; + case TT_COMMENT : + str = "comment"; + break; + case TT_ERROR : + str = "error"; + break; + case TT_OPERATOR : + str = "operator"; + break; + case TT_KEYWORDS : + str = "keywords"; + break; + case TT_PARAMETER : + str = "parameter"; + break; + default : + str = "unknown"; + break; + } + return xmlCharStrdup( str ); +} + +//! Saves the current xml DOM to file with the provided libxml2 encoding string in an unformatted way. +void BasicCodeTagger::saveTreeToFile( const std::string& filePath, const std::string& encoding ) +{ + //saveDocument + int ret = xmlSaveFormatFileEnc( filePath.c_str(), m_pDocument, encoding.c_str(), 0 ); + if ( ret == -1 ) + throw FILE_WRITING; +} diff --git a/helpcompiler/source/HelpCompiler.cxx b/helpcompiler/source/HelpCompiler.cxx index 74b29f59ba52..8c6f66b49977 100644 --- a/helpcompiler/source/HelpCompiler.cxx +++ b/helpcompiler/source/HelpCompiler.cxx @@ -19,6 +19,7 @@ #include <helpcompiler/HelpCompiler.hxx> +#include <helpcompiler/BasCodeTagger.hxx> #include <limits.h> #include <stdlib.h> #include <string.h> @@ -36,25 +37,55 @@ static void impl_sleep( sal_uInt32 nSec ) osl::Thread::wait( aTime ); } - HelpCompiler::HelpCompiler(StreamTable &in_streamTable, const fs::path &in_inputFile, - const fs::path &in_src, const fs::path &in_resEmbStylesheet, + const fs::path &in_src, const fs::path &in_zipdir, const fs::path &in_resEmbStylesheet, const std::string &in_module, const std::string &in_lang, bool in_bExtensionMode) : streamTable(in_streamTable), inputFile(in_inputFile), - src(in_src), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet), + src(in_src), zipdir(in_zipdir), module(in_module), lang(in_lang), resEmbStylesheet(in_resEmbStylesheet), bExtensionMode( in_bExtensionMode ) { xmlKeepBlanksDefaultValue = 0; char* guitmp = getenv("GUI"); if (guitmp) { - // WTF? gui = (strcmp(guitmp, "UNX") ? gui : "UNIX"); gui = (strcmp(guitmp, "MAC") ? gui : "MAC"); gui = (strcmp(guitmp, "WNT") ? gui : "WIN"); } } +void HelpCompiler::sourceDocumentPreWorks( xmlDocPtr doc, const fs::path &filePath ) +{ + if ( doc ) + { + if ( module == "sbasic" ) + { + try + { + BasicCodeTagger bct( doc ); + bct.tagBasicCodes(); + } + catch ( BasicCodeTagger::TaggerException ex ) + { + if ( ex != BasicCodeTagger::EMPTY_DOCUMENT ) + throw; + } + //save document in ziptmp<modul>_<lang>/text directory + //1. construct new path + const std::string& pth = filePath.native_file_string(); + std::string sourceNativeXhpPath = pth.substr( pth.rfind( lang+"/text/" ) ).substr( lang.length() ); + std::string xhpFileName = sourceNativeXhpPath.substr( sourceNativeXhpPath.rfind( '/' ) + 1 ); + sourceNativeXhpPath = sourceNativeXhpPath.substr( 0, sourceNativeXhpPath.rfind( '/' ) ); + //2. save xml doc with the new path + // -create directory hierachy + fs::create_directory( fs::path( zipdir.native_file_string() + sourceNativeXhpPath, fs::native ) ); + // -save document + if ( -1 == xmlSaveFormatFileEnc( (zipdir.native_file_string() + sourceNativeXhpPath + '/' + xhpFileName).c_str(), doc, "utf-8", 0 ) ) + throw BasicCodeTagger::FILE_WRITING; + } + } +} + xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath) { static const char *params[4 + 1]; @@ -68,6 +99,7 @@ xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath) impl_sleep( 3 ); res = xmlParseFile(filePath.native_file_string().c_str()); } + sourceDocumentPreWorks( res, filePath ); } else { @@ -93,7 +125,7 @@ xmlDocPtr HelpCompiler::getSourceDocument(const fs::path &filePath) impl_sleep( 3 ); doc = xmlParseFile(filePath.native_file_string().c_str()); } - + sourceDocumentPreWorks( doc, filePath ); //???res = xmlParseFile(filePath.native_file_string().c_str()); res = xsltApplyStylesheet(cur, doc, params); diff --git a/helpcompiler/source/HelpLinker.cxx b/helpcompiler/source/HelpLinker.cxx index 62d364583f2a..4bbe2b6bd23e 100644 --- a/helpcompiler/source/HelpLinker.cxx +++ b/helpcompiler/source/HelpLinker.cxx @@ -377,7 +377,7 @@ void HelpLinker::link() throw( HelpProcessingException ) xhpFile = fs::path(xhpFileName, fs::native); } - HelpCompiler hc( streamTable, xhpFile, langsourceRoot, + HelpCompiler hc( streamTable, xhpFile, langsourceRoot, zipdir, embeddStylesheet, module, lang, bExtensionMode ); HCDBG(std::cerr << "before compile of " << xhpFileName << std::endl); |