859
859
void LatexParser::resolveCommandOptions(const QString &line, int column, QStringList &values, QList<int> *starts){
860
const QString BracketsOpen("[{");
861
const QString BracketsClose("]}");
860
const QString BracketsOpen("[{(");
861
const QString BracketsClose("]})");
862
862
int start=column;
937
937
int LatexParser::findContext(QString &line,int &column) const{
938
/* return a number for a context
941
* 2 option \command[option]{arg}
942
* 3 argument \command{arg}
943
* 4 argument 2 \command{arg}{arg2}
938
946
if(line.isEmpty())
940
QString eow="\\[]{} $";
948
QString eow="\\[]{}$";
942
950
if(i>=line.length())
996
1005
if(closeBrackets.contains(ch)){
1008
++ret; //going through another braces pair, [] is not checked
1001
1012
if(n==0 && eow.contains(ch)){
1003
1014
//TODO: check if not \\ (newline) was found
1004
line=line.mid(i,stop-i+1);
1015
line=line.mid(i,stop-i+1).simplified();
1007
1018
}else{ // this is a overly strict interpretation of command syntax
1032
1043
value.remove(0,1);
1033
1044
if(value.endsWith('}')||value.endsWith(']'))
1036
1047
switch (temp) {
1037
1048
case 0: return Unknown;
1038
1049
case 1: return Command;
1051
if(specialTreatmentCommands.contains(command)){
1052
QSet<QPair<QString,int> > helper=specialTreatmentCommands.value(command);
1053
QPair<QString,int> elem;
1054
foreach(elem,helper){
1061
QStringList keys=possibleCommands.keys();
1064
QStringList checkOptions;
1065
checkOptions << "key%1"+command << "key%1"+command+"#c";
1067
foreach(elem,checkOptions){
1068
if(keys.contains(elem)){
1070
command=elem.mid(4);
1076
// check that cursor is within keyval
1078
for(int i=col;col>0;col--){
1079
if(line.at(i-1).isLetter())
1081
if(line.at(i-1)=='{' || line.at(i-1)==',')
1040
1092
if (environmentCommands.contains(command))
1041
1093
return Environment;
1042
1094
else if (possibleCommands["%label"].contains(command))
1052
1104
else if (possibleCommands["%graphics"].contains(command))
1053
1105
return Graphics;
1054
1106
else return Option;
1056
1108
// find possible commands for keyval completion
1059
foreach(elem,possibleCommands.keys()){
1060
if(elem.startsWith("key%") && (elem.mid(4)==command || elem.mid(4)==command+"#c"))
1110
if(specialTreatmentCommands.contains(command)){
1111
QSet<QPair<QString,int> > helper=specialTreatmentCommands.value(command);
1112
QPair<QString,int> elem;
1113
foreach(elem,helper){
1064
1118
QStringList keys=possibleCommands.keys();
1066
1120
if(!vals.isEmpty()){
1282
QString removePathDelim(const QString &s) {
1283
// we use the explicit chars intentionally and not QDir::separator()
1284
// because it shall also work for / on windows (many paths are internally
1285
// represented with / as delimiter
1286
if (s.endsWith('/') || s.endsWith('\\')) {
1287
return s.left(s.length()-1);
1229
1292
QTextCodec* QTextCodecForTeXShopName(const QByteArray& enc){
1230
1293
//copied and modified from texworks
1526
1589
environmentAliases.insert(key,value);
1592
specialTreatmentCommands.unite(elem.specialTreatmentCommands);
1593
specialDefCommands.unite(elem.specialDefCommands);
1531
1596
void LatexParser::clear(){
1703
1768
this->wordStartIndex = 0;
1706
LatexPackage loadCwlFile(const QString fileName,LatexCompleterConfig *config) {
1771
LatexPackage loadCwlFile(const QString fileName,LatexCompleterConfig *config,QStringList conditions) {
1707
1772
QStringList words;
1708
1773
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1709
1774
LatexPackage package;
1714
1779
QString fn=findResourceFile("completion/"+fileName,false,addPaths);
1716
1781
QFile tagsfile(fn);
1782
bool skipSection=false;
1717
1783
if (!fn.isEmpty() && tagsfile.open(QFile::ReadOnly)) {
1719
1785
QTextStream stream(&tagsfile);
1720
1786
stream.setCodec("UTF-8");
1721
1787
QRegExp rxCom("^(\\\\\\w+\\*?)(\\[.+\\])*\\{(.*)\\}");
1722
1788
QRegExp rxCom2("^(\\\\\\w+\\*?)\\[(.+)\\]");
1789
QRegExp rxCom3("^(\\\\\\w+\\*?)");
1723
1790
rxCom.setMinimal(true);
1724
1791
QStringList keywords;
1725
1792
keywords << "text" << "title";
1793
QStringList specialTreatment;
1794
specialTreatment << "color";
1726
1795
QString keyvals;
1727
1796
while (!stream.atEnd()) {
1728
1797
line = stream.readLine().trimmed();
1798
if(line.startsWith("#endif")){
1799
// end of conditional section
1803
if(line.startsWith("#ifOption:")){
1804
QString condition=line.mid(10);
1805
skipSection=!conditions.contains(condition);
1808
if(skipSection) // skip conditional sections (if condition is not met)
1729
1812
if(line.startsWith("#include:")){
1730
1813
//include additional cwl file
1731
1814
QString fn=line.mid(9);
1769
1854
valid=valid.mid(1);
1857
// second time split for specialDef
1858
int sep=valid.indexOf('#');
1860
definition=valid.mid(sep+1);
1861
valid=valid.left(sep);
1772
1864
if(valid.startsWith("/")){
1773
1865
env=valid.mid(1).split(',');
1789
1881
if(keywords.contains(rxCom.cap(3))){
1790
1882
package.optionCommands << rxCom.cap(1);
1884
if(specialTreatment.contains(rxCom.cap(3))){
1885
package.specialTreatmentCommands[rxCom.cap(1)].insert(qMakePair(rxCom.cap(3),1));
1792
1887
rxCom2.indexIn(line); // for commands which don't have a braces part e.g. \item[text]
1888
int res3=rxCom3.indexIn(line); // for commands which don't have a options either e.g. \node (asas)
1793
1889
if(keywords.contains(rxCom2.cap(2))){
1794
1890
package.optionCommands << rxCom2.cap(1);
1818
1914
valid.remove('r');
1916
if(valid.contains('s')){ // special def
1918
package.specialDefCommands.insert(rxCom.cap(1),definition);
1921
package.specialDefCommands.insert(rxCom3.cap(1),definition);
1923
if(definition.startsWith('%')){
1924
config->specialCompletionKeys.insert(definition);
1926
if(definition.length()>2){
1927
QString helper=definition.mid(1,definition.length()-2);
1928
if(helper.startsWith('%'))
1929
config->specialCompletionKeys.insert(helper);
1820
1934
if(valid.contains('c')){ // cite command
1822
1936
package.possibleCommands["%cite"] << rxCom.cap(1);
1892
2006
valid.remove('D');
2008
if(valid.contains('B')){ // color
2009
package.possibleCommands["%color"] << line;
2010
hideFromCompletion=true;
1894
2012
// normal commands for syntax checking
1895
2013
// will be extended to distinguish between normal and math commands
1896
if(valid.isEmpty() || valid.contains('n')){
1898
if(rxCom.cap(1)=="\\begin" || rxCom.cap(1)=="\\end"){
1899
package.possibleCommands["normal"] << rxCom.cap(1)+"{"+rxCom.cap(3)+"}";
1901
package.possibleCommands["normal"] << rxCom.cap(1);
1904
package.possibleCommands["normal"] << line.simplified();
2014
if(valid.isEmpty() || valid.contains('n')){
2016
if(rxCom.cap(1)=="\\begin" || rxCom.cap(1)=="\\end"){
2017
package.possibleCommands["normal"] << rxCom.cap(1)+"{"+rxCom.cap(3)+"}";
2019
package.possibleCommands["normal"] << rxCom.cap(1);
2022
package.possibleCommands["normal"] << line.simplified();
1907
2025
if(valid.contains('m')){ // math commands
1909
2027
if(rxCom.cap(1)=="\\begin" || rxCom.cap(1)=="\\end"){
2028
2147
return package;
2031
LatexPackage::LatexPackage(){
2150
LatexPackage::LatexPackage() : notFound(false) {
2032
2151
completionWords.clear();
2033
2152
packageName.clear();
2155
QString LatexPackage::makeKey(const QString &cwlFilename, const QString &options) {
2156
return QString("%1#%2").arg(options).arg(cwlFilename);
2159
QString LatexPackage::keyToCwlFilename(const QString &key) {
2160
int i = key.indexOf('#');
2161
if (i<0) return key;
2162
else return key.mid(i+1);
2165
QString LatexPackage::keyToPackageName(const QString &key) {
2166
// Workaround since there is currently no reliable way to determine the packageName from LatexPackage directly (the attribute with the same name contains the key and sometimes nothing).
2167
QString name = LatexPackage::keyToCwlFilename(key);
2168
if (name.endsWith(".cwl"))
2169
name.remove(name.length()-4, 4);
2170
if (name.startsWith("class-"))
2175
QString LatexPackage::keyToOptions(const QString &key) {
2176
int i = key.indexOf('#');
2177
if (i<0) return QString();
2178
else return key.left(i);
2036
2181
void LatexPackage::unite(LatexPackage &add){
2037
2182
completionWords.append(add.completionWords);
2038
2183
optionCommands.unite(add.optionCommands);
2039
2184
environmentAliases.unite(add.environmentAliases);
2185
specialTreatmentCommands.unite(add.specialTreatmentCommands);
2186
specialDefCommands.unite(add.specialDefCommands);
2040
2187
//possibleCommands.unite(add.possibleCommands);
2041
2188
foreach(const QString& elem,add.possibleCommands.keys()){
2042
2189
QSet<QString> set2=add.possibleCommands[elem];
2050
QString getImageAsText(const QPixmap &AImage) {
2197
QString getImageAsText(const QPixmap &AImage,const int w) {
2052
2199
QBuffer buffer(&ba);
2053
2200
buffer.open(QIODevice::WriteOnly);
2054
2201
AImage.save(&buffer, "PNG");
2055
return QString("<img src=\"data:image/png;base64,%1\">").arg(QString(buffer.data().toBase64()));
2202
QString text=w<0 ? QString("<img src=\"data:image/png;base64,%1\">").arg(QString(buffer.data().toBase64())): QString("<img src=\"data:image/png;base64,%1\" width=%2 >").arg(QString(buffer.data().toBase64())).arg(w);
2058
2206
void showTooltipLimited(QPoint tt,QString topic,int width){