]> git.lyx.org Git - lyx.git/blobdiff - src/tex2lyx/table.C
Add a Buffer::fully_loaded member function, returning true only when
[lyx.git] / src / tex2lyx / table.C
index abbb57235bc29f9ef0267a504dcfb83f8dc8ed8c..cbbb7225b85c7139dec02811df44e484355a33ad 100644 (file)
@@ -1,19 +1,26 @@
-/** The .tex to .lyx converter
-    \author André Pönitz (2003)
+/**
+ * \file table.C
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
  */
 
 // {[(
 
 #include <config.h>
 
-#include "Lsstream.h"
 #include "tex2lyx.h"
 
 #include <cctype>
 #include <fstream>
 #include <iostream>
-#include <string>
+#include <sstream>
 #include <vector>
+#include <map>
 
 using std::cerr;
 using std::endl;
@@ -23,42 +30,13 @@ using std::ostringstream;
 using std::string;
 using std::vector;
 
+#include "mathed/math_gridinfo.h"
 
-namespace {
-
-struct ColInfo
-{
-       ColInfo() : rightline(false) {}
-       string align;      // column alignment
-       string width;      // column width
-       bool   rightline;  // a line on the right?
-};
-
-
-struct RowInfo
-{
-       RowInfo() : topline(false), bottomline(false) {} 
-       bool topline;     // horizontal line above
-       bool bottomline;  // horizontal line below
-};
+// filled in preamble.C
+std::map<char, int> special_columns;
 
 
-struct CellInfo
-{
-       CellInfo()
-               : multi(0), leftline(false), rightline(false),
-          topline(false), bottomline(false)
-       {}
-
-       string content;    // cell content
-       int multi;         // multicolumn flag
-       string align;      // cell alignment
-       bool leftline;     // do we have a line on the left?
-       bool rightline;    // do we have a line on the right?
-       bool topline;        // do we have a line above?
-       bool bottomline;   // do we have a line below?
-};
-
+namespace {
 
 int string2int(string const & s, int deflt = 0)
 {
@@ -72,25 +50,24 @@ int string2int(string const & s, int deflt = 0)
 string read_hlines(Parser & p)
 {
        ostringstream os;
-       p.skipSpaces();
+       p.skip_spaces();
        while (p.good()) {
-               if (p.nextToken().cs() == "hline") {
-                       p.getToken();
+               if (p.next_token().cs() == "hline") {
+                       p.get_token();
                        os << "\\hline";
-               } else if (p.nextToken().cs() == "cline") {
-                       p.getToken();
-                       os << "\\cline{" << p.verbatimItem() << "}";
+               } else if (p.next_token().cs() == "cline") {
+                       p.get_token();
+                       os << "\\cline{" << p.verbatim_item() << "}";
                } else
                        break;
-               p.skipSpaces();
+               p.skip_spaces();
        };
        //cerr << "read_hlines(), read: '" << os.str() << "'\n";
-       //cerr << "read_hlines(), next token: " << p.nextToken() << "\n";
+       //cerr << "read_hlines(), next token: " << p.next_token() << "\n";
        return os.str();
 }
 
 
-
 /* rather brutish way to code table structure in a string:
 
   \begin{tabular}{ccc}
@@ -111,59 +88,72 @@ char const LINE  = '\002';
 char const HLINE = '\004';
 
 
-bool handle_colalign(Parser & p, vector<ColInfo> & colinfo)
+void handle_colalign(Parser & p, vector<ColInfo> & colinfo)
 {
-       if (p.getToken().cat() != catBegin)
+       if (p.get_token().cat() != catBegin)
                cerr << "wrong syntax for table column alignment. '{' expected\n";
 
-       string nextalign = "block";
+       char nextalign = 'b';
        bool leftline = false;
-       for (Token t = p.getToken(); p.good() && t.cat() != catEnd; t = p.getToken()){
+       for (Token t=p.get_token(); p.good() && t.cat() != catEnd; t = p.get_token()){
 #ifdef FILEDEBUG
                cerr << "t: " << t << "  c: '" << t.character() << "'\n";
 #endif
 
                switch (t.character()) {
                        case 'c':
-                               colinfo.push_back(ColInfo());
-                               colinfo.back().align = "center";
-                               break;
                        case 'l':
-                               colinfo.push_back(ColInfo());
-                               colinfo.back().align = "left";
-                               break;
-                       case 'r':
-                               colinfo.push_back(ColInfo());
-                               colinfo.back().align = "right";
+                       case 'r': {
+                               ColInfo ci;
+                               ci.align = t.character();
+                               if (colinfo.size() && colinfo.back().rightline > 1) {
+                                       ci.leftline = true;
+                                       --colinfo.back().rightline;
+                               }
+                               colinfo.push_back(ci);
                                break;
+                       }
                        case 'p':
                                colinfo.push_back(ColInfo());
                                colinfo.back().align = nextalign;
-                               colinfo.back().width = p.verbatimItem();
-                               nextalign = "block";
+                               colinfo.back().width = p.verbatim_item();
+                               nextalign = 'b';
                                break;
                        case '|':
                                if (colinfo.empty())
                                        leftline = true;
                                else
-                                       colinfo.back().rightline = true;
+                                       ++colinfo.back().rightline;
                                break;
                        case '>': {
-                               string s = p.verbatimItem();
+                               string s = p.verbatim_item();
                                if (s == "\\raggedleft ")
-                                       nextalign = "left";
+                                       nextalign = 'l';
                                else if (s == "\\raggedright ")
-                                       nextalign = "right";
+                                       nextalign = 'r';
                                else
                                        cerr << "unknown '>' column '" << s << "'\n";
                                break;
                        }
                        default:
-                               cerr << "ignoring special separator '" << t << "'\n";
+                               if (special_columns.find(t.character()) != special_columns.end()) {
+                                       ColInfo ci;
+                                       ci.align = 'c';
+                                       ci.special += t.character();
+                                       int const nargs = special_columns[t.character()];
+                                       for (int i = 0; i < nargs; ++i)
+                                               ci.special += "{" + p.verbatim_item() + "}";
+                                       //cerr << "handling special column '" << t << "' " << nargs
+                                       //      << "  '" << ci.special << "'\n";
+                                       colinfo.push_back(ci);
+                               } else {
+                                       cerr << "ignoring special separator '" << t << "'\n";
+                               }
                                break;
                        }
        }
-       return leftline;
+       if (colinfo.size() && leftline)
+               colinfo[0].leftline = true;
 }
 
 
@@ -175,7 +165,7 @@ void parse_table(Parser & p, ostream & os, unsigned flags)
        string hlines;
 
        while (p.good()) {
-               Token const & t = p.getToken();
+               Token const & t = p.get_token();
 
 #ifdef FILEDEBUG
                cerr << "t: " << t << " flags: " << flags << "\n";
@@ -186,13 +176,13 @@ void parse_table(Parser & p, ostream & os, unsigned flags)
                //
                if (t.cat() == catMath) {
                                // we are inside some text mode thingy, so opening new math is allowed
-                       Token const & n = p.getToken();
+                       Token const & n = p.get_token();
                        if (n.cat() == catMath) {
                                // TeX's $$...$$ syntax for displayed math
                                os << "\\[";
                                parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
                                os << "\\]";
-                               p.getToken(); // skip the second '$' token
+                               p.get_token(); // skip the second '$' token
                        } else {
                                // simple $...$  stuff
                                p.putback();
@@ -239,7 +229,7 @@ void parse_table(Parser & p, ostream & os, unsigned flags)
                        hlines += "\\hline";
 
                else if (t.cs() == "cline")
-                       hlines += "\\cline{" + p.verbatimItem() + '}';
+                       hlines += "\\cline{" + p.verbatim_item() + '}';
 
                else if (t.cat() == catComment)
                        handle_comment(p);
@@ -258,7 +248,7 @@ void parse_table(Parser & p, ostream & os, unsigned flags)
 
                else if (t.cs() == "begin") {
                        string const name = p.getArg('{', '}');
-                       active_environments_push(name);
+                       active_environments.push_back(name);
                        parse_table(p, os, FLAG_END);
                }
 
@@ -266,19 +256,39 @@ void parse_table(Parser & p, ostream & os, unsigned flags)
                        if (flags & FLAG_END) {
                                // eat environment name
                                string const name = p.getArg('{', '}');
-                               if (name != curr_env())
+                               if (name != active_environment())
                                        p.error("\\end{" + name + "} does not match \\begin{"
-                                               + curr_env() + "}");
-                               active_environments_pop();
+                                               + active_environment() + "}");
+                               active_environments.pop_back();
                                return;
                        }
                        p.error("found 'end' unexpectedly");
                }
+
+               else
+                       os << t.asInput();
        }
 }
 
 
-void handle_tabular(Parser & p, ostream & os)
+void handle_hline_above(RowInfo & ri, vector<CellInfo> & ci)
+{
+       ri.topline = true;
+       for (size_t col = 0; col < ci.size(); ++col)
+               ci[col].topline = true;
+}
+
+
+void handle_hline_below(RowInfo & ri, vector<CellInfo> & ci)
+{
+       ri.bottomline = true;
+       for (size_t col = 0; col < ci.size(); ++col)
+               ci[col].bottomline = true;
+}
+
+
+void handle_tabular(Parser & p, ostream & os,
+                   Context & context)
 {
        string posopts = p.getOpt();
        if (posopts.size())
@@ -287,7 +297,7 @@ void handle_tabular(Parser & p, ostream & os)
        vector<ColInfo>            colinfo;
 
        // handle column formatting
-       bool leftline = handle_colalign(p, colinfo);
+       handle_colalign(p, colinfo);
 
        // handle initial hlines
 
@@ -302,16 +312,15 @@ void handle_tabular(Parser & p, ostream & os)
 
        vector< vector<CellInfo> > cellinfo(lines.size());
        vector<RowInfo> rowinfo(lines.size());
-       
+
        // split into rows
        //cerr << "// split into rows\n";
        for (size_t row = 0; row < rowinfo.size(); ++row) {
 
                // init row
-               vector<CellInfo> & cellinfos = cellinfo[row];
-               cellinfos.resize(colinfo.size());
+               cellinfo[row].resize(colinfo.size());
 
-               // split row    
+               // split row
                vector<string> dummy;
                //cerr << "\n########### LINE: " << lines[row] << "########\n";
                split(lines[row], dummy, HLINE);
@@ -329,35 +338,45 @@ void handle_tabular(Parser & p, ostream & os)
                //cerr << "line: " << row << " below 2: " << dummy[2] <<  "\n";
                //cerr << "line: " << row << " cells 1: " << dummy[1] <<  "\n";
 
-               for (int i = 0; i <= 2; i += 2) {       
+               for (int i = 0; i <= 2; i += 2) {
                        //cerr << "   reading from line string '" << dummy[i] << "'\n";
                        Parser p1(dummy[i]);
                        while (p1.good()) {
-                               Token t = p1.getToken();
+                               Token t = p1.get_token();
                                //cerr << "read token: " << t << "\n";
                                if (t.cs() == "hline") {
                                        if (i == 0) {
-                                               rowinfo[row].topline = true;
-                                               for (size_t col = 0; col < colinfo.size(); ++col)
-                                                       cellinfos[col].topline = true;
+                                               if (rowinfo[row].topline) {
+                                                       if (row > 0) // extra bottomline above
+                                                               handle_hline_below(rowinfo[row - 1], cellinfo[row - 1]);
+                                                       else
+                                                               cerr << "dropping extra hline\n";
+                                                       //cerr << "below row: " << row-1 << endl;
+                                               } else {
+                                                       handle_hline_above(rowinfo[row], cellinfo[row]);
+                                                       //cerr << "above row: " << row << endl;
+                                               }
                                        } else {
-                                               rowinfo[row].bottomline = true;
-                                               for (size_t col = 0; col < colinfo.size(); ++col)
-                                                       cellinfos[col].bottomline = true;
+                                               //cerr << "below row: " << row << endl;
+                                               handle_hline_below(rowinfo[row], cellinfo[row]);
                                        }
                                } else if (t.cs() == "cline") {
-                                       string arg = p1.verbatimItem();
+                                       string arg = p1.verbatim_item();
                                        //cerr << "read cline arg: '" << arg << "'\n";
                                        vector<string> t;
                                        split(arg, t, '-');
                                        t.resize(2);
-                                       size_t from = string2int(t[0]);
+                                       size_t from = string2int(t[0]) - 1;
                                        size_t to = string2int(t[1]);
                                        for (size_t col = from; col < to; ++col) {
-                                               if (i == 0) 
-                                                       cellinfos[col].topline = true;
-                                               else    
-                                                       cellinfos[col].bottomline = true;
+                                               //cerr << "row: " << row << " col: " << col << " i: " << i << endl;
+                                               if (i == 0) {
+                                                       rowinfo[row].topline = true;
+                                                       cellinfo[row][col].topline = true;
+                                               } else {
+                                                       rowinfo[row].bottomline = true;
+                                                       cellinfo[row][col].bottomline = true;
+                                               }
                                        }
                                } else {
                                        cerr << "unexpected line token: " << t << endl;
@@ -368,45 +387,55 @@ void handle_tabular(Parser & p, ostream & os)
                // split into cells
                vector<string> cells;
                split(lines[row], cells, TAB);
-               for (size_t col = 0, cell = 0; cell < cells.size() && col < colinfo.size(); ++col, ++cell) {
-                       //cerr << "cell content: " << cells[cell] << "\n";
+               for (size_t col = 0, cell = 0;
+                               cell < cells.size() && col < colinfo.size(); ++col, ++cell) {
+                       //cerr << "cell content: '" << cells[cell] << "'\n";
                        Parser p(cells[cell]);
-                       p.skipSpaces(); 
-                       //cerr << "handling cell: " << p.nextToken().cs() << " '" <<
+                       p.skip_spaces();
                        //cells[cell] << "'\n";
-                       if (p.nextToken().cs() == "multicolumn") {
+                       if (p.next_token().cs() == "multicolumn") {
                                // how many cells?
-                               p.getToken();
-                               size_t ncells = string2int(p.verbatimItem());
+                               p.get_token();
+                               size_t const ncells = string2int(p.verbatim_item());
 
-                               // special cell properties alignment    
+                               // special cell properties alignment
                                vector<ColInfo> t;
-                               bool leftline = handle_colalign(p, t);
-                               CellInfo & ci = cellinfos[col];
-                               ci.multi     = 1;
-                               ci.align     = t.front().align;
-                               ci.content   = parse_text(p, FLAG_ITEM, false);
-                               ci.leftline  = leftline;
-                               ci.rightline = t.front().rightline;
+                               handle_colalign(p, t);
+                               cellinfo[row][col].multi     = 1;
+                               cellinfo[row][col].align     = t.front().align;
+                               ostringstream os;
+                               parse_text_in_inset(p, os, FLAG_ITEM, false, context);
+                               cellinfo[row][col].content   = os.str();
+                               cellinfo[row][col].leftline  |= t.front().leftline;
+                               cellinfo[row][col].rightline |= t.front().rightline;
 
                                // add dummy cells for multicol
                                for (size_t i = 0; i < ncells - 1 && col < colinfo.size(); ++i) {
                                        ++col;
-                                       cellinfos[col].multi = 2;
-                                       cellinfos[col].align = "center";
+                                       cellinfo[row][col].multi = 2;
+                                       cellinfo[row][col].align = 'c';
                                }
+
+                               // more than one line on the right?
+                               if (t.front().rightline > 1)
+                                       cellinfo[row][col + 1].leftline = true;
+
                        } else {
-                               cellinfos[col].content = parse_text(p, FLAG_ITEM, false);
+                               // FLAG_END is a hack, we need to read all of it
+                               cellinfo[row][col].leftline = colinfo[col].leftline;
+                               cellinfo[row][col].rightline = colinfo[col].rightline;
+                               cellinfo[row][col].align = colinfo[col].align;
+                               ostringstream os;
+                               parse_text_in_inset(p, os, FLAG_CELL, false, context);
+                               cellinfo[row][col].content   = os.str();
                        }
                }
 
-               cellinfo.push_back(cellinfos);
-
                //cerr << "//  handle almost empty last row what we have\n";
                // handle almost empty last row
                if (row && lines[row].empty() && row + 1 == rowinfo.size()) {
                        //cerr << "remove empty last line\n";
-                       if (rowinfo[row].topline);
+                       if (rowinfo[row].topline)
                                rowinfo[row - 1].bottomline = true;
                        for (size_t col = 0; col < colinfo.size(); ++col)
                                if (cellinfo[row][col].topline)
@@ -418,19 +447,23 @@ void handle_tabular(Parser & p, ostream & os)
 
        //cerr << "// output what we have\n";
        // output what we have
-       os << "<lyxtabular version=\"3\" rows=\"" << rowinfo.size()
+       os << "\n<lyxtabular version=\"3\" rows=\"" << rowinfo.size()
                 << "\" columns=\"" << colinfo.size() << "\">\n"
                 << "<features>\n";
 
        //cerr << "// after header\n";
        for (size_t col = 0; col < colinfo.size(); ++col) {
-               os << "<column alignment=\"" << colinfo[col].align << "\"";
+               os << "<column alignment=\""
+                  << verbose_align(colinfo[col].align) << "\"";
+               os << " valignment=\"top\"";
+               if (colinfo[col].leftline)
+                       os << " leftline=\"true\"";
                if (colinfo[col].rightline)
                        os << " rightline=\"true\"";
-               if (col == 0 && leftline)
-                       os << " leftline=\"true\"";
-               os << " valignment=\"top\"";
-               os << " width=\"" << colinfo[col].width << "\"";
+               if (colinfo[col].width.size())
+                       os << " width=\"" << colinfo[col].width << "\"";
+               if (colinfo[col].special.size())
+                       os << " special=\"" << colinfo[col].special << "\"";
                os << ">\n";
        }
        //cerr << "// after cols\n";
@@ -447,27 +480,32 @@ void handle_tabular(Parser & p, ostream & os)
                        os << "<cell";
                        if (cell.multi)
                                os << " multicolumn=\"" << cell.multi << "\"";
-                       if (cell.leftline)
-                               os << " leftline=\"true\"";
-                       if (cell.rightline)
-                               os << " rightline=\"true\"";
+                       os << " alignment=\"" << verbose_align(cell.align)
+                          << "\""
+                          << " valignment=\"top\"";
                        if (cell.topline)
                                os << " topline=\"true\"";
                        if (cell.bottomline)
                                os << " bottomline=\"true\"";
-                       os << " alignment=\"" << cell.align << "\""
-                                << " valignment=\"top\""
-                                << " usebox=\"none\""
-                                << ">"
-                          << "\n\\begin_inset Text"
-                          << "\n\n\\layout Standard\n\n"
+                       if (cell.leftline)
+                               os << " leftline=\"true\"";
+                       if (cell.rightline)
+                               os << " rightline=\"true\"";
+                       //cerr << "\nrow: " << row << " col: " << col;
+                       //if (cell.topline)
+                       //      cerr << " topline=\"true\"";
+                       //if (cell.bottomline)
+                       //      cerr << " bottomline=\"true\"";
+                       os << " usebox=\"none\""
+                          << ">"
+                          << "\n\\begin_inset Text\n"
                           << cell.content
-                          << "\n\\end_inset\n\n"
+                          << "\n\\end_inset \n"
                           << "</cell>\n";
                }
                os << "</row>\n";
        }
-                       
+
        os << "</lyxtabular>\n";
 }