You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kile/src/kile/kiledocumentinfo.cpp

1319 lines
34 KiB

/*********************************************************************************************
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 <tdelocale.h>
#include <tdeapplication.h>
#include "kiledebug.h"
#include <kiconloader.h>
#include <tdemessagebox.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\tlater" << endl;
}
}
KILE_DEBUG() << "\treturning " << 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;
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;
}
// 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()
{
}
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() << "\tfound \\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() << "\tsetting 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"