lyx_mirror/src/output_plaintext.cpp
2020-12-01 00:46:09 +02:00

254 lines
5.6 KiB
C++

/**
* \file output_plaintext.cpp
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Lars Gullik Bjønnes
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "output_plaintext.h"
#include "Buffer.h"
#include "BufferParams.h"
#include "Layout.h"
#include "output.h"
#include "OutputParams.h"
#include "Paragraph.h"
#include "ParagraphList.h"
#include "ParagraphParameters.h"
#include "insets/Inset.h"
#include "support/debug.h"
#include "support/gettext.h"
#include "support/lstrings.h"
using namespace std;
using namespace lyx::support;
namespace lyx {
void writePlaintextFile(Buffer const & buf, FileName const & fname,
OutputParams const & runparams)
{
ofdocstream ofs;
if (!openFileWrite(ofs, fname))
return;
// make sure we are ready to export
buf.updateBuffer();
buf.updateMacroInstances(OutputUpdate);
buf.makeCitationLabels();
writePlaintextFile(buf, ofs, runparams);
}
void writePlaintextFile(Buffer const & buf, odocstream & os,
OutputParams const & runparams)
{
bool ref_printed = false;
ParagraphList const & par = buf.paragraphs();
ParagraphList::const_iterator beg = par.begin();
ParagraphList::const_iterator end = par.end();
ParagraphList::const_iterator it = beg;
for (; it != end; ++it) {
bool const merged_par = (*it).parEndChange().deleted();
writePlaintextParagraph(buf, *it, os, runparams, ref_printed);
if (!merged_par)
os << "\n";
if (runparams.linelen > 0 && !merged_par)
os << "\n";
}
}
static pair<int, docstring> addDepth(int depth, int ldepth)
{
int d = depth * 2;
if (ldepth > depth)
d += (ldepth - depth) * 2;
return make_pair(d, docstring(d, ' '));
}
void writePlaintextParagraph(Buffer const & buf,
Paragraph const & par,
odocstream & ods,
OutputParams const & runparams,
bool & ref_printed, size_t max_length)
{
int ltype = 0;
depth_type ltype_depth = 0;
depth_type depth = par.params().depth();
// First write the layout
string const tmp = to_utf8(par.layout().name());
if (compare_ascii_no_case(tmp, "itemize") == 0) {
ltype = 1;
ltype_depth = depth + 1;
} else if (compare_ascii_no_case(tmp, "enumerate") == 0) {
ltype = 2;
ltype_depth = depth + 1;
} else if (contains(ascii_lowercase(tmp), "ection")) {
ltype = 3;
ltype_depth = depth + 1;
} else if (contains(ascii_lowercase(tmp), "aragraph")) {
ltype = 4;
ltype_depth = depth + 1;
} else if (compare_ascii_no_case(tmp, "description") == 0) {
ltype = 5;
ltype_depth = depth + 1;
} else if (compare_ascii_no_case(tmp, "abstract") == 0) {
ltype = 6;
ltype_depth = 0;
} else if (compare_ascii_no_case(tmp, "bibliography") == 0) {
ltype = 7;
ltype_depth = 0;
} else {
ltype = 0;
ltype_depth = 0;
}
/* the labelwidthstring used in lists */
/* noindent ? */
/* what about the alignment */
// runparams.linelen == 0 is special and means we don't have paragraph breaks
string::size_type currlinelen = 0;
odocstringstream os;
os << docstring(depth * 2, ' ');
currlinelen += depth * 2;
//--
// we should probably change to the paragraph language in the
// support/gettext.here (if possible) so that strings are output in
// the correct language! (20012712 Jug)
//--
switch (ltype) {
case 0: // Standard
case 4: // (Sub)Paragraph
case 5: // Description
break;
case 6: // Abstract
if (runparams.linelen > 0) {
os << buf.B_("Abstract") << "\n\n";
currlinelen = 0;
} else {
docstring const abst = buf.B_("Abstract: ");
os << abst;
currlinelen += abst.length();
}
break;
case 7: // Bibliography
if (!ref_printed) {
if (runparams.linelen > 0) {
os << buf.B_("References") << "\n\n";
currlinelen = 0;
} else {
docstring const refs = buf.B_("References: ");
os << refs;
currlinelen += refs.length();
}
ref_printed = true;
}
break;
default: {
docstring const label = par.params().labelString();
if (!label.empty()) {
os << label << ' ';
currlinelen += label.length() + 1;
}
break;
}
}
if (currlinelen == 0) {
pair<int, docstring> p = addDepth(depth, ltype_depth);
os << p.second;
currlinelen += p.first;
}
docstring word;
for (pos_type i = 0; i < par.size(); ++i) {
// deleted characters don't make much sense in plain text output
if (par.isDeleted(i))
continue;
if (os.str().size() > max_length)
break;
char_type c = par.getUChar(buf.params(), runparams, i);
if (par.isInset(i) || c == ' ') {
if (runparams.linelen > 0 &&
currlinelen + word.length() > runparams.linelen) {
os << '\n';
pair<int, docstring> p = addDepth(depth, ltype_depth);
os << p.second;
currlinelen = p.first;
}
os << word;
currlinelen += word.length();
word.erase();
}
if (par.isInset(i)) {
OutputParams rp = runparams;
rp.depth = par.params().depth();
int len = par.getInset(i)->plaintext(os, rp, max_length);
if (len >= Inset::PLAINTEXT_NEWLINE)
currlinelen = len - Inset::PLAINTEXT_NEWLINE;
else
currlinelen += len;
continue;
}
switch (c) {
case ' ':
os << ' ';
++currlinelen;
break;
case '\0':
LYXERR(Debug::INFO, "writePlaintextFile: NUL char in structure.");
break;
default:
word += c;
break;
}
}
// currlinelen may be greater than runparams.linelen!
// => check whether word is empty and do nothing in this case
if (!word.empty()) {
if (runparams.linelen > 0 &&
currlinelen + word.length() > runparams.linelen) {
os << '\n';
pair<int, docstring> p = addDepth(depth, ltype_depth);
os << p.second;
currlinelen = p.first;
}
os << word;
}
ods << os.str();
}
} // namespace lyx