/*********************************************************************************************
begin : Sun Jul 20 2003
copyright : ( C ) 2003 by Jeroen Wijnhout ( Jeroen . Wijnhout @ kdemail . net )
( C ) 2005 - 2007 by Holger Danielsson ( holger . danielsson @ versanet . de )
( C ) 2006 by Michel Ludwig ( michel . ludwig @ kdemail . net )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 2005-11-02: dani
// - cleaning up source of central function updateStruct()
// - always use 'else if', because all conditions are exclusive or
// - most often used commands are at the top
// - add some new types of elements (and levels) for the structure view
// - new commands, which are passed to the structure listview:
// \includegraphics, \caption
// - all user defined commands for labels are recognized
// - changed folder name of KileStruct::BibItem to "bibs", so that "refs"
// is still unused and can be used for references (if wanted)
// - \begin, \end to gather all environments. But only figure and table
// environments are passed to the structure view
// 2005-11-26: dani
// - add support for \fref, \Fref and \eqref references commands
// 2005-12-07: dani
// - add support to enable and disable some structure view items
// 2006-01-16 tbraun
// - fix #59945 Now we call (through a signal ) project->buildProjectTree so the bib files are correct,
// and therefore the keys in \cite completion
// 2006-02-09 tbraun/dani
// - fix #106261#4 improved parsing of (optional) command parameters
// - all comments are removed
//2006-09-09 mludwig
// - generalising the different document types
//2007-02-15
// - signal foundItem() not only sends the cursor position of the parameter,
// but also the real cursor position of the command
// 2007-03-12 dani
// - use KileDocument::Extensions
// 2007-03-24 dani
// - preliminary minimal support for Beamer class
// 2007-03-25 dani
// - merge labels and sections in document structure view as user configurable option
// 2007-04-06 dani
// - add TODO/FIXME section to structure view
# include "kiledocumentinfo.h"
# include <tqfileinfo.h>
# include <tqlabel.h>
# include <tqlayout.h>
# include <tqregexp.h>
# include <tqdatetime.h>
# include <tdeio/netaccess.h>
# include <tdeconfig.h>
# include <klocale.h>
# include <tdeapplication.h>
# include "kiledebug.h"
# include <kiconloader.h>
# include <kmessagebox.h>
# include <kinputdialog.h>
# include "codecompletion.h"
# include "kileuntitled.h"
# include "kileconfig.h"
namespace KileDocument
{
bool Info : : containsInvalidCharacters ( const KURL & url )
{
TQString filename = url . fileName ( ) ;
return filename . contains ( " " ) | | filename . contains ( " ~ " ) | | filename . contains ( " $ " ) | | filename . contains ( " # " ) ;
}
KURL Info : : repairInvalidCharacters ( const KURL & url , bool checkForFileExistence /* = true */ )
{
KURL ret ( url ) ;
do {
bool isOK ;
TQString newURL = KInputDialog : : getText (
i18n ( " Invalid Characters " ) ,
i18n ( " The filename contains invalid characters ($~ #).<br>Please provide \
another one , or click \ " Cancel \" to save anyway. " ) ,
ret . filename ( ) ,
& isOK ) ;
if ( ! isOK )
break ;
ret . setFileName ( newURL ) ;
} while ( containsInvalidCharacters ( ret ) ) ;
return ( checkForFileExistence ? renameIfExist ( ret ) : ret ) ;
}
KURL Info : : renameIfExist ( const KURL & url )
{
KURL ret ( url ) ;
while ( TDEIO : : NetAccess : : exists ( url , true , kapp - > mainWidget ( ) ) ) // check for writing possibility
{
bool isOK ;
TQString newURL = KInputDialog : : getText (
i18n ( " File Already Exists " ) ,
i18n ( " A file with filename '%1' already exists.<br>Please provide \
another one , or click \ " Cancel \" to overwrite it. " ) . arg ( ret . fileName ( ) ) ,
ret . filename ( ) ,
& isOK ) ;
if ( ! isOK )
break ;
ret . setFileName ( newURL ) ;
}
return ret ;
}
KURL Info : : repairExtension ( const KURL & url , bool checkForFileExistence /* = true */ )
{
KURL ret ( url ) ;
TQString filename = url . fileName ( ) ;
if ( filename . contains ( " . " ) & & filename [ 0 ] ! = ' . ' ) // There already is an extension
return ret ;
if ( KMessageBox : : Yes = = KMessageBox : : questionYesNo ( NULL ,
i18n ( " The given filename has no extension; do you want one to be automatically added? " ) ,
i18n ( " Missing Extension " ) ,
KStdGuiItem : : yes ( ) ,
KStdGuiItem : : no ( ) ,
" AutomaticallyAddExtension " ) )
{
ret . setFileName ( filename + " .tex " ) ;
}
return ( checkForFileExistence ? renameIfExist ( ret ) : ret ) ;
}
KURL Info : : makeValidTeXURL ( const KURL & url , bool istexfile , bool checkForFileExistence )
{
KURL newURL ( url ) ;
//add a .tex extension
if ( ! istexfile )
newURL = repairExtension ( newURL , checkForFileExistence ) ;
//remove characters TeX does not accept, make sure the newURL does not exists yet
if ( containsInvalidCharacters ( newURL ) )
newURL = repairInvalidCharacters ( newURL , checkForFileExistence ) ;
return newURL ;
}
Info : : Info ( ) : m_bIsRoot ( false ) , m_config ( kapp - > config ( ) ) , documentTypePromotionAllowed ( true )
{
updateStructLevelInfo ( ) ;
}
Info : : ~ Info ( void )
{
KILE_DEBUG ( ) < < " DELETING DOCINFO " < < m_url . path ( ) < < endl ;
}
void Info : : updateStructLevelInfo ( )
{
KILE_DEBUG ( ) < < " ===void Info::updateStructLevelInfo()=== " < < endl ;
// read config for structureview items
m_showStructureLabels = KileConfig : : svShowLabels ( ) ;
m_showStructureReferences = KileConfig : : svShowReferences ( ) ;
m_showStructureBibitems = KileConfig : : svShowBibitems ( ) ;
m_showStructureGraphics = KileConfig : : svShowGraphics ( ) ;
m_showStructureFloats = KileConfig : : svShowFloats ( ) ;
m_showStructureInputFiles = KileConfig : : svShowInputFiles ( ) ;
m_showStructureTodo = KileConfig : : svShowTodo ( ) ;
m_showSectioningLabels = KileConfig : : svShowSectioningLabels ( ) ;
m_openStructureLabels = KileConfig : : svOpenLabels ( ) ;
m_openStructureReferences = KileConfig : : svOpenReferences ( ) ;
m_openStructureBibitems = KileConfig : : svOpenBibitems ( ) ;
m_openStructureTodo = KileConfig : : svOpenTodo ( ) ;
}
void Info : : setBaseDirectory ( const KURL & url )
{
KILE_DEBUG ( ) < < " ===void Info::setBaseDirectory(const KURL& " < < url < < " )=== " < < endl ;
m_baseDirectory = url ;
}
const KURL & Info : : getBaseDirectory ( ) const
{
return m_baseDirectory ;
}
bool Info : : isTextDocument ( )
{
return false ;
}
Type Info : : getType ( )
{
return Undefined ;
}
TQString Info : : getFileFilter ( ) const
{
return TQString ( ) ;
}
bool Info : : isDocumentTypePromotionAllowed ( )
{
return documentTypePromotionAllowed ;
}
void Info : : setDocumentTypePromotionAllowed ( bool b )
{
documentTypePromotionAllowed = b ;
}
KURL Info : : url ( )
{
return m_url ;
}
void Info : : count ( const TQString line , long * stat )
{
TQChar c ;
int state = stStandard ;
bool word = false ; // we are in a word
for ( uint p = 0 ; p < line . length ( ) ; + + p )
{
c = line [ p ] ;
switch ( state )
{
case stStandard :
switch ( c )
{
case TEX_CAT0 :
state = stControlSequence ;
+ + stat [ 1 ] ;
//look ahead to avoid counting words like K\"ahler as two words
if ( ! line [ p + 1 ] . isPunct ( ) | | line [ p + 1 ] = = ' ~ ' | | line [ p + 1 ] = = ' ^ ' )
word = false ;
break ;
case TEX_CAT14 :
state = stComment ;
break ;
default :
if ( c . isLetterOrNumber ( ) )
{
//only start new word if first character is a letter (42test is still counted as a word, but 42.2 not)
if ( c . isLetter ( ) & & ! word )
{
word = true ;
+ + stat [ 3 ] ;
}
+ + stat [ 0 ] ;
}
else
{
+ + stat [ 2 ] ;
word = false ;
}
break ;
}
break ;
case stControlSequence :
if ( c . isLetter ( ) )
{
// "\begin{[a-zA-z]+}" is an environment, and you can't define a command like \begin
if ( line . mid ( p , 5 ) = = " begin " )
{
+ + stat [ 5 ] ;
state = stEnvironment ;
stat [ 1 ] + = 5 ;
p + = 4 ; // after break p++ is executed
}
else if ( line . mid ( p , 3 ) = = " end " )
{
stat [ 1 ] + = 3 ;
state = stEnvironment ;
p + = 2 ;
} // we don't count \end as new environment, this can give wrong results in selections
else
{
+ + stat [ 4 ] ;
+ + stat [ 1 ] ;
state = stCommand ;
}
}
else
{
+ + stat [ 4 ] ;
+ + stat [ 1 ] ;
state = stStandard ;
}
break ;
case stCommand :
if ( c . isLetter ( ) )
+ + stat [ 1 ] ;
else if ( c = = TEX_CAT0 )
{
+ + stat [ 1 ] ;
state = stControlSequence ;
}
else if ( c = = TEX_CAT14 )
state = stComment ;
else
{
+ + stat [ 2 ] ;
state = stStandard ;
}
break ;
case stEnvironment :
if ( c = = TEX_CAT2 ) // until we find a closing } we have an environment
{
+ + stat [ 1 ] ;
state = stStandard ;
}
else if ( c = = TEX_CAT14 )
state = stComment ;
else
+ + stat [ 1 ] ;
break ;
case stComment : // if we get a selection the line possibly contains \n and so the comment is only valid till \n and not necessarily till line.length()
if ( c = = ' \n ' )
{
+ + stat [ 2 ] ; // \n was counted as punctuation in the old implementation
state = stStandard ;
word = false ;
}
break ;
default :
kdWarning ( ) < < " Unhandled state in getStatistics " < < state < < endl ;
break ;
}
}
}
TQString Info : : lastModifiedFile ( const TQStringList * list /* = 0L */ )
{
KILE_DEBUG ( ) < < " ==TQString Info::lastModifiedFile()===== " < < endl ;
TQFileInfo fileinfo ( url ( ) . path ( ) ) ;
TQString basepath = fileinfo . dirPath ( true ) , last = fileinfo . absFilePath ( ) ;
TQDateTime time ( fileinfo . lastModified ( ) ) ;
if ( list = = 0L ) list = & m_deps ;
KILE_DEBUG ( ) < < " \t " < < fileinfo . absFilePath ( ) < < " : " < < time . toString ( ) < < endl ;
for ( uint i = 0 ; i < list - > count ( ) ; + + i )
{
fileinfo . setFile ( basepath + ' / ' + ( * list ) [ i ] ) ;
KILE_DEBUG ( ) < < " \t " < < fileinfo . absFilePath ( ) < < " : " < < fileinfo . lastModified ( ) . toString ( ) < < endl ;
if ( fileinfo . lastModified ( ) > time )
{
time = fileinfo . lastModified ( ) ;
last = fileinfo . absFilePath ( ) ;
KILE_DEBUG ( ) < < " \t \t later " < < endl ;
}
}
KILE_DEBUG ( ) < < " \t returning " < < fileinfo . absFilePath ( ) < < endl ;
return last ;
}
void Info : : updateStruct ( )
{
KILE_DEBUG ( ) < < " ==Info::updateStruct()======= " < < endl ;
m_labels . clear ( ) ;
m_bibItems . clear ( ) ;
m_deps . clear ( ) ;
m_bibliography . clear ( ) ;
m_packages . clear ( ) ;
m_newCommands . clear ( ) ;
m_bIsRoot = false ;
m_preamble = TQString ( ) ;
}
void Info : : updateBibItems ( )
{
}
void Info : : slotCompleted ( )
{
emit completed ( this ) ;
}
TextInfo : : TextInfo ( Kate : : Document * doc , Extensions * extensions , const TQString & defaultHighlightMode ) : m_doc ( 0 ) , m_defaultHighlightMode ( defaultHighlightMode )
{
setDoc ( doc ) ;
if ( m_doc )
{
KILE_DEBUG ( ) < < " TextInfo created for " < < m_doc - > docName ( ) < < endl ;
}
m_arStatistics = new long [ SIZE_STAT_ARRAY ] ;
if ( m_doc )
{
m_url = doc - > url ( ) ;
}
else
{
m_url = KURL ( ) ;
}
m_extensions = extensions ;
}
TextInfo : : ~ TextInfo ( )
{
delete [ ] m_arStatistics ;
}
const Kate : : Document * TextInfo : : getDoc ( ) const
{
return m_doc ;
}
Kate : : Document * TextInfo : : getDoc ( )
{
return m_doc ;
}
void TextInfo : : setDoc ( Kate : : Document * doc )
{
KILE_DEBUG ( ) < < " ===void TextInfo::setDoc(Kate::Document *doc)=== " < < endl ;
if ( m_doc = = doc )
return ;
detach ( ) ;
if ( doc )
{
m_doc = doc ;
m_url = doc - > url ( ) ;
connect ( m_doc , TQT_SIGNAL ( fileNameChanged ( ) ) , this , TQT_SLOT ( slotFileNameChanged ( ) ) ) ;
connect ( m_doc , TQT_SIGNAL ( completed ( ) ) , this , TQT_SLOT ( slotCompleted ( ) ) ) ;
setHighlightMode ( m_defaultHighlightMode ) ;
installEventFilters ( ) ;
}
}
void TextInfo : : detach ( )
{
if ( m_doc )
{
m_doc - > disconnect ( this ) ;
removeInstalledEventFilters ( ) ;
}
m_doc = 0L ;
}
const long * TextInfo : : getStatistics ( )
{
/* [0] = #c in words, [1] = #c in latex commands and environments,
[ 2 ] = # c whitespace , [ 3 ] = # words , [ 4 ] = # latex_commands , [ 5 ] = latex_environments */
m_arStatistics [ 0 ] = m_arStatistics [ 1 ] = m_arStatistics [ 2 ] = m_arStatistics [ 3 ] = m_arStatistics [ 4 ] = m_arStatistics [ 5 ] = 0 ;
return m_arStatistics ;
}
// FIXME for KDE 4.0, rearrange the hole docinfo layout to get rid of this hack
KURL TextInfo : : url ( )
{
KURL url ;
if ( m_doc )
url = m_doc - > url ( ) ;
else
{
TQFileInfo info ( m_url . path ( ) ) ;
if ( info . exists ( ) )
url = m_url ;
else
url = KURL ( ) ;
}
// KILE_DEBUG() << "===KURL TextInfo::url()===, url is " << url.path() << endl;
return url ;
}
Type TextInfo : : getType ( )
{
return Text ;
}
bool TextInfo : : isTextDocument ( )
{
return true ;
}
void TextInfo : : setHighlightMode ( const TQString & highlight )
{
KILE_DEBUG ( ) < < " ==Kile::setHighlightMode( " < < m_doc - > url ( ) < < " , " < < highlight < < " )================== " < < endl ;
if ( m_doc & & ! highlight . isEmpty ( ) )
{
bool found = false ;
uint c = m_doc - > hlModeCount ( ) ;
uint mode = 0 ;
for ( uint i = 0 ; i < c ; + + i )
{
if ( m_doc - > hlModeName ( i ) = = highlight ) {
found = true ;
mode = i ;
break ;
}
}
if ( found )
{
m_doc - > setHlMode ( mode ) ;
}
}
}
void TextInfo : : setDefaultHightlightMode ( const TQString & string )
{
m_defaultHighlightMode = string ;
}
// match a { with the corresponding }
// pos is the position of the {
TQString TextInfo : : matchBracket ( TQChar obracket , uint & l , uint & pos )
{
TQChar cbracket ;
if ( obracket = = ' { ' ) cbracket = ' } ' ;
if ( obracket = = ' [ ' ) cbracket = ' ] ' ;
if ( obracket = = ' ( ' ) cbracket = ' ) ' ;
TQString line , grab = " " ;
int count = 0 , len ;
+ + pos ;
TodoResult todo ;
while ( l < = m_doc - > numLines ( ) )
{
line = getTextline ( l , todo ) ;
len = line . length ( ) ;
for ( int i = pos ; i < len ; + + i )
{
if ( line [ i ] = = ' \\ ' & & ( line [ i + 1 ] = = obracket | | line [ i + 1 ] = = cbracket ) ) + + i ;
else if ( line [ i ] = = obracket ) + + count ;
else if ( line [ i ] = = cbracket )
{
- - count ;
if ( count < 0 )
{
pos = i ;
return grab ;
}
}
grab + = line [ i ] ;
}
+ + l ;
pos = 0 ;
}
return TQString ( ) ;
}
TQString TextInfo : : getTextline ( uint line , TodoResult & todo )
{
static TQRegExp reComments ( " [^ \\ \\ ](%.*$) " ) ;
todo . type = - 1 ;
TQString s = m_doc - > textLine ( line ) ;
if ( ! s . isEmpty ( ) )
{
// remove comment lines
if ( s [ 0 ] = = ' % ' )
{
searchTodoComment ( s , 0 , todo ) ;
s = TQString ( ) ;
}
else
{
//remove escaped \ characters
s . replace ( " \\ \\ " , " " ) ;
//remove comments
int pos = s . find ( reComments ) ;
if ( pos ! = - 1 )
{
searchTodoComment ( s , pos , todo ) ;
s = s . left ( reComments . pos ( 1 ) ) ;
}
}
}
return s ;
}
void TextInfo : : searchTodoComment ( const TQString & s , uint startpos , TodoResult & todo )
{
static TQRegExp reTodoComment ( " \\ b(TODO|FIXME) \ \ b ( : | \ \ s ) ? \ \ s * ( . * ) " ) ;
if ( s . find ( reTodoComment , startpos ) ! = - 1 )
{
todo . type = ( reTodoComment . cap ( 1 ) = = " TODO " ) ? KileStruct : : ToDo : KileStruct : : FixMe ;
todo . colTag = reTodoComment . pos ( 1 ) ;
todo . colComment = reTodoComment . pos ( 3 ) ;
todo . comment = reTodoComment . cap ( 3 ) . stripWhiteSpace ( ) ;
}
}
KTextEditor : : View * TextInfo : : createView ( TQWidget * parent , const char * name )
{
if ( ! m_doc )
{
return NULL ;
}
KTextEditor : : View * view = m_doc - > createView ( parent , name ) ;
installEventFilters ( view ) ;
return view ;
}
void TextInfo : : slotFileNameChanged ( )
{
emit urlChanged ( this , url ( ) ) ;
}
void TextInfo : : installEventFilters ( KTextEditor : : View * /* view */ )
{
/* do nothing */
}
void TextInfo : : removeInstalledEventFilters ( KTextEditor : : View * /* view */ )
{
/* do nothing */
}
void TextInfo : : installEventFilters ( )
{
if ( ! m_doc )
{
return ;
}
TQPtrList < KTextEditor : : View > views = m_doc - > views ( ) ;
KTextEditor : : View * view ;
for ( view = views . first ( ) ; view ; view = views . next ( ) )
{
installEventFilters ( view ) ;
}
}
void TextInfo : : removeInstalledEventFilters ( )
{
if ( ! m_doc )
{
return ;
}
TQPtrList < KTextEditor : : View > views = m_doc - > views ( ) ;
KTextEditor : : View * view ;
for ( view = views . first ( ) ; view ; view = views . next ( ) )
{
removeInstalledEventFilters ( view ) ;
}
}
LaTeXInfo : : LaTeXInfo ( Kate : : Document * doc , Extensions * extensions , LatexCommands * commands , const TQObject * eventFilter ) : TextInfo ( doc , extensions , " LaTeX " ) , m_commands ( commands ) , m_eventFilter ( eventFilter )
{
documentTypePromotionAllowed = false ;
updateStructLevelInfo ( ) ;
}
LaTeXInfo : : ~ LaTeXInfo ( )
{
}
const long * LaTeXInfo : : getStatistics ( )
{
/* [0] = #c in words, [1] = #c in latex commands and environments,
[ 2 ] = # c whitespace , [ 3 ] = # words , [ 4 ] = # latex_commands , [ 5 ] = latex_environments */
m_arStatistics [ 0 ] = m_arStatistics [ 1 ] = m_arStatistics [ 2 ] = m_arStatistics [ 3 ] = m_arStatistics [ 4 ] = m_arStatistics [ 5 ] = 0 ;
TQString line ;
if ( m_doc & & m_doc - > hasSelection ( ) )
{
line = m_doc - > selection ( ) ;
KILE_DEBUG ( ) < < " getStat : line : " < < line < < endl ;
count ( line , m_arStatistics ) ;
}
else if ( m_doc )
for ( uint l = 0 ; l < m_doc - > numLines ( ) ; + + l )
{
line = m_doc - > textLine ( l ) ;
KILE_DEBUG ( ) < < " getStat : line : " < < line < < endl ;
count ( line , m_arStatistics ) ;
}
return m_arStatistics ;
}
Type LaTeXInfo : : getType ( )
{
return LaTeX ;
}
TQString LaTeXInfo : : getFileFilter ( ) const
{
return m_extensions - > latexDocumentFileFilter ( ) + ' \n ' + m_extensions - > latexPackageFileFilter ( ) ;
}
void LaTeXInfo : : updateStructLevelInfo ( ) {
KILE_DEBUG ( ) < < " ===void LaTeXInfo::updateStructLevelInfo()=== " < < endl ;
// read config stuff
Info : : updateStructLevelInfo ( ) ;
// clear all entries
m_dictStructLevel . clear ( ) ;
//TODO: make sectioning and bibliography configurable
// sectioning
m_dictStructLevel [ " \\ part " ] = KileStructData ( 1 , KileStruct : : Sect , " part " ) ;
m_dictStructLevel [ " \\ chapter " ] = KileStructData ( 2 , KileStruct : : Sect , " chapter " ) ;
m_dictStructLevel [ " \\ section " ] = KileStructData ( 3 , KileStruct : : Sect , " section " ) ;
m_dictStructLevel [ " \\ subsection " ] = KileStructData ( 4 , KileStruct : : Sect , " subsection " ) ;
m_dictStructLevel [ " \\ subsubsection " ] = KileStructData ( 5 , KileStruct : : Sect , " subsubsection " ) ;
m_dictStructLevel [ " \\ paragraph " ] = KileStructData ( 6 , KileStruct : : Sect , " subsubsection " ) ;
m_dictStructLevel [ " \\ subparagraph " ] = KileStructData ( 7 , KileStruct : : Sect , " subsubsection " ) ;
m_dictStructLevel [ " \\ bibliography " ] = KileStructData ( 0 , KileStruct : : Bibliography , " viewbib " ) ;
// hidden commands
m_dictStructLevel [ " \\ usepackage " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : Package ) ;
m_dictStructLevel [ " \\ newcommand " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : NewCommand ) ;
m_dictStructLevel [ " \\ newlength " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : NewCommand ) ;
m_dictStructLevel [ " \\ newenvironment " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : NewEnvironment ) ;
m_dictStructLevel [ " \\ addunit " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : NewCommand ) ; // hack to get support for the fancyunits package until we can configure the commands in the gui (tbraun)
m_dictStructLevel [ " \\ DeclareMathOperator " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : NewCommand ) ; // amsmath package
m_dictStructLevel [ " \\ caption " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : Caption ) ;
// bibitems
if ( m_showStructureBibitems )
{
m_dictStructLevel [ " \\ bibitem " ] = KileStructData ( KileStruct : : NotSpecified , KileStruct : : BibItem , TQString ( ) , " bibs " ) ;
}
// graphics
if ( m_showStructureGraphics )
{
m_dictStructLevel [ " \\ includegraphics " ] = KileStructData ( KileStruct : : Object , KileStruct : : Graphics , " graphics " ) ;
}
// float environments
if ( m_showStructureFloats )
{
m_dictStructLevel [ " \\ begin " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeginEnv ) ;
m_dictStructLevel [ " \\ end " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : EndEnv ) ;
// some entries, which could never be found (but they are set manually)
m_dictStructLevel [ " \\ begin{figure} " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeginFloat , " frame_image " ) ;
m_dictStructLevel [ " \\ begin{figure*} " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeginFloat , " frame_image " ) ;
m_dictStructLevel [ " \\ begin{table} " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeginFloat , " frame_spreadsheet " ) ;
m_dictStructLevel [ " \\ end{float} " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : EndFloat ) ;
}
// preliminary minimal beamer support
m_dictStructLevel [ " \\ frame " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeamerFrame , " beamerframe " ) ;
m_dictStructLevel [ " \\ frametitle " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : BeamerFrametitle ) ;
m_dictStructLevel [ " \\ begin{frame} " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeamerBeginFrame , " beamerframe " ) ;
m_dictStructLevel [ " \\ end{frame} " ] = KileStructData ( KileStruct : : Hidden , KileStruct : : BeamerEndFrame ) ;
m_dictStructLevel [ " \\ begin{block} " ] = KileStructData ( KileStruct : : Object , KileStruct : : BeamerBeginBlock , " beamerblock " ) ;
// add user defined commands
TQStringList list ;
TQStringList : : ConstIterator it ;
// labels, we also gather them
m_commands - > commandList ( list , KileDocument : : CmdAttrLabel , false ) ;
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it )
m_dictStructLevel [ * it ] = KileStructData ( KileStruct : : NotSpecified , KileStruct : : Label , TQString ( ) , " labels " ) ;
// input files
if ( m_showStructureInputFiles )
{
m_commands - > commandList ( list , KileDocument : : CmdAttrIncludes , false ) ;
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it )
m_dictStructLevel [ * it ] = KileStructData ( KileStruct : : File , KileStruct : : Input , " include " ) ;
}
// references
if ( m_showStructureReferences )
{
m_commands - > commandList ( list , KileDocument : : CmdAttrReference , false ) ;
for ( it = list . begin ( ) ; it ! = list . end ( ) ; + + it )
m_dictStructLevel [ * it ] = KileStructData ( KileStruct : : Hidden , KileStruct : : Reference ) ;
}
}
void LaTeXInfo : : installEventFilters ( KTextEditor : : View * view )
{
view - > focusProxy ( ) - > installEventFilter ( const_cast < TQObject * > ( m_eventFilter ) ) ;
}
void LaTeXInfo : : removeInstalledEventFilters ( KTextEditor : : View * view )
{
view - > focusProxy ( ) - > removeEventFilter ( const_cast < TQObject * > ( m_eventFilter ) ) ;
}
BracketResult LaTeXInfo : : matchBracket ( uint & l , uint & pos )
{
BracketResult result ;
TodoResult todo ;
if ( m_doc - > textLine ( l ) [ pos ] = = ' [ ' )
{
result . option = TextInfo : : matchBracket ( ' [ ' , l , pos ) ;
int p = 0 ;
while ( l < m_doc - > numLines ( ) )
{
if ( ( p = getTextline ( l , todo ) . find ( ' { ' , pos ) ) ! = - 1 )
{
pos = p ;
break ;
}
else
{
pos = 0 ;
+ + l ;
}
}
}
if ( m_doc - > textLine ( l ) [ pos ] = = ' { ' )
{
result . line = l ;
result . col = pos ;
result . value = TextInfo : : matchBracket ( ' { ' , l , pos ) ;
}
return result ;
}
//FIXME refactor, clean this mess up
void LaTeXInfo : : updateStruct ( )
{
KILE_DEBUG ( ) < < " ==void TeXInfo::updateStruct: ( " < < url ( ) < < " )========= " < < endl ;
if ( getDoc ( ) = = 0L )
return ;
Info : : updateStruct ( ) ;
TQMapConstIterator < TQString , KileStructData > it ;
static TQRegExp reCommand ( " ( \\ \\ [a-zA-Z]+) \ \ s * \ \ * ? \ \ s * ( \ \ { | \ \ [ ) " );
static TQRegExp reRoot ( " \\ \\ documentclass| \\ \\ documentstyle " ) ;
static TQRegExp reBD ( " \\ \\ begin \\ s* \\ { \\ s*document \\ s* \\ } " ) ;
static TQRegExp reReNewCommand ( " \\ \\ renewcommand.*$ " ) ;
static TQRegExp reNumOfParams ( " \\ s* \\ [([1-9]+) \ \ ] " ) ;
static TQRegExp reNumOfOptParams ( " \\ s* \\ [([1-9]+) \ \ ] \ \ s * \ \ [ ( [ ^ \ \ { ] * ) \ \ ] " ); // the quantifier * isn't used by mistake, because also emtpy optional brackets are correct.
int teller = 0 , tagStart , bd = 0 ;
uint tagEnd , tagLine = 0 , tagCol = 0 ;
uint tagStartLine = 0 , tagStartCol = 0 ;
BracketResult result ;
TQString m , s , shorthand ;
bool foundBD = false ; // found \begin { document }
bool fire = true ; //whether or not we should emit a foundItem signal
bool fireSuspended ; // found an item, but it should not be fired (this time)
TodoResult todo ;
for ( uint i = 0 ; i < m_doc - > numLines ( ) ; + + i )
{
if ( teller > 100 )
{
teller = 0 ;
kapp - > processEvents ( ) ;
}
else
+ + teller ;
tagStart = tagEnd = 0 ;
fire = true ;
s = getTextline ( i , todo ) ;
if ( todo . type ! = - 1 & & m_showStructureTodo )
{
TQString folder = ( todo . type = = KileStruct : : ToDo ) ? " todo " : " fixme " ;
emit ( foundItem ( todo . comment , i + 1 , todo . colComment , todo . type , KileStruct : : Object , i + 1 , todo . colTag , TQString ( ) , folder ) ) ;
}
if ( s . isEmpty ( ) )
continue ;
//ignore renewcommands
s . replace ( reReNewCommand , " " ) ;
//find all commands in this line
while ( tagStart ! = - 1 )
{
if ( ( ! foundBD ) & & ( ( bd = s . find ( reBD , tagEnd ) ) ! = - 1 ) )
{
KILE_DEBUG ( ) < < " \t found \\ begin{document} " < < endl ;
foundBD = true ;
if ( bd = = 0 ) m_preamble = m_doc - > text ( 0 , 0 , i - 1 , m_doc - > textLine ( i - 1 ) . length ( ) ) ;
else m_preamble = m_doc - > text ( 0 , 0 , i , bd ) ;
}
if ( ( ! foundBD ) & & ( s . find ( reRoot , tagEnd ) ! = - 1 ) )
{
KILE_DEBUG ( ) < < " \t setting m_bIsRoot to true " < < endl ;
tagEnd + = reRoot . cap ( 0 ) . length ( ) ;
m_bIsRoot = true ;
}
tagStart = reCommand . search ( s , tagEnd ) ;
m = TQString ( ) ;
shorthand = TQString ( ) ;
if ( tagStart ! = - 1 )
{
tagEnd = tagStart + reCommand . cap ( 0 ) . length ( ) - 1 ;
//look up the command in the dictionary
it = m_dictStructLevel . find ( reCommand . cap ( 1 ) ) ;
//if it is was a structure element, find the title (or label)
if ( it ! = m_dictStructLevel . end ( ) )
{
tagLine = i + 1 ;
tagCol = tagEnd + 1 ;
tagStartLine = tagLine ;
tagStartCol = tagStart + 1 ;
if ( reCommand . cap ( 1 ) ! = " \\ frame " )
{
result = matchBracket ( i , static_cast < uint & > ( tagEnd ) ) ;
m = result . value . stripWhiteSpace ( ) ;
shorthand = result . option . stripWhiteSpace ( ) ;
if ( i > = tagLine ) //matching brackets spanned multiple lines
s = m_doc - > textLine ( i ) ;
if ( result . line > 0 | | result . col > 0 )
{
tagLine = result . line + 1 ;
tagCol = result . col + 1 ;
}
//KILE_DEBUG() << "\tgrabbed: " << reCommand.cap(1) << "[" << shorthand << "]{" << m << "}" << endl;
}
else
{
m = i18n ( " Frame " ) ;
}
}
//title (or label) found, add the element to the listview
if ( ! m . isNull ( ) )
{
// no problems so far ...
fireSuspended = false ;
// remove trailing ./
if ( ( * it ) . type & ( KileStruct : : Input | KileStruct : : Graphics ) )
{
if ( m . left ( 2 ) = = " ./ " )
m = m . mid ( 2 , m . length ( ) - 2 ) ;
}
// update parameter for environments, because only
// floating environments and beamer frames are passed
if ( ( * it ) . type = = KileStruct : : BeginEnv )
{
if ( m = = " figure " | | m = = " figure* " | | m = = " table " )
{
it = m_dictStructLevel . find ( " \\ begin{ " + m + ' } ' ) ;
}
else if ( m = = " frame " )
{
it = m_dictStructLevel . find ( " \\ begin{frame} " ) ;
m = i18n ( " Frame " ) ;
}
else if ( m = = " block " | | m = = " exampleblock " | | m = = " alertblock " )
{
const TQString untitledBlockDisplayName = i18n ( " Untitled Block " ) ;
it = m_dictStructLevel . find ( " \\ begin{block} " ) ;
if ( s . at ( tagEnd + 1 ) = = ' { ' )
{
tagEnd + + ;
result = matchBracket ( i , static_cast < uint & > ( tagEnd ) ) ;
m = result . value . stripWhiteSpace ( ) ;
if ( m . isEmpty ( ) ) {
m = untitledBlockDisplayName ;
}
}
else
m = untitledBlockDisplayName ;
}
else
fireSuspended = true ; // only floats and beamer frames, no other environments
}
// tell structure view that a floating environment or a beamer frame must be closed
else if ( ( * it ) . type = = KileStruct : : EndEnv )
{
if ( m = = " figure " | | m = = " figure* " | | m = = " table " )
{
it = m_dictStructLevel . find ( " \\ end{float} " ) ;
}
else if ( m = = " frame " )
{
it = m_dictStructLevel . find ( " \\ end{frame} " ) ;
}
else
fireSuspended = true ; // only floats, no other environments
}
// sectioning commands
else if ( ( * it ) . type = = KileStruct : : Sect )
{
if ( ! shorthand . isNull ( ) )
m = shorthand ;
}
// update the label list
else if ( ( * it ) . type = = KileStruct : : Label )
{
m_labels . append ( m ) ;
// label entry as child of sectioning
if ( m_showSectioningLabels )
{
emit ( foundItem ( m , tagLine , tagCol , KileStruct : : Label , KileStruct : : Object , tagStartLine , tagStartCol , " label " , " root " ) ) ;
fireSuspended = true ;
}
}
// update the references list
else if ( ( * it ) . type = = KileStruct : : Reference )
{
// m_references.append(m);
//fireSuspended = true; // don't emit references
}
// update the dependencies
else if ( ( * it ) . type = = KileStruct : : Input )
{
// \input- or \include-commands can be used without extension. So we check
// if an extension exists. If not the default extension is added
// ( LaTeX reference says that this is '.tex'). This assures that
// all files, which are listed in the structure view, have an extension.
TQString ext = TQFileInfo ( m ) . extension ( ) ;
if ( ext . isEmpty ( ) )
m + = m_extensions - > latexDocumentDefault ( ) ;
m_deps . append ( m ) ;
}
// update the referenced Bib files
else if ( ( * it ) . type = = KileStruct : : Bibliography )
{
KILE_DEBUG ( ) < < " ===TeXInfo::updateStruct()===appending Bibiliograph file(s) " < < m < < endl ;
TQStringList bibs = TQStringList : : split ( " , " , m ) ;
TQString biblio ;
// assure that all files have an extension
TQString bibext = m_extensions - > bibtexDefault ( ) ;
int bibextlen = bibext . length ( ) ;
uint cumlen = 0 ;
int nextbib = 0 ; // length to add to jump to the next bibliography
for ( uint b = 0 ; b < bibs . count ( ) ; + + b )
{
nextbib = 0 ;
biblio = bibs [ b ] ;
m_bibliography . append ( biblio ) ;
if ( biblio . left ( 2 ) = = " ./ " )
{ nextbib + = 2 ;
biblio = biblio . mid ( 2 , biblio . length ( ) - 2 ) ;
}
if ( biblio . right ( bibextlen ) ! = bibext )
{
biblio + = bibext ;
nextbib - = bibextlen ;
}
m_deps . append ( biblio ) ;
emit ( foundItem ( biblio , tagLine , tagCol + cumlen , ( * it ) . type , ( * it ) . level , tagStartLine , tagStartCol , ( * it ) . pix , ( * it ) . folder ) ) ;
cumlen + = biblio . length ( ) + 1 + nextbib ;
}
fire = false ;
}
// update the bibitem list
else if ( ( * it ) . type = = KileStruct : : BibItem )
{
//KILE_DEBUG() << "\tappending bibitem " << m << endl;
m_bibItems . append ( m ) ;
}
// update the package list
else if ( ( * it ) . type = = KileStruct : : Package )
{
TQStringList pckgs = TQStringList : : split ( " , " , m ) ;
uint cumlen = 0 ;
for ( uint p = 0 ; p < pckgs . count ( ) ; + + p )
{
TQString package = pckgs [ p ] . stripWhiteSpace ( ) ;
if ( ! package . isEmpty ( ) ) {
m_packages . append ( package ) ;
// hidden, so emit is useless
// emit( foundItem(package, tagLine, tagCol+cumlen, (*it).type, (*it).level, tagStartLine, tagStartCol, (*it).pix, (*it).folder) );
cumlen + = package . length ( ) + 1 ;
}
}
fire = false ;
}
// newcommand found, add it to the newCommands list
else if ( ( * it ) . type & ( KileStruct : : NewCommand | KileStruct : : NewEnvironment ) )
{
TQString optArg , mandArgs ;
//find how many parameters this command takes
if ( s . find ( reNumOfParams , tagEnd + 1 ) ! = - 1 )
{
bool ok ;
int noo = reNumOfParams . cap ( 1 ) . toInt ( & ok ) ;
if ( ok )
{
if ( s . find ( reNumOfOptParams , tagEnd + 1 ) ! = - 1 )
{
KILE_DEBUG ( ) < < " Opt param is " < < reNumOfOptParams . cap ( 2 ) < < " %EOL " < < endl ;
noo - - ; // if we have an opt argument, we have one mandatory argument less, and noo=0 can't occur because then latex complains (and we don't macht them with reNumOfParams either)
optArg = ' [ ' + reNumOfOptParams . cap ( 2 ) + ' ] ' ;
}
for ( int noo_index = 0 ; noo_index < noo ; + + noo_index )
{
mandArgs + = ' { ' + s_bullet + ' } ' ;
}
}
if ( ! optArg . isEmpty ( ) )
{
if ( ( * it ) . type = = KileStruct : : NewEnvironment )
{
m_newCommands . append ( TQString ( " \\ begin{%1}%2%3 " ) . arg ( m ) . arg ( optArg ) . arg ( mandArgs ) ) ;
}
else
m_newCommands . append ( m + optArg + mandArgs ) ;
}
}
if ( ( * it ) . type = = KileStruct : : NewEnvironment )
{
m_newCommands . append ( TQString ( " \\ begin{%1}%3 " ) . arg ( m ) . arg ( mandArgs ) ) ;
m_newCommands . append ( TQString ( " \\ end{%1} " ) . arg ( m ) ) ;
}
else
m_newCommands . append ( m + mandArgs ) ;
//FIXME set tagEnd to the end of the command definition
break ;
}
// and some other commands, which don't need special actions:
// \caption, ...
// KILE_DEBUG() << "\t\temitting: " << m << endl;
if ( fire & & ! fireSuspended )
emit ( foundItem ( m , tagLine , tagCol , ( * it ) . type , ( * it ) . level , tagStartLine , tagStartCol , ( * it ) . pix , ( * it ) . folder ) ) ;
} //if m
} // if tagStart
} // while tagStart
} //for
checkChangedDeps ( ) ;
emit ( doneUpdating ( ) ) ;
emit ( isrootChanged ( isLaTeXRoot ( ) ) ) ;
}
void LaTeXInfo : : checkChangedDeps ( )
{
if ( m_depsPrev ! = m_deps )
{
KILE_DEBUG ( ) < < " ===void LaTeXInfo::checkChangedDeps()===, deps have changed " < < endl ;
emit ( depChanged ( ) ) ;
m_depsPrev = m_deps ;
}
}
BibInfo : : BibInfo ( Kate : : Document * doc , Extensions * extensions , LatexCommands * /* commands */ ) : TextInfo ( doc , extensions , " BibTeX " )
{
documentTypePromotionAllowed = false ;
}
BibInfo : : ~ BibInfo ( )
{
}
bool BibInfo : : isLaTeXRoot ( )
{
return false ;
}
void BibInfo : : updateStruct ( )
{
if ( getDoc ( ) = = 0L ) return ;
Info : : updateStruct ( ) ;
KILE_DEBUG ( ) < < " ==void BibInfo::updateStruct()======== " < < endl ;
static TQRegExp reItem ( " ^( \\ s*) @ ( [ a - zA - Z ] + ) " ) ;
static TQRegExp reSpecial ( " string|preamble|comment " ) ;
TQString s , key ;
int col = 0 , startcol , startline = 0 ;
for ( uint i = 0 ; i < m_doc - > numLines ( ) ; + + i )
{
s = m_doc - > textLine ( i ) ;
if ( ( s . find ( reItem ) ! = - 1 ) & & ! reSpecial . exactMatch ( reItem . cap ( 2 ) . lower ( ) ) )
{
KILE_DEBUG ( ) < < " found: " < < reItem . cap ( 2 ) < < endl ;
//start looking for key
key = " " ;
bool keystarted = false ;
int state = 0 ;
startcol = reItem . cap ( 1 ) . length ( ) ;
col = startcol + reItem . cap ( 2 ) . length ( ) ;
while ( col < static_cast < int > ( s . length ( ) ) )
{
+ + col ;
if ( col = = static_cast < int > ( s . length ( ) ) )
{
do
{
+ + i ;
s = m_doc - > textLine ( i ) ;
} while ( ( s . length ( ) = = 0 ) & & ( i < m_doc - > numLines ( ) ) ) ;
if ( i = = m_doc - > numLines ( ) ) break ;
col = 0 ;
}
if ( state = = 0 )
{
if ( s [ col ] = = ' { ' ) state = 1 ;
else if ( ! s [ col ] . isSpace ( ) ) break ;
}
else if ( state = = 1 )
{
if ( s [ col ] = = ' , ' )
{
key = key . stripWhiteSpace ( ) ;
KILE_DEBUG ( ) < < " found: " < < key < < endl ;
m_bibItems . append ( key ) ;
emit ( foundItem ( key , startline + 1 , startcol , KileStruct : : BibItem , 0 , startline + 1 , startcol , " viewbib " , reItem . cap ( 2 ) . lower ( ) ) ) ;
break ;
}
else
{
key + = s [ col ] ;
if ( ! keystarted ) { startcol = col ; startline = i ; }
keystarted = true ;
}
}
}
}
}
emit ( doneUpdating ( ) ) ;
}
Type BibInfo : : getType ( )
{
return BibTeX ;
}
TQString BibInfo : : getFileFilter ( ) const
{
return m_extensions - > bibtexFileFilter ( ) ;
}
ScriptInfo : : ScriptInfo ( Kate : : Document * doc , Extensions * extensions ) : TextInfo ( doc , extensions , " JavaScript " )
{
documentTypePromotionAllowed = false ;
}
ScriptInfo : : ~ ScriptInfo ( )
{
}
bool ScriptInfo : : isLaTeXRoot ( )
{
return false ;
}
Type ScriptInfo : : getType ( )
{
return Script ;
}
TQString ScriptInfo : : getFileFilter ( ) const
{
return m_extensions - > scriptFileFilter ( ) ;
}
}
# include "kiledocumentinfo.moc"