2003-08-23 00:17:00 +00:00
|
|
|
/**
|
2007-04-26 04:41:58 +00:00
|
|
|
* \file Paragraph.cpp
|
2003-08-23 00:17:00 +00:00
|
|
|
* This file is part of LyX, the document processor.
|
|
|
|
* Licence details can be found in the file COPYING.
|
2002-03-21 17:27:08 +00:00
|
|
|
*
|
2003-08-23 00:17:00 +00:00
|
|
|
* \author Asger Alstrup
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author Lars Gullik Bjønnes
|
2009-11-19 18:28:36 +00:00
|
|
|
* \author Richard Heck (XHTML output)
|
2003-08-23 00:17:00 +00:00
|
|
|
* \author Jean-Marc Lasgouttes
|
|
|
|
* \author Angus Leeming
|
|
|
|
* \author John Levon
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author André Pönitz
|
2003-08-23 00:17:00 +00:00
|
|
|
* \author Dekel Tsur
|
2008-11-14 15:58:50 +00:00
|
|
|
* \author Jürgen Vigna
|
2002-03-21 17:27:08 +00:00
|
|
|
*
|
2003-08-23 00:17:00 +00:00
|
|
|
* Full author contact details are available in file CREDITS.
|
|
|
|
*/
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Paragraph.h"
|
2003-05-22 22:44:30 +00:00
|
|
|
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Buffer.h"
|
|
|
|
#include "BufferParams.h"
|
2020-10-20 08:36:59 +00:00
|
|
|
#include "BufferEncodings.h"
|
2007-10-18 15:29:51 +00:00
|
|
|
#include "Changes.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Counters.h"
|
2007-10-18 15:29:51 +00:00
|
|
|
#include "InsetList.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "Language.h"
|
2005-01-24 17:12:19 +00:00
|
|
|
#include "LaTeXFeatures.h"
|
2007-09-29 20:02:32 +00:00
|
|
|
#include "Layout.h"
|
2007-04-29 18:17:15 +00:00
|
|
|
#include "Font.h"
|
2007-10-19 14:35:05 +00:00
|
|
|
#include "FontList.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "LyXRC.h"
|
|
|
|
#include "OutputParams.h"
|
2007-03-18 10:59:16 +00:00
|
|
|
#include "output_latex.h"
|
2009-06-05 17:44:35 +00:00
|
|
|
#include "output_xhtml.h"
|
2019-05-09 23:35:40 +00:00
|
|
|
#include "output_docbook.h"
|
2007-04-24 10:01:03 +00:00
|
|
|
#include "ParagraphParameters.h"
|
2009-05-01 09:43:40 +00:00
|
|
|
#include "SpellChecker.h"
|
2016-06-19 02:39:38 +00:00
|
|
|
#include "texstream.h"
|
2007-04-26 04:41:58 +00:00
|
|
|
#include "TexRow.h"
|
2008-02-26 13:07:59 +00:00
|
|
|
#include "Text.h"
|
2020-10-20 08:36:59 +00:00
|
|
|
#include "TextClass.h"
|
2009-05-01 09:43:40 +00:00
|
|
|
#include "WordLangTuple.h"
|
2008-02-26 13:07:59 +00:00
|
|
|
#include "WordList.h"
|
2001-12-28 13:26:54 +00:00
|
|
|
|
2007-07-11 16:39:26 +00:00
|
|
|
#include "frontends/alert.h"
|
2006-12-29 23:54:48 +00:00
|
|
|
|
2007-04-25 01:24:38 +00:00
|
|
|
#include "insets/InsetBibitem.h"
|
2007-10-23 18:51:04 +00:00
|
|
|
#include "insets/InsetLabel.h"
|
2010-11-22 07:50:34 +00:00
|
|
|
#include "insets/InsetSpecialChar.h"
|
2017-06-03 15:26:05 +00:00
|
|
|
#include "insets/InsetText.h"
|
2001-12-28 13:26:54 +00:00
|
|
|
|
2016-10-18 01:29:53 +00:00
|
|
|
#include "mathed/InsetMathHull.h"
|
|
|
|
|
2007-11-29 07:04:28 +00:00
|
|
|
#include "support/debug.h"
|
2009-06-22 16:38:11 +00:00
|
|
|
#include "support/docstring_list.h"
|
2007-11-29 07:04:28 +00:00
|
|
|
#include "support/gettext.h"
|
2009-06-22 16:38:11 +00:00
|
|
|
#include "support/lassert.h"
|
2001-12-28 13:26:54 +00:00
|
|
|
#include "support/lstrings.h"
|
2003-11-25 17:23:36 +00:00
|
|
|
#include "support/textutils.h"
|
2003-09-06 12:36:58 +00:00
|
|
|
|
2016-07-10 15:50:19 +00:00
|
|
|
#include <atomic>
|
2004-07-24 10:55:30 +00:00
|
|
|
#include <sstream>
|
2007-10-24 07:08:55 +00:00
|
|
|
#include <vector>
|
2003-10-30 08:47:16 +00:00
|
|
|
|
2007-12-12 10:16:00 +00:00
|
|
|
using namespace std;
|
2007-12-12 18:57:56 +00:00
|
|
|
using namespace lyx::support;
|
2001-11-27 10:34:16 +00:00
|
|
|
|
2017-06-26 12:41:34 +00:00
|
|
|
// OSX clang, gcc < 4.8.0, and msvc < 2015 do not support C++11 thread_local
|
|
|
|
#if defined(__APPLE__) || (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
2017-06-03 15:26:05 +00:00
|
|
|
#define THREAD_LOCAL_STATIC static __thread
|
|
|
|
#elif defined(_MSC_VER) && (_MSC_VER < 1900)
|
|
|
|
#define THREAD_LOCAL_STATIC static __declspec(thread)
|
|
|
|
#else
|
|
|
|
#define THREAD_LOCAL_STATIC thread_local static
|
|
|
|
#endif
|
|
|
|
|
2006-12-29 23:54:48 +00:00
|
|
|
namespace lyx {
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2010-09-19 16:00:32 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// SpellResultRange
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class SpellResultRange {
|
|
|
|
public:
|
|
|
|
SpellResultRange(FontSpan range, SpellChecker::Result result)
|
|
|
|
: range_(range), result_(result)
|
|
|
|
{}
|
|
|
|
///
|
2010-09-20 06:54:34 +00:00
|
|
|
FontSpan const & range() const { return range_; }
|
2010-09-19 16:00:32 +00:00
|
|
|
///
|
2010-09-20 06:54:34 +00:00
|
|
|
void range(FontSpan const & r) { range_ = r; }
|
2010-09-19 16:00:32 +00:00
|
|
|
///
|
|
|
|
SpellChecker::Result result() const { return result_; }
|
|
|
|
///
|
|
|
|
void result(SpellChecker::Result r) { result_ = r; }
|
|
|
|
///
|
2014-07-28 18:41:01 +00:00
|
|
|
bool contains(pos_type pos) const { return range_.contains(pos); }
|
2010-09-19 16:00:32 +00:00
|
|
|
///
|
2010-09-20 06:54:34 +00:00
|
|
|
bool covered(FontSpan const & r) const
|
2010-09-19 16:00:32 +00:00
|
|
|
{
|
|
|
|
// 1. first of new range inside current range or
|
|
|
|
// 2. last of new range inside current range or
|
|
|
|
// 3. first of current range inside new range or
|
|
|
|
// 4. last of current range inside new range
|
2014-07-28 18:41:01 +00:00
|
|
|
//FIXME: is this the same as !range_.intersect(r).empty() ?
|
|
|
|
return range_.contains(r.first) || range_.contains(r.last) ||
|
|
|
|
r.contains(range_.first) || r.contains(range_.last);
|
2010-09-19 16:00:32 +00:00
|
|
|
}
|
|
|
|
///
|
|
|
|
void shift(pos_type pos, int offset)
|
|
|
|
{
|
|
|
|
if (range_.first > pos) {
|
|
|
|
range_.first += offset;
|
|
|
|
range_.last += offset;
|
2011-03-16 13:54:36 +00:00
|
|
|
} else if (range_.last >= pos) {
|
2010-09-19 16:00:32 +00:00
|
|
|
range_.last += offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
FontSpan range_ ;
|
|
|
|
SpellChecker::Result result_ ;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// SpellCheckerState
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class SpellCheckerState {
|
|
|
|
public:
|
2012-10-27 13:45:27 +00:00
|
|
|
SpellCheckerState()
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
needs_refresh_ = true;
|
|
|
|
current_change_number_ = 0;
|
|
|
|
}
|
|
|
|
|
2012-05-28 20:41:32 +00:00
|
|
|
void setRange(FontSpan const & fp, SpellChecker::Result state)
|
2010-09-14 05:24:04 +00:00
|
|
|
{
|
2011-01-07 15:20:58 +00:00
|
|
|
Ranges result;
|
|
|
|
RangesIterator et = ranges_.end();
|
|
|
|
RangesIterator it = ranges_.begin();
|
|
|
|
for (; it != et; ++it) {
|
|
|
|
if (!it->covered(fp))
|
|
|
|
result.push_back(SpellResultRange(it->range(), it->result()));
|
|
|
|
else if (state == SpellChecker::WORD_OK) {
|
|
|
|
// trim or split the current misspelled range
|
|
|
|
// store misspelled ranges only
|
|
|
|
FontSpan range = it->range();
|
|
|
|
if (fp.first > range.first) {
|
|
|
|
// misspelled area in front of WORD_OK
|
|
|
|
range.last = fp.first - 1;
|
|
|
|
result.push_back(SpellResultRange(range, it->result()));
|
|
|
|
range = it->range();
|
|
|
|
}
|
|
|
|
if (fp.last < range.last) {
|
|
|
|
// misspelled area after WORD_OK range
|
|
|
|
range.first = fp.last + 1;
|
|
|
|
result.push_back(SpellResultRange(range, it->result()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ranges_ = result;
|
2010-09-14 05:24:04 +00:00
|
|
|
if (state != SpellChecker::WORD_OK)
|
2010-09-19 16:00:32 +00:00
|
|
|
ranges_.push_back(SpellResultRange(fp, state));
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void increasePosAfterPos(pos_type pos)
|
|
|
|
{
|
|
|
|
correctRangesAfterPos(pos, 1);
|
|
|
|
needsRefresh(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void decreasePosAfterPos(pos_type pos)
|
|
|
|
{
|
|
|
|
correctRangesAfterPos(pos, -1);
|
|
|
|
needsRefresh(pos);
|
|
|
|
}
|
|
|
|
|
2010-10-12 19:05:47 +00:00
|
|
|
void refreshLast(pos_type pos)
|
|
|
|
{
|
|
|
|
if (pos < refresh_.last)
|
|
|
|
refresh_.last = pos;
|
|
|
|
}
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
SpellChecker::Result getState(pos_type pos) const
|
|
|
|
{
|
|
|
|
SpellChecker::Result result = SpellChecker::WORD_OK;
|
|
|
|
RangesIterator et = ranges_.end();
|
|
|
|
RangesIterator it = ranges_.begin();
|
|
|
|
for (; it != et; ++it) {
|
2014-07-28 18:41:01 +00:00
|
|
|
if(it->contains(pos)) {
|
2010-09-19 16:00:32 +00:00
|
|
|
return it->result();
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2010-12-22 07:29:16 +00:00
|
|
|
FontSpan const & getRange(pos_type pos) const
|
|
|
|
{
|
2010-12-22 17:09:51 +00:00
|
|
|
/// empty span to indicate mismatch
|
|
|
|
static FontSpan empty_;
|
2010-12-22 07:29:16 +00:00
|
|
|
RangesIterator et = ranges_.end();
|
|
|
|
RangesIterator it = ranges_.begin();
|
|
|
|
for (; it != et; ++it) {
|
2014-07-28 18:41:01 +00:00
|
|
|
if(it->contains(pos)) {
|
2010-12-22 07:29:16 +00:00
|
|
|
return it->range();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return empty_;
|
|
|
|
}
|
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
bool needsRefresh() const
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
return needs_refresh_;
|
|
|
|
}
|
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
SpellChecker::ChangeNumber currentChangeNumber() const
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
return current_change_number_;
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
void refreshRange(pos_type & first, pos_type & last) const
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
first = refresh_.first;
|
|
|
|
last = refresh_.last;
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
void needsRefresh(pos_type pos)
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
if (needs_refresh_ && pos != -1) {
|
|
|
|
if (pos < refresh_.first)
|
|
|
|
refresh_.first = pos;
|
|
|
|
if (pos > refresh_.last)
|
|
|
|
refresh_.last = pos;
|
|
|
|
} else if (pos != -1) {
|
2011-01-07 15:20:58 +00:00
|
|
|
// init request check for neighbour positions too
|
|
|
|
refresh_.first = pos > 0 ? pos - 1 : 0;
|
|
|
|
// no need for special end of paragraph check
|
|
|
|
refresh_.last = pos + 1;
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
needs_refresh_ = pos != -1;
|
|
|
|
}
|
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
void needsCompleteRefresh(SpellChecker::ChangeNumber change_number)
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
needs_refresh_ = true;
|
|
|
|
refresh_.first = 0;
|
|
|
|
refresh_.last = -1;
|
|
|
|
current_change_number_ = change_number;
|
|
|
|
}
|
|
|
|
private:
|
2010-09-19 16:00:32 +00:00
|
|
|
typedef vector<SpellResultRange> Ranges;
|
2010-09-14 05:24:04 +00:00
|
|
|
typedef Ranges::const_iterator RangesIterator;
|
|
|
|
Ranges ranges_;
|
2010-09-19 16:00:32 +00:00
|
|
|
/// the area of the paragraph with pending spell check
|
2010-09-14 05:24:04 +00:00
|
|
|
FontSpan refresh_;
|
2010-09-19 16:00:32 +00:00
|
|
|
/// spell state cache version number
|
2010-09-14 05:24:04 +00:00
|
|
|
SpellChecker::ChangeNumber current_change_number_;
|
2020-08-01 05:57:38 +00:00
|
|
|
bool needs_refresh_;
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2010-09-19 16:00:32 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void correctRangesAfterPos(pos_type pos, int offset)
|
2010-09-14 14:00:29 +00:00
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
RangesIterator et = ranges_.end();
|
2010-09-19 16:00:32 +00:00
|
|
|
Ranges::iterator it = ranges_.begin();
|
2010-09-14 05:24:04 +00:00
|
|
|
for (; it != et; ++it) {
|
2010-09-19 16:00:32 +00:00
|
|
|
it->shift(pos, offset);
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2007-10-19 08:57:22 +00:00
|
|
|
// Paragraph::Private
|
2007-04-24 10:01:03 +00:00
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
class Paragraph::Private
|
|
|
|
{
|
2016-07-10 15:50:19 +00:00
|
|
|
// Enforce our own "copy" constructor
|
|
|
|
Private(Private const &) = delete;
|
|
|
|
Private & operator=(Private const &) = delete;
|
|
|
|
// Unique ID generator
|
|
|
|
static int make_id();
|
2007-04-24 10:01:03 +00:00
|
|
|
public:
|
|
|
|
///
|
2008-03-06 21:31:27 +00:00
|
|
|
Private(Paragraph * owner, Layout const & layout);
|
2007-04-24 10:01:03 +00:00
|
|
|
/// "Copy constructor"
|
2007-10-19 08:57:22 +00:00
|
|
|
Private(Private const &, Paragraph * owner);
|
2008-07-30 09:07:32 +00:00
|
|
|
/// Copy constructor from \p beg to \p end
|
|
|
|
Private(Private const &, Paragraph * owner, pos_type beg, pos_type end);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
///
|
2007-10-24 07:08:55 +00:00
|
|
|
void insertChar(pos_type pos, char_type c, Change const & change);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
/// Output the surrogate pair formed by \p c and \p next to \p os.
|
|
|
|
/// \return the number of characters written.
|
2018-04-22 17:06:46 +00:00
|
|
|
int latexSurrogatePair(BufferParams const &, otexstream & os,
|
|
|
|
char_type c, char_type next,
|
2009-07-16 06:19:25 +00:00
|
|
|
OutputParams const &);
|
2007-10-19 08:57:22 +00:00
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
/// Output a space in appropriate formatting (or a surrogate pair
|
|
|
|
/// if the next character is a combining character).
|
|
|
|
/// \return whether a surrogate pair was output.
|
2018-04-22 17:06:46 +00:00
|
|
|
bool simpleTeXBlanks(BufferParams const &,
|
|
|
|
OutputParams const &,
|
2011-02-10 20:02:48 +00:00
|
|
|
otexstream &,
|
2007-10-22 13:09:16 +00:00
|
|
|
pos_type i,
|
2007-04-24 10:01:03 +00:00
|
|
|
unsigned int & column,
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const & font,
|
2007-04-29 18:58:28 +00:00
|
|
|
Layout const & style);
|
2007-10-19 08:57:22 +00:00
|
|
|
|
2007-10-23 13:25:05 +00:00
|
|
|
/// This could go to ParagraphParameters if we want to.
|
2011-02-10 20:02:48 +00:00
|
|
|
int startTeXParParams(BufferParams const &, otexstream &,
|
2008-09-18 14:51:16 +00:00
|
|
|
OutputParams const &) const;
|
2007-10-23 13:25:05 +00:00
|
|
|
|
|
|
|
/// This could go to ParagraphParameters if we want to.
|
2011-06-22 16:21:03 +00:00
|
|
|
bool endTeXParParams(BufferParams const &, otexstream &,
|
|
|
|
OutputParams const &) const;
|
2007-10-23 13:25:05 +00:00
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
///
|
2008-02-27 20:43:16 +00:00
|
|
|
void latexInset(BufferParams const &,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
otexstream &,
|
2011-02-10 20:02:48 +00:00
|
|
|
OutputParams &,
|
2007-05-28 22:27:45 +00:00
|
|
|
Font & running_font,
|
2007-04-29 18:17:15 +00:00
|
|
|
Font & basefont,
|
|
|
|
Font const & outerfont,
|
2007-04-24 10:01:03 +00:00
|
|
|
bool & open_font,
|
2007-05-08 17:46:03 +00:00
|
|
|
Change & running_change,
|
2007-04-29 18:58:28 +00:00
|
|
|
Layout const & style,
|
2007-04-24 10:01:03 +00:00
|
|
|
pos_type & i,
|
2020-08-15 10:26:07 +00:00
|
|
|
unsigned int & column,
|
2020-08-16 08:47:08 +00:00
|
|
|
bool const fontswitch_inset,
|
|
|
|
bool const closeLanguage,
|
|
|
|
bool const lang_switched_at_inset);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
///
|
2007-10-22 13:09:16 +00:00
|
|
|
void latexSpecialChar(
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
otexstream & os,
|
2012-07-23 12:56:00 +00:00
|
|
|
BufferParams const & bparams,
|
2008-10-19 07:03:44 +00:00
|
|
|
OutputParams const & runparams,
|
|
|
|
Font const & running_font,
|
2019-03-11 14:24:22 +00:00
|
|
|
string & alien_script,
|
2007-10-22 13:09:16 +00:00
|
|
|
Layout const & style,
|
2007-10-20 08:09:55 +00:00
|
|
|
pos_type & i,
|
2011-02-12 11:03:24 +00:00
|
|
|
pos_type end_pos,
|
2007-10-22 13:09:16 +00:00
|
|
|
unsigned int & column);
|
2007-10-20 08:09:55 +00:00
|
|
|
|
2007-10-23 09:53:06 +00:00
|
|
|
///
|
|
|
|
bool latexSpecialT1(
|
|
|
|
char_type const c,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
otexstream & os,
|
2008-10-19 07:03:44 +00:00
|
|
|
pos_type i,
|
2020-10-21 08:35:40 +00:00
|
|
|
unsigned int & column) const;
|
2007-10-23 09:53:06 +00:00
|
|
|
///
|
2017-02-23 09:17:52 +00:00
|
|
|
bool latexSpecialTU(
|
|
|
|
char_type const c,
|
|
|
|
otexstream & os,
|
|
|
|
pos_type i,
|
2020-10-21 08:35:40 +00:00
|
|
|
unsigned int & column) const;
|
2017-02-23 09:17:52 +00:00
|
|
|
///
|
2012-03-09 11:14:39 +00:00
|
|
|
bool latexSpecialT3(
|
|
|
|
char_type const c,
|
|
|
|
otexstream & os,
|
|
|
|
pos_type i,
|
2020-10-21 08:35:40 +00:00
|
|
|
unsigned int & column) const;
|
2007-10-23 09:53:06 +00:00
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
///
|
2009-11-17 22:18:28 +00:00
|
|
|
void validate(LaTeXFeatures & features) const;
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-24 15:32:43 +00:00
|
|
|
/// Checks if the paragraph contains only text and no inset or font change.
|
|
|
|
bool onlyText(Buffer const & buf, Font const & outerfont,
|
|
|
|
pos_type initial) const;
|
|
|
|
|
2010-09-29 19:31:16 +00:00
|
|
|
/// a vector of speller skip positions
|
|
|
|
typedef vector<FontSpan> SkipPositions;
|
|
|
|
typedef SkipPositions::const_iterator SkipPositionsIterator;
|
2010-09-14 05:24:04 +00:00
|
|
|
|
2010-09-29 19:31:16 +00:00
|
|
|
void appendSkipPosition(SkipPositions & skips, pos_type const pos) const;
|
2017-07-03 17:53:14 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
Language * getSpellLanguage(pos_type const from) const;
|
|
|
|
|
|
|
|
Language * locateSpellRange(pos_type & from, pos_type & to,
|
2012-10-27 13:45:27 +00:00
|
|
|
SkipPositions & skips) const;
|
2010-09-14 05:24:04 +00:00
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
bool hasSpellerChange() const
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
SpellChecker::ChangeNumber speller_change_number = 0;
|
|
|
|
if (theSpellChecker())
|
|
|
|
speller_change_number = theSpellChecker()->changeNumber();
|
|
|
|
return speller_change_number > speller_state_.currentChangeNumber();
|
|
|
|
}
|
|
|
|
|
2010-12-07 00:13:19 +00:00
|
|
|
bool ignoreWord(docstring const & word) const ;
|
2017-07-03 17:53:14 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void setMisspelled(pos_type from, pos_type to, SpellChecker::Result state)
|
2010-08-26 11:47:27 +00:00
|
|
|
{
|
|
|
|
pos_type textsize = owner_->size();
|
|
|
|
// check for sane arguments
|
2011-01-28 07:01:38 +00:00
|
|
|
if (to <= from || from >= textsize)
|
2010-09-14 05:24:04 +00:00
|
|
|
return;
|
2011-01-28 07:01:38 +00:00
|
|
|
FontSpan fp = FontSpan(from, to - 1);
|
2010-09-14 05:24:04 +00:00
|
|
|
speller_state_.setRange(fp, state);
|
2010-08-26 11:47:27 +00:00
|
|
|
}
|
2009-08-09 14:33:35 +00:00
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
void requestSpellCheck(pos_type pos)
|
|
|
|
{
|
2011-08-20 13:48:19 +00:00
|
|
|
if (pos == -1)
|
|
|
|
speller_state_.needsCompleteRefresh(speller_state_.currentChangeNumber());
|
|
|
|
else
|
|
|
|
speller_state_.needsRefresh(pos);
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2012-10-27 13:45:27 +00:00
|
|
|
void readySpellCheck()
|
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
speller_state_.needsRefresh(-1);
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
bool needsSpellCheck() const
|
|
|
|
{
|
|
|
|
return speller_state_.needsRefresh();
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void rangeOfSpellCheck(pos_type & first, pos_type & last) const
|
|
|
|
{
|
|
|
|
speller_state_.refreshRange(first, last);
|
|
|
|
if (last == -1) {
|
|
|
|
last = owner_->size();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pos_type endpos = last;
|
2019-12-27 12:01:35 +00:00
|
|
|
owner_->locateWord(first, endpos, WHOLE_WORD, true);
|
2010-09-14 05:24:04 +00:00
|
|
|
if (endpos < last) {
|
|
|
|
endpos = last;
|
2019-12-27 12:01:35 +00:00
|
|
|
owner_->locateWord(last, endpos, WHOLE_WORD, true);
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
last = endpos;
|
|
|
|
}
|
2010-09-14 12:48:03 +00:00
|
|
|
|
2010-09-29 19:31:16 +00:00
|
|
|
int countSkips(SkipPositionsIterator & it, SkipPositionsIterator const et,
|
2010-09-14 14:01:44 +00:00
|
|
|
int & start) const
|
2010-09-14 12:48:03 +00:00
|
|
|
{
|
2010-09-29 19:31:16 +00:00
|
|
|
int numskips = 0;
|
|
|
|
while (it != et && it->first < start) {
|
2020-08-01 05:57:38 +00:00
|
|
|
long skip = it->last - it->first + 1;
|
2010-09-29 19:31:16 +00:00
|
|
|
start += skip;
|
|
|
|
numskips += skip;
|
2010-09-14 12:48:03 +00:00
|
|
|
++it;
|
|
|
|
}
|
2010-09-29 19:31:16 +00:00
|
|
|
return numskips;
|
2010-09-14 12:48:03 +00:00
|
|
|
}
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void markMisspelledWords(pos_type const & first, pos_type const & last,
|
|
|
|
SpellChecker::Result result,
|
|
|
|
docstring const & word,
|
2010-09-29 19:31:16 +00:00
|
|
|
SkipPositions const & skips);
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2009-08-09 17:00:26 +00:00
|
|
|
InsetCode ownerCode() const
|
2009-08-09 14:33:35 +00:00
|
|
|
{
|
|
|
|
return inset_owner_ ? inset_owner_->lyxCode() : NO_CODE;
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
/// Which Paragraph owns us?
|
|
|
|
Paragraph * owner_;
|
|
|
|
|
|
|
|
/// In which Inset?
|
2008-09-13 17:01:54 +00:00
|
|
|
Inset const * inset_owner_;
|
2007-10-19 08:57:22 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
FontList fontlist_;
|
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
///
|
2007-10-19 08:57:22 +00:00
|
|
|
ParagraphParameters params_;
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
/// for recording and looking up changes
|
|
|
|
Changes changes_;
|
|
|
|
|
2007-10-18 15:29:51 +00:00
|
|
|
///
|
|
|
|
InsetList insetlist_;
|
2007-10-23 13:25:05 +00:00
|
|
|
|
|
|
|
/// end of label
|
|
|
|
pos_type begin_of_body_;
|
2007-10-24 07:08:55 +00:00
|
|
|
|
2007-10-24 08:50:58 +00:00
|
|
|
typedef docstring TextContainer;
|
2007-10-24 07:08:55 +00:00
|
|
|
///
|
|
|
|
TextContainer text_;
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2009-12-18 14:48:56 +00:00
|
|
|
typedef set<docstring> Words;
|
2014-03-21 11:24:47 +00:00
|
|
|
typedef map<string, Words> LangWordsMap;
|
2008-02-26 13:07:59 +00:00
|
|
|
///
|
2010-06-09 21:02:47 +00:00
|
|
|
LangWordsMap words_;
|
2008-03-06 21:31:27 +00:00
|
|
|
///
|
|
|
|
Layout const * layout_;
|
2010-09-14 05:24:04 +00:00
|
|
|
///
|
|
|
|
SpellCheckerState speller_state_;
|
2020-08-01 05:57:38 +00:00
|
|
|
///
|
|
|
|
int id_;
|
2007-04-24 10:01:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-03-06 21:31:27 +00:00
|
|
|
Paragraph::Private::Private(Paragraph * owner, Layout const & layout)
|
2020-08-01 05:57:38 +00:00
|
|
|
: owner_(owner), inset_owner_(nullptr), begin_of_body_(0), layout_(&layout), id_(-1)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2007-10-24 07:08:55 +00:00
|
|
|
text_.reserve(100);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-07-10 15:50:19 +00:00
|
|
|
//static
|
|
|
|
int Paragraph::Private::make_id()
|
|
|
|
{
|
|
|
|
// The id is unique per session across buffers because it is used in
|
|
|
|
// LFUN_PARAGRAPH_GOTO to switch to a different buffer, for instance in the
|
|
|
|
// outliner.
|
|
|
|
// (thread-safe)
|
2020-08-01 05:57:38 +00:00
|
|
|
static int next_id(0);
|
2016-07-10 15:50:19 +00:00
|
|
|
return next_id++;
|
|
|
|
}
|
|
|
|
|
2010-01-06 09:12:49 +00:00
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
Paragraph::Private::Private(Private const & p, Paragraph * owner)
|
2010-09-14 14:00:29 +00:00
|
|
|
: owner_(owner), inset_owner_(p.inset_owner_), fontlist_(p.fontlist_),
|
2010-01-06 09:12:49 +00:00
|
|
|
params_(p.params_), changes_(p.changes_), insetlist_(p.insetlist_),
|
2008-03-06 21:31:27 +00:00
|
|
|
begin_of_body_(p.begin_of_body_), text_(p.text_), words_(p.words_),
|
2020-08-01 05:57:38 +00:00
|
|
|
layout_(p.layout_), id_(make_id())
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
requestSpellCheck(p.text_.size());
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-30 09:07:32 +00:00
|
|
|
Paragraph::Private::Private(Private const & p, Paragraph * owner,
|
|
|
|
pos_type beg, pos_type end)
|
2020-08-01 05:57:38 +00:00
|
|
|
: owner_(owner), inset_owner_(p.inset_owner_),
|
2008-07-30 09:07:32 +00:00
|
|
|
params_(p.params_), changes_(p.changes_),
|
2008-08-13 13:25:36 +00:00
|
|
|
insetlist_(p.insetlist_, beg, end),
|
2008-07-30 09:07:32 +00:00
|
|
|
begin_of_body_(p.begin_of_body_), words_(p.words_),
|
2020-08-01 05:57:38 +00:00
|
|
|
layout_(p.layout_), id_(make_id())
|
2008-07-30 09:07:32 +00:00
|
|
|
{
|
|
|
|
if (beg >= pos_type(p.text_.size()))
|
|
|
|
return;
|
|
|
|
text_ = p.text_.substr(beg, end - beg);
|
2008-08-07 08:50:41 +00:00
|
|
|
|
2008-07-30 09:07:32 +00:00
|
|
|
FontList::const_iterator fcit = fontlist_.begin();
|
|
|
|
FontList::const_iterator fend = fontlist_.end();
|
|
|
|
for (; fcit != fend; ++fcit) {
|
|
|
|
if (fcit->pos() < beg)
|
|
|
|
continue;
|
|
|
|
if (fcit->pos() >= end) {
|
|
|
|
// Add last entry in the fontlist_.
|
|
|
|
fontlist_.set(text_.size() - 1, fcit->font());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Add a new entry in the fontlist_.
|
|
|
|
fontlist_.set(fcit->pos() - beg, fcit->font());
|
|
|
|
}
|
2010-09-14 05:24:04 +00:00
|
|
|
requestSpellCheck(p.text_.size());
|
2008-07-30 09:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-13 10:06:48 +00:00
|
|
|
void Paragraph::addChangesToToc(DocIterator const & cdit, Buffer const & buf,
|
|
|
|
bool output_active, TocBackend & backend) const
|
2008-09-30 11:06:34 +00:00
|
|
|
{
|
2017-01-13 10:06:48 +00:00
|
|
|
d->changes_.addToToc(cdit, buf, output_active, backend);
|
2008-09-30 11:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-08-04 22:50:36 +00:00
|
|
|
bool Paragraph::isDeleted(pos_type start, pos_type end) const
|
2009-05-14 22:21:05 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(start >= 0 && start <= size(), return false);
|
|
|
|
LASSERT(end > start && end <= size() + 1, return false);
|
2009-05-14 22:21:05 +00:00
|
|
|
|
2009-08-04 22:50:36 +00:00
|
|
|
return d->changes_.isDeleted(start, end);
|
2009-05-14 22:21:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
bool Paragraph::isChanged(pos_type start, pos_type end) const
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(start >= 0 && start <= size(), return false);
|
|
|
|
LASSERT(end > start && end <= size() + 1, return false);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->changes_.isChanged(start, end);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
2020-03-06 09:53:54 +00:00
|
|
|
// FIXME: Ideally the diverse isChanged() methods should account for that!
|
|
|
|
bool Paragraph::hasChangedInsets(pos_type start, pos_type end) const
|
|
|
|
{
|
|
|
|
LASSERT(start >= 0 && start <= size(), return false);
|
|
|
|
LASSERT(end > start && end <= size() + 1, return false);
|
|
|
|
|
2020-03-16 06:12:16 +00:00
|
|
|
for (auto const & icit : d->insetlist_) {
|
2020-03-06 10:20:46 +00:00
|
|
|
if (icit.pos < start)
|
2020-03-06 09:53:54 +00:00
|
|
|
continue;
|
2020-03-06 10:20:46 +00:00
|
|
|
if (icit.pos >= end)
|
2020-03-06 09:53:54 +00:00
|
|
|
break;
|
2020-03-06 10:20:46 +00:00
|
|
|
if (icit.inset && icit.inset->isChanged())
|
2020-03-06 09:53:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2020-01-11 20:21:34 +00:00
|
|
|
bool Paragraph::isChanged() const
|
|
|
|
{
|
|
|
|
return d->changes_.isChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-12 21:38:51 +00:00
|
|
|
bool Paragraph::isMergedOnEndOfParDeletion(bool trackChanges) const
|
|
|
|
{
|
2007-04-24 10:01:03 +00:00
|
|
|
// keep the logic here in sync with the logic of eraseChars()
|
2008-01-12 21:38:51 +00:00
|
|
|
if (!trackChanges)
|
2007-04-24 10:01:03 +00:00
|
|
|
return true;
|
|
|
|
|
2015-02-24 09:17:45 +00:00
|
|
|
Change const & change = d->changes_.lookup(size());
|
2009-08-04 22:15:17 +00:00
|
|
|
return change.inserted() && change.currentAuthor();
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-26 12:47:50 +00:00
|
|
|
Change Paragraph::parEndChange() const
|
|
|
|
{
|
|
|
|
return d->changes_.lookup(size());
|
|
|
|
}
|
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
void Paragraph::setChange(Change const & change)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
|
|
|
// beware of the imaginary end-of-par character!
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.set(change, 0, size() + 1);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Propagate the change recursively - but not in case of DELETED!
|
|
|
|
*
|
|
|
|
* Imagine that your co-author makes changes in an existing inset. He
|
|
|
|
* sends your document to you and you come to the conclusion that the
|
|
|
|
* inset should go completely. If you erase it, LyX must not delete all
|
|
|
|
* text within the inset. Otherwise, the change tracked insertions of
|
|
|
|
* your co-author get lost and there is no way to restore them later.
|
|
|
|
*
|
|
|
|
* Conclusion: An inset's content should remain untouched if you delete it
|
|
|
|
*/
|
|
|
|
|
2009-08-04 22:15:17 +00:00
|
|
|
if (!change.deleted()) {
|
2007-04-24 10:01:03 +00:00
|
|
|
for (pos_type pos = 0; pos < size(); ++pos) {
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset * inset = getInset(pos))
|
|
|
|
inset->setChange(change);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
void Paragraph::setChange(pos_type pos, Change const & change)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(pos >= 0 && pos <= size(), return);
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.set(change, pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// see comment in setChange(Change const &) above
|
2009-08-04 22:15:17 +00:00
|
|
|
if (!change.deleted() && pos < size())
|
2020-01-13 08:21:32 +00:00
|
|
|
if (Inset * inset = getInset(pos))
|
|
|
|
inset->setChange(change);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
Change const & Paragraph::lookupChange(pos_type pos) const
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(pos >= 0 && pos <= size());
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->changes_.lookup(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-16 08:37:32 +00:00
|
|
|
void Paragraph::acceptChanges(pos_type start, pos_type end)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(start >= 0 && start <= size(), return);
|
|
|
|
LASSERT(end > start && end <= size() + 1, return);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
for (pos_type pos = start; pos < end; ++pos) {
|
|
|
|
switch (lookupChange(pos).type) {
|
|
|
|
case Change::UNCHANGED:
|
|
|
|
// accept changes in nested inset
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset * inset = getInset(pos))
|
2009-07-16 08:37:32 +00:00
|
|
|
inset->acceptChanges();
|
2007-04-24 10:01:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Change::INSERTED:
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.set(Change(Change::UNCHANGED), pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
// also accept changes in nested inset
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset * inset = getInset(pos))
|
2009-07-16 08:37:32 +00:00
|
|
|
inset->acceptChanges();
|
2007-04-24 10:01:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Change::DELETED:
|
|
|
|
// Suppress access to non-existent
|
|
|
|
// "end-of-paragraph char"
|
|
|
|
if (pos < size()) {
|
|
|
|
eraseChar(pos, false);
|
|
|
|
--end;
|
|
|
|
--pos;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-16 08:37:32 +00:00
|
|
|
void Paragraph::rejectChanges(pos_type start, pos_type end)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(start >= 0 && start <= size(), return);
|
|
|
|
LASSERT(end > start && end <= size() + 1, return);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
for (pos_type pos = start; pos < end; ++pos) {
|
|
|
|
switch (lookupChange(pos).type) {
|
|
|
|
case Change::UNCHANGED:
|
|
|
|
// reject changes in nested inset
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset * inset = getInset(pos))
|
2009-07-16 08:37:32 +00:00
|
|
|
inset->rejectChanges();
|
2007-04-24 10:01:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Change::INSERTED:
|
|
|
|
// Suppress access to non-existent
|
|
|
|
// "end-of-paragraph char"
|
|
|
|
if (pos < size()) {
|
|
|
|
eraseChar(pos, false);
|
|
|
|
--end;
|
|
|
|
--pos;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Change::DELETED:
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.set(Change(Change::UNCHANGED), pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// Do NOT reject changes within a deleted inset!
|
|
|
|
// There may be insertions of a co-author inside of it!
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
void Paragraph::Private::insertChar(pos_type pos, char_type c,
|
2007-10-19 08:57:22 +00:00
|
|
|
Change const & change)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(pos >= 0 && pos <= int(text_.size()), return);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// track change
|
|
|
|
changes_.insert(change, pos);
|
|
|
|
|
|
|
|
// This is actually very common when parsing buffers (and
|
|
|
|
// maybe inserting ascii text)
|
2007-10-31 07:48:13 +00:00
|
|
|
if (pos == pos_type(text_.size())) {
|
2007-04-24 10:01:03 +00:00
|
|
|
// when appending characters, no need to update tables
|
2007-10-24 07:08:55 +00:00
|
|
|
text_.push_back(c);
|
2010-09-14 05:24:04 +00:00
|
|
|
// but we want spell checking
|
|
|
|
requestSpellCheck(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
text_.insert(text_.begin() + pos, c);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// Update the font table.
|
2007-10-19 14:35:05 +00:00
|
|
|
fontlist_.increasePosAfterPos(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// Update the insets
|
2007-10-18 15:29:51 +00:00
|
|
|
insetlist_.increasePosAfterPos(pos);
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
// Update list of misspelled positions
|
|
|
|
speller_state_.increasePosAfterPos(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-08 14:03:15 +00:00
|
|
|
bool Paragraph::insertInset(pos_type pos, Inset * inset,
|
2013-05-19 10:39:01 +00:00
|
|
|
Font const & font, Change const & change)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(inset, return false);
|
|
|
|
LASSERT(pos >= 0 && pos <= size(), return false);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2008-10-08 14:03:15 +00:00
|
|
|
// Paragraph::insertInset() can be used in cut/copy/paste operation where
|
|
|
|
// d->inset_owner_ is not set yet.
|
2008-10-08 14:06:20 +00:00
|
|
|
if (d->inset_owner_ && !d->inset_owner_->insetAllowed(inset->lyxCode()))
|
2008-10-08 14:03:15 +00:00
|
|
|
return false;
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insertChar(pos, META_INSET, change);
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(d->text_[pos] == META_INSET, return false);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-18 15:29:51 +00:00
|
|
|
// Add a new entry in the insetlist_.
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insetlist_.insert(inset, pos);
|
2010-09-14 05:24:04 +00:00
|
|
|
|
|
|
|
// Some insets require run of spell checker
|
|
|
|
requestSpellCheck(pos);
|
2013-05-19 10:39:01 +00:00
|
|
|
setFont(pos, font);
|
2008-10-08 14:03:15 +00:00
|
|
|
return true;
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
bool Paragraph::eraseChar(pos_type pos, bool trackChanges)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2008-09-15 16:07:53 +00:00
|
|
|
LASSERT(pos >= 0 && pos <= size(), return false);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// keep the logic here in sync with the logic of isMergedOnEndOfParDeletion()
|
|
|
|
|
|
|
|
if (trackChanges) {
|
2007-10-19 08:57:22 +00:00
|
|
|
Change change = d->changes_.lookup(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-05-28 22:27:45 +00:00
|
|
|
// set the character to DELETED if
|
2007-04-24 10:01:03 +00:00
|
|
|
// a) it was previously unchanged or
|
|
|
|
// b) it was inserted by a co-author
|
|
|
|
|
2009-08-04 22:15:17 +00:00
|
|
|
if (!change.changed() ||
|
|
|
|
(change.inserted() && !change.currentAuthor())) {
|
2007-04-24 10:01:03 +00:00
|
|
|
setChange(pos, Change(Change::DELETED));
|
2010-09-29 19:32:41 +00:00
|
|
|
// request run of spell checker
|
|
|
|
requestSpellCheck(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-08-04 22:15:17 +00:00
|
|
|
if (change.deleted())
|
2007-04-24 10:01:03 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't physically access the imaginary end-of-paragraph character.
|
|
|
|
// eraseChar() can only mark it as DELETED. A physical deletion of
|
|
|
|
// end-of-par must be handled externally.
|
|
|
|
if (pos == size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// track change
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.erase(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// if it is an inset, delete the inset entry
|
2007-10-24 07:08:55 +00:00
|
|
|
if (d->text_[pos] == META_INSET)
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insetlist_.erase(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
d->text_.erase(d->text_.begin() + pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-19 14:35:05 +00:00
|
|
|
// Update the fontlist_
|
|
|
|
d->fontlist_.erase(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-18 15:29:51 +00:00
|
|
|
// Update the insetlist_
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insetlist_.decreasePosAfterPos(pos);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
// Update list of misspelled positions
|
|
|
|
d->speller_state_.decreasePosAfterPos(pos);
|
2010-10-12 19:05:47 +00:00
|
|
|
d->speller_state_.refreshLast(size());
|
2010-09-14 05:24:04 +00:00
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-19 08:57:22 +00:00
|
|
|
int Paragraph::eraseChars(pos_type start, pos_type end, bool trackChanges)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(start >= 0 && start <= size(), return 0);
|
|
|
|
LASSERT(end >= start && end <= size() + 1, return 0);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
pos_type i = start;
|
|
|
|
for (pos_type count = end - start; count; --count) {
|
|
|
|
if (!eraseChar(i, trackChanges))
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return end - i;
|
|
|
|
}
|
|
|
|
|
2020-11-28 21:43:00 +00:00
|
|
|
|
2019-03-02 17:58:53 +00:00
|
|
|
// Handle combining characters
|
2018-04-22 17:06:46 +00:00
|
|
|
int Paragraph::Private::latexSurrogatePair(BufferParams const & bparams,
|
|
|
|
otexstream & os, char_type c, char_type next,
|
|
|
|
OutputParams const & runparams)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
|
|
|
// Writing next here may circumvent a possible font change between
|
|
|
|
// c and next. Since next is only output if it forms a surrogate pair
|
|
|
|
// with c we can ignore this:
|
|
|
|
// A font change inside a surrogate pair does not make sense and is
|
|
|
|
// hopefully impossible to input.
|
|
|
|
// FIXME: change tracking
|
|
|
|
// Is this correct WRT change tracking?
|
2009-07-16 06:19:25 +00:00
|
|
|
Encoding const & encoding = *(runparams.encoding);
|
2012-08-21 10:48:34 +00:00
|
|
|
docstring latex1 = encoding.latexChar(next).first;
|
|
|
|
if (runparams.inIPA) {
|
|
|
|
string const tipashortcut = Encodings::TIPAShortcut(next);
|
|
|
|
if (!tipashortcut.empty()) {
|
|
|
|
latex1 = from_ascii(tipashortcut);
|
|
|
|
}
|
|
|
|
}
|
2018-04-20 16:01:16 +00:00
|
|
|
docstring latex2 = encoding.latexChar(c).first;
|
|
|
|
|
2019-03-11 14:24:22 +00:00
|
|
|
if (bparams.useNonTeXFonts || docstring(1, next) == latex1) {
|
|
|
|
// Encoding supports the combination:
|
2019-01-11 09:08:49 +00:00
|
|
|
// output as is (combining char after base char).
|
|
|
|
os << latex2 << latex1;
|
|
|
|
return latex1.length() + latex2.length();
|
|
|
|
}
|
|
|
|
|
2019-03-11 14:24:22 +00:00
|
|
|
os << latex1 << "{" << latex2 << "}";
|
|
|
|
return latex1.length() + latex2.length() + 2;
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-22 17:06:46 +00:00
|
|
|
bool Paragraph::Private::simpleTeXBlanks(BufferParams const & bparams,
|
|
|
|
OutputParams const & runparams,
|
2011-02-10 20:02:48 +00:00
|
|
|
otexstream & os,
|
2007-10-22 13:09:16 +00:00
|
|
|
pos_type i,
|
2007-04-24 10:01:03 +00:00
|
|
|
unsigned int & column,
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const & font,
|
2007-04-29 18:58:28 +00:00
|
|
|
Layout const & style)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2010-08-07 22:07:49 +00:00
|
|
|
if (style.pass_thru || runparams.pass_thru)
|
2007-04-24 10:01:03 +00:00
|
|
|
return false;
|
|
|
|
|
2007-10-24 09:46:38 +00:00
|
|
|
if (i + 1 < int(text_.size())) {
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type next = text_[i + 1];
|
2007-04-24 10:01:03 +00:00
|
|
|
if (Encodings::isCombiningChar(next)) {
|
|
|
|
// This space has an accent, so we must always output it.
|
2018-04-22 17:06:46 +00:00
|
|
|
column += latexSurrogatePair(bparams, os, ' ', next, runparams) - 1;
|
2007-04-24 10:01:03 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-02 23:46:04 +00:00
|
|
|
if (runparams.linelen > 0
|
|
|
|
&& column > runparams.linelen
|
2007-04-24 10:01:03 +00:00
|
|
|
&& i
|
2007-10-24 07:08:55 +00:00
|
|
|
&& text_[i - 1] != ' '
|
2007-10-24 09:46:38 +00:00
|
|
|
&& (i + 1 < int(text_.size()))
|
2007-04-24 10:01:03 +00:00
|
|
|
// same in FreeSpacing mode
|
|
|
|
&& !owner_->isFreeSpacing()
|
|
|
|
// In typewriter mode, we want to avoid
|
|
|
|
// ! . ? : at the end of a line
|
2007-10-28 18:51:54 +00:00
|
|
|
&& !(font.fontInfo().family() == TYPEWRITER_FAMILY
|
2007-10-24 07:08:55 +00:00
|
|
|
&& (text_[i - 1] == '.'
|
|
|
|
|| text_[i - 1] == '?'
|
|
|
|
|| text_[i - 1] == ':'
|
|
|
|
|| text_[i - 1] == '!'))) {
|
2007-04-24 10:01:03 +00:00
|
|
|
os << '\n';
|
2011-02-10 20:02:48 +00:00
|
|
|
os.texrow().start(owner_->id(), i + 1);
|
2007-04-24 10:01:03 +00:00
|
|
|
column = 0;
|
|
|
|
} else if (style.free_spacing) {
|
|
|
|
os << '~';
|
|
|
|
} else {
|
|
|
|
os << ' ';
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-07 22:07:49 +00:00
|
|
|
void Paragraph::Private::latexInset(BufferParams const & bparams,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
otexstream & os,
|
2010-08-07 22:07:49 +00:00
|
|
|
OutputParams & runparams,
|
|
|
|
Font & running_font,
|
|
|
|
Font & basefont,
|
|
|
|
Font const & outerfont,
|
|
|
|
bool & open_font,
|
|
|
|
Change & running_change,
|
|
|
|
Layout const & style,
|
|
|
|
pos_type & i,
|
2020-08-15 10:26:07 +00:00
|
|
|
unsigned int & column,
|
2020-08-16 08:47:08 +00:00
|
|
|
bool const fontswitch_inset,
|
|
|
|
bool const closeLanguage,
|
|
|
|
bool const lang_switched_at_inset)
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2007-10-22 13:09:16 +00:00
|
|
|
Inset * inset = owner_->getInset(i);
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(inset);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2013-04-08 09:07:02 +00:00
|
|
|
if (style.pass_thru) {
|
2013-03-08 19:52:18 +00:00
|
|
|
odocstringstream ods;
|
|
|
|
inset->plaintext(ods, runparams);
|
|
|
|
os << ods.str();
|
2007-10-20 08:09:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
// FIXME: move this to InsetNewline::latex
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
if (inset->lyxCode() == NEWLINE_CODE || inset->lyxCode() == SEPARATOR_CODE) {
|
2007-10-20 08:09:55 +00:00
|
|
|
// newlines are handled differently here than
|
|
|
|
// the default in simpleTeXSpecialChars().
|
|
|
|
if (!style.newline_allowed) {
|
|
|
|
os << '\n';
|
|
|
|
} else {
|
|
|
|
if (open_font) {
|
2017-06-03 15:26:05 +00:00
|
|
|
bool needPar = false;
|
2007-10-20 08:09:55 +00:00
|
|
|
column += running_font.latexWriteEndChanges(
|
|
|
|
os, bparams, runparams,
|
2017-06-03 15:26:05 +00:00
|
|
|
basefont, basefont, needPar);
|
2007-10-20 08:09:55 +00:00
|
|
|
open_font = false;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-28 18:51:54 +00:00
|
|
|
if (running_font.fontInfo().family() == TYPEWRITER_FAMILY)
|
2007-10-20 08:09:55 +00:00
|
|
|
os << '~';
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
basefont = owner_->getLayoutFont(bparams, outerfont);
|
|
|
|
running_font = basefont;
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
if (runparams.moving_arg)
|
|
|
|
os << "\\protect ";
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
}
|
2011-02-10 20:02:48 +00:00
|
|
|
os.texrow().start(owner_->id(), i + 1);
|
2007-10-20 08:09:55 +00:00
|
|
|
column = 0;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2009-08-04 23:01:06 +00:00
|
|
|
if (owner_->isDeleted(i)) {
|
2007-10-20 08:09:55 +00:00
|
|
|
if( ++runparams.inDeletedInset == 1)
|
|
|
|
runparams.changeOfDeletedInset = owner_->lookupChange(i);
|
|
|
|
}
|
2007-07-21 18:10:55 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
if (inset->canTrackChanges()) {
|
|
|
|
column += Changes::latexMarkChange(os, bparams, running_change,
|
2009-10-12 16:22:05 +00:00
|
|
|
Change(Change::UNCHANGED), runparams);
|
2007-10-20 08:09:55 +00:00
|
|
|
running_change = Change(Change::UNCHANGED);
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
bool close = false;
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
odocstream::pos_type const len = os.os().tellp();
|
2007-10-20 08:09:55 +00:00
|
|
|
|
2019-08-05 14:30:01 +00:00
|
|
|
if (inset->forceLTR(runparams)
|
2007-11-05 23:44:47 +00:00
|
|
|
&& running_font.isRightToLeft()
|
2009-07-16 10:08:13 +00:00
|
|
|
// ERT is an exception, it should be output with no
|
|
|
|
// decorations at all
|
|
|
|
&& inset->lyxCode() != ERT_CODE) {
|
2018-09-28 06:36:44 +00:00
|
|
|
if (runparams.use_polyglossia) {
|
2018-10-09 16:04:51 +00:00
|
|
|
os << "\\LRE{";
|
2018-09-28 06:36:44 +00:00
|
|
|
} else if (running_font.language()->lang() == "farsi"
|
|
|
|
|| running_font.language()->lang() == "arabic_arabi")
|
|
|
|
os << "\\textLR{" << termcmd;
|
2007-10-20 08:09:55 +00:00
|
|
|
else
|
2008-11-18 10:40:22 +00:00
|
|
|
os << "\\L{";
|
2007-10-20 08:09:55 +00:00
|
|
|
close = true;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2020-08-16 09:18:49 +00:00
|
|
|
if (open_font && fontswitch_inset) {
|
2020-08-14 07:08:46 +00:00
|
|
|
bool lang_closed = false;
|
|
|
|
// Close language if needed
|
2020-08-17 11:11:46 +00:00
|
|
|
if (closeLanguage && !lang_switched_at_inset) {
|
2020-08-14 07:08:46 +00:00
|
|
|
// We need prev_font here as language changes directly at inset
|
|
|
|
// will only be started inside the inset.
|
|
|
|
Font const prev_font = (i > 0) ?
|
|
|
|
owner_->getFont(bparams, i - 1, outerfont)
|
|
|
|
: running_font;
|
|
|
|
Font tmpfont(basefont);
|
|
|
|
tmpfont.setLanguage(prev_font.language());
|
|
|
|
bool needPar = false;
|
|
|
|
unsigned int count = tmpfont.latexWriteEndChanges(os, bparams, runparams,
|
|
|
|
basefont, basefont,
|
|
|
|
needPar, closeLanguage);
|
|
|
|
column += count;
|
|
|
|
lang_closed = count > 0;
|
|
|
|
}
|
|
|
|
// Update the running_font, making sure, however,
|
|
|
|
// to leave the language as it was.
|
|
|
|
// FIXME: probably a better way to keep track of the old
|
|
|
|
// language, than copying the entire font?
|
|
|
|
Font const copy_font(running_font);
|
|
|
|
basefont = owner_->getLayoutFont(bparams, outerfont);
|
|
|
|
running_font = basefont;
|
2020-08-15 13:21:19 +00:00
|
|
|
if (!closeLanguage)
|
2020-08-14 07:08:46 +00:00
|
|
|
running_font.setLanguage(copy_font.language());
|
2020-08-15 17:20:30 +00:00
|
|
|
OutputParams rp = runparams;
|
|
|
|
rp.encoding = basefont.language()->encoding();
|
2020-08-14 07:08:46 +00:00
|
|
|
// For these, we use switches, so they should be taken as
|
|
|
|
// base inside the inset.
|
|
|
|
basefont.fontInfo().setSize(copy_font.fontInfo().size());
|
|
|
|
basefont.fontInfo().setFamily(copy_font.fontInfo().family());
|
|
|
|
basefont.fontInfo().setSeries(copy_font.fontInfo().series());
|
2020-08-15 05:06:20 +00:00
|
|
|
// Now re-do font changes in a way needed here
|
|
|
|
// (using switches with multi-par insets)
|
|
|
|
InsetText const * textinset = inset->asInsetText();
|
|
|
|
bool const cprotect = textinset
|
|
|
|
? textinset->hasCProtectContent(runparams.moving_arg)
|
|
|
|
&& !textinset->text().isMainText()
|
|
|
|
: false;
|
|
|
|
unsigned int count2 = basefont.latexWriteStartChanges(os, bparams,
|
2020-08-15 17:20:30 +00:00
|
|
|
rp, running_font,
|
2020-08-15 13:21:19 +00:00
|
|
|
basefont, true,
|
2020-08-15 05:06:20 +00:00
|
|
|
cprotect);
|
2020-08-16 08:47:46 +00:00
|
|
|
open_font = true;
|
2020-08-15 05:06:20 +00:00
|
|
|
column += count2;
|
2020-08-14 07:08:46 +00:00
|
|
|
if (count2 == 0 && (lang_closed || lang_switched_at_inset))
|
|
|
|
// All fonts closed
|
|
|
|
open_font = false;
|
|
|
|
if (closeLanguage)
|
|
|
|
runparams.local_font = &basefont;
|
2007-10-20 08:09:55 +00:00
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2020-10-01 10:34:15 +00:00
|
|
|
if (fontswitch_inset && !closeLanguage) {
|
2020-08-17 11:25:02 +00:00
|
|
|
// The directionality has been switched at inset.
|
|
|
|
// Force markup inside.
|
|
|
|
runparams.local_font = &basefont;
|
|
|
|
}
|
|
|
|
|
2016-09-04 02:21:19 +00:00
|
|
|
size_t const previous_row_count = os.texrow().rows();
|
2008-05-31 20:54:50 +00:00
|
|
|
|
|
|
|
try {
|
2011-03-12 01:40:01 +00:00
|
|
|
runparams.lastid = id_;
|
|
|
|
runparams.lastpos = i;
|
2011-02-10 20:02:48 +00:00
|
|
|
inset->latex(os, runparams);
|
2008-05-31 20:54:50 +00:00
|
|
|
} catch (EncodingException & e) {
|
|
|
|
// add location information and throw again.
|
|
|
|
e.par_id = id_;
|
|
|
|
e.pos = i;
|
2020-10-09 17:42:51 +00:00
|
|
|
throw;
|
2008-05-31 20:54:50 +00:00
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2018-10-13 11:51:00 +00:00
|
|
|
if (close)
|
|
|
|
os << '}';
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2016-09-04 02:21:19 +00:00
|
|
|
if (os.texrow().rows() > previous_row_count) {
|
2011-02-10 20:02:48 +00:00
|
|
|
os.texrow().start(owner_->id(), i + 1);
|
2007-10-20 08:09:55 +00:00
|
|
|
column = 0;
|
|
|
|
} else {
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
column += (unsigned int)(os.os().tellp() - len);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
|
2009-08-04 23:01:06 +00:00
|
|
|
if (owner_->isDeleted(i))
|
2007-10-20 08:09:55 +00:00
|
|
|
--runparams.inDeletedInset;
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
void Paragraph::Private::latexSpecialChar(otexstream & os,
|
2012-07-23 12:56:00 +00:00
|
|
|
BufferParams const & bparams,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
OutputParams const & runparams,
|
|
|
|
Font const & running_font,
|
2019-03-11 14:24:22 +00:00
|
|
|
string & alien_script,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
Layout const & style,
|
|
|
|
pos_type & i,
|
2011-02-12 11:03:24 +00:00
|
|
|
pos_type end_pos,
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
unsigned int & column)
|
2007-10-20 08:09:55 +00:00
|
|
|
{
|
2018-07-15 12:26:29 +00:00
|
|
|
char_type const c = owner_->getUChar(bparams, runparams, i);
|
2007-10-22 13:09:16 +00:00
|
|
|
|
2015-04-20 16:13:49 +00:00
|
|
|
if (style.pass_thru || runparams.pass_thru
|
|
|
|
|| contains(style.pass_thru_chars, c)
|
|
|
|
|| contains(runparams.pass_thru_chars, c)) {
|
2011-02-27 12:16:17 +00:00
|
|
|
if (c != '\0') {
|
|
|
|
Encoding const * const enc = runparams.encoding;
|
2012-03-25 13:36:00 +00:00
|
|
|
if (enc && !enc->encodable(c))
|
2011-02-27 12:16:17 +00:00
|
|
|
throw EncodingException(c);
|
2007-10-22 13:09:16 +00:00
|
|
|
os.put(c);
|
2011-02-27 12:16:17 +00:00
|
|
|
}
|
2007-10-22 13:09:16 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-03-09 11:14:39 +00:00
|
|
|
// TIPA uses its own T3 encoding
|
|
|
|
if (runparams.inIPA && latexSpecialT3(c, os, i, column))
|
|
|
|
return;
|
2008-11-21 14:58:26 +00:00
|
|
|
// If T1 font encoding is used, use the special
|
|
|
|
// characters it provides.
|
2015-07-15 16:55:30 +00:00
|
|
|
// NOTE: Some languages reset the font encoding internally to a
|
|
|
|
// non-standard font encoding. If we are using such a language,
|
|
|
|
// we do not output special T1 chars.
|
2012-03-09 11:14:39 +00:00
|
|
|
if (!runparams.inIPA && !running_font.language()->internalFontEncoding()
|
2017-02-25 11:49:49 +00:00
|
|
|
&& !runparams.isFullUnicode() && bparams.main_font_encoding() == "T1"
|
2017-02-15 07:35:46 +00:00
|
|
|
&& latexSpecialT1(c, os, i, column))
|
2007-10-23 09:53:06 +00:00
|
|
|
return;
|
2019-03-16 11:59:34 +00:00
|
|
|
// NOTE: "fontspec" (non-TeX fonts) sets the font encoding to "TU" (untill 2017 "EU1" or "EU2")
|
2017-02-23 09:17:52 +00:00
|
|
|
else if (!runparams.inIPA && !running_font.language()->internalFontEncoding()
|
|
|
|
&& runparams.isFullUnicode() && latexSpecialTU(c, os, i, column))
|
|
|
|
return;
|
2007-10-23 09:53:06 +00:00
|
|
|
|
|
|
|
// Otherwise, we use what LaTeX provides us.
|
2007-10-20 08:09:55 +00:00
|
|
|
switch (c) {
|
|
|
|
case '\\':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textbackslash" << termcmd;
|
2007-10-20 08:09:55 +00:00
|
|
|
column += 15;
|
|
|
|
break;
|
|
|
|
case '<':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textless" << termcmd;
|
2007-10-23 09:53:06 +00:00
|
|
|
column += 10;
|
|
|
|
break;
|
2007-10-20 08:09:55 +00:00
|
|
|
case '>':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textgreater" << termcmd;
|
2007-10-23 09:53:06 +00:00
|
|
|
column += 13;
|
2007-10-20 08:09:55 +00:00
|
|
|
break;
|
2007-10-23 09:53:06 +00:00
|
|
|
case '|':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textbar" << termcmd;
|
2007-10-23 09:53:06 +00:00
|
|
|
column += 9;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
os << '-';
|
2016-04-24 18:12:43 +00:00
|
|
|
if (i + 1 < static_cast<pos_type>(text_.size()) &&
|
|
|
|
(end_pos == -1 || i + 1 < end_pos) &&
|
|
|
|
text_[i+1] == '-') {
|
2018-01-02 08:28:04 +00:00
|
|
|
// Prevent "--" becoming an en dash and "---" an em dash.
|
|
|
|
// (Within \ttfamily, "---" is merged to en dash + hyphen.)
|
2015-02-24 20:58:27 +00:00
|
|
|
os << "{}";
|
|
|
|
column += 2;
|
|
|
|
}
|
2007-10-20 08:09:55 +00:00
|
|
|
break;
|
|
|
|
case '\"':
|
2017-08-09 15:25:02 +00:00
|
|
|
os << "\\textquotedbl" << termcmd;
|
|
|
|
column += 14;
|
2007-10-20 08:09:55 +00:00
|
|
|
break;
|
|
|
|
|
2018-12-06 13:18:24 +00:00
|
|
|
case '$': case '&':
|
|
|
|
case '%': case '#': case '{':
|
|
|
|
case '}': case '_':
|
2007-10-20 08:09:55 +00:00
|
|
|
os << '\\';
|
|
|
|
os.put(c);
|
|
|
|
column += 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '~':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textasciitilde" << termcmd;
|
2007-10-20 08:09:55 +00:00
|
|
|
column += 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '^':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textasciicircum" << termcmd;
|
2007-10-20 08:09:55 +00:00
|
|
|
column += 17;
|
|
|
|
break;
|
|
|
|
|
2008-12-10 19:52:13 +00:00
|
|
|
case '*':
|
|
|
|
case '[':
|
|
|
|
case ']':
|
2007-10-20 08:09:55 +00:00
|
|
|
// avoid being mistaken for optional arguments
|
|
|
|
os << '{';
|
|
|
|
os.put(c);
|
|
|
|
os << '}';
|
|
|
|
column += 2;
|
|
|
|
break;
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-20 08:09:55 +00:00
|
|
|
case ' ':
|
|
|
|
// Blanks are printed before font switching.
|
|
|
|
// Sure? I am not! (try nice-latex)
|
|
|
|
// I am sure it's correct. LyX might be smarter
|
|
|
|
// in the future, but for now, nothing wrong is
|
|
|
|
// written. (Asger)
|
|
|
|
break;
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2017-03-19 19:50:34 +00:00
|
|
|
case 0x2013:
|
|
|
|
case 0x2014:
|
2017-12-16 15:11:25 +00:00
|
|
|
// XeTeX's dash behaviour is determined via a global setting
|
|
|
|
if (bparams.use_dash_ligatures
|
|
|
|
&& owner_->getFontSettings(bparams, i).fontInfo().family() != TYPEWRITER_FAMILY
|
2018-01-29 07:37:25 +00:00
|
|
|
&& !runparams.inIPA
|
2018-01-10 14:31:32 +00:00
|
|
|
// TODO #10961: && not in inset Flex Code
|
|
|
|
// TODO #10961: && not in layout LyXCode
|
2020-11-30 22:00:40 +00:00
|
|
|
&& (!bparams.useNonTeXFonts || runparams.flavor != Flavor::XeTeX)) {
|
2017-03-19 19:50:34 +00:00
|
|
|
if (c == 0x2013) {
|
|
|
|
// en-dash
|
|
|
|
os << "--";
|
|
|
|
column +=2;
|
|
|
|
} else {
|
|
|
|
// em-dash
|
|
|
|
os << "---";
|
|
|
|
column +=3;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall through
|
2007-10-20 08:09:55 +00:00
|
|
|
default:
|
2007-10-23 09:53:06 +00:00
|
|
|
if (c == '\0')
|
|
|
|
return;
|
|
|
|
|
|
|
|
Encoding const & encoding = *(runparams.encoding);
|
2012-03-09 09:05:13 +00:00
|
|
|
char_type next = '\0';
|
2007-10-24 09:46:38 +00:00
|
|
|
if (i + 1 < int(text_.size())) {
|
2012-03-09 09:05:13 +00:00
|
|
|
next = text_[i + 1];
|
2007-10-23 09:53:06 +00:00
|
|
|
if (Encodings::isCombiningChar(next)) {
|
2018-04-22 17:06:46 +00:00
|
|
|
column += latexSurrogatePair(bparams, os, c, next, runparams) - 1;
|
2007-10-23 09:53:06 +00:00
|
|
|
++i;
|
2007-04-24 10:01:03 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-10-20 08:09:55 +00:00
|
|
|
}
|
2012-03-25 13:36:00 +00:00
|
|
|
pair<docstring, bool> latex = encoding.latexChar(c);
|
2012-03-09 09:05:13 +00:00
|
|
|
docstring nextlatex;
|
2012-05-26 14:36:24 +00:00
|
|
|
bool nexttipas = false;
|
|
|
|
string nexttipashortcut;
|
2019-03-11 14:24:22 +00:00
|
|
|
if (next != '\0' && next != META_INSET && !encoding.encodable(next)) {
|
2012-03-25 13:36:00 +00:00
|
|
|
nextlatex = encoding.latexChar(next).first;
|
2012-05-26 14:36:24 +00:00
|
|
|
if (runparams.inIPA) {
|
|
|
|
nexttipashortcut = Encodings::TIPAShortcut(next);
|
|
|
|
nexttipas = !nexttipashortcut.empty();
|
|
|
|
}
|
|
|
|
}
|
2012-03-09 09:05:13 +00:00
|
|
|
bool tipas = false;
|
|
|
|
if (runparams.inIPA) {
|
|
|
|
string const tipashortcut = Encodings::TIPAShortcut(c);
|
|
|
|
if (!tipashortcut.empty()) {
|
2012-03-25 13:36:00 +00:00
|
|
|
latex.first = from_ascii(tipashortcut);
|
|
|
|
latex.second = false;
|
2012-03-09 09:05:13 +00:00
|
|
|
tipas = true;
|
|
|
|
}
|
|
|
|
}
|
2019-03-11 14:24:22 +00:00
|
|
|
// eventually close "script wrapper" command (see `Paragraph::latex`)
|
|
|
|
if (!alien_script.empty()
|
|
|
|
&& alien_script != Encodings::isKnownScriptChar(next)) {
|
|
|
|
column += latex.first.length();
|
|
|
|
alien_script.clear();
|
|
|
|
os << latex.first << "}";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (latex.second
|
2012-05-26 14:36:24 +00:00
|
|
|
&& ((!prefixIs(nextlatex, '\\')
|
|
|
|
&& !prefixIs(nextlatex, '{')
|
|
|
|
&& !prefixIs(nextlatex, '}'))
|
|
|
|
|| (nexttipas
|
|
|
|
&& !prefixIs(from_ascii(nexttipashortcut), '\\')))
|
2012-03-25 13:36:00 +00:00
|
|
|
&& !tipas) {
|
2019-03-11 14:24:22 +00:00
|
|
|
// Prevent eating of a following space or command corruption by
|
2007-10-23 09:53:06 +00:00
|
|
|
// following characters
|
2012-03-09 09:05:13 +00:00
|
|
|
if (next == ' ' || next == '\0') {
|
2012-03-25 13:36:00 +00:00
|
|
|
column += latex.first.length() + 1;
|
|
|
|
os << latex.first << "{}";
|
2012-03-09 09:05:13 +00:00
|
|
|
} else {
|
2012-03-25 13:36:00 +00:00
|
|
|
column += latex.first.length();
|
|
|
|
os << latex.first << " ";
|
2012-03-09 09:05:13 +00:00
|
|
|
}
|
2007-10-23 09:53:06 +00:00
|
|
|
} else {
|
2012-03-25 13:36:00 +00:00
|
|
|
column += latex.first.length() - 1;
|
|
|
|
os << latex.first;
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
2007-10-20 08:09:55 +00:00
|
|
|
break;
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
bool Paragraph::Private::latexSpecialT1(char_type const c, otexstream & os,
|
2020-10-21 08:35:40 +00:00
|
|
|
pos_type i, unsigned int & column) const
|
2007-10-23 09:53:06 +00:00
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '>':
|
|
|
|
case '<':
|
|
|
|
os.put(c);
|
|
|
|
// In T1 encoding, these characters exist
|
|
|
|
// but we should avoid ligatures
|
2007-12-14 14:52:52 +00:00
|
|
|
if (i + 1 >= int(text_.size()) || text_[i + 1] != c)
|
2007-10-23 09:53:06 +00:00
|
|
|
return true;
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textcompwordmark" << termcmd;
|
2008-07-04 06:01:45 +00:00
|
|
|
column += 19;
|
2007-10-23 09:53:06 +00:00
|
|
|
return true;
|
|
|
|
case '|':
|
|
|
|
os.put(c);
|
|
|
|
return true;
|
2008-08-19 08:51:56 +00:00
|
|
|
case '\"':
|
|
|
|
// soul.sty breaks with \char`\"
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textquotedbl" << termcmd;
|
2008-08-19 08:51:56 +00:00
|
|
|
column += 14;
|
|
|
|
return true;
|
2007-10-23 09:53:06 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-23 09:17:52 +00:00
|
|
|
bool Paragraph::Private::latexSpecialTU(char_type const c, otexstream & os,
|
2020-10-21 08:35:40 +00:00
|
|
|
pos_type i, unsigned int & column) const
|
2017-02-23 09:17:52 +00:00
|
|
|
{
|
|
|
|
// TU encoding is currently on par with T1.
|
|
|
|
return latexSpecialT1(c, os, i, column);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-09 11:14:39 +00:00
|
|
|
bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os,
|
2020-10-21 08:35:40 +00:00
|
|
|
pos_type /*i*/, unsigned int & column) const
|
2012-03-09 11:14:39 +00:00
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '*':
|
|
|
|
case '[':
|
|
|
|
case ']':
|
|
|
|
case '\"':
|
|
|
|
os.put(c);
|
|
|
|
return true;
|
2012-08-19 14:59:53 +00:00
|
|
|
case '|':
|
2016-12-16 09:20:25 +00:00
|
|
|
os << "\\textvertline" << termcmd;
|
2012-08-19 14:59:53 +00:00
|
|
|
column += 14;
|
|
|
|
return true;
|
2012-03-09 11:14:39 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-17 22:18:28 +00:00
|
|
|
void Paragraph::Private::validate(LaTeXFeatures & features) const
|
2007-04-24 10:01:03 +00:00
|
|
|
{
|
2009-12-01 14:34:05 +00:00
|
|
|
if (layout_->inpreamble && inset_owner_) {
|
2017-12-26 12:11:00 +00:00
|
|
|
// FIXME: Using a string stream here circumvents the encoding
|
2010-11-28 12:27:52 +00:00
|
|
|
// switching machinery of odocstream. Therefore the
|
|
|
|
// output is wrong if this paragraph contains content
|
|
|
|
// that needs to switch encoding.
|
2018-01-11 12:43:35 +00:00
|
|
|
Buffer const & buf = inset_owner_->buffer();
|
2016-09-25 10:38:53 +00:00
|
|
|
otexstringstream os;
|
2017-02-18 09:40:42 +00:00
|
|
|
os << layout_->preamble();
|
2016-09-25 10:38:53 +00:00
|
|
|
size_t const length = os.length();
|
2019-04-20 15:51:06 +00:00
|
|
|
TeXOnePar(buf, *inset_owner_->getText(int(buf.getParFromID(owner_->id()).idx())),
|
|
|
|
buf.getParFromID(owner_->id()).pit(), os,
|
2017-12-26 12:11:00 +00:00
|
|
|
features.runparams(), string(), 0, -1, true);
|
|
|
|
if (os.length() > length)
|
2016-09-25 10:38:53 +00:00
|
|
|
features.addPreambleSnippet(os.release(), true);
|
2009-12-01 14:34:05 +00:00
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2020-11-30 22:00:40 +00:00
|
|
|
if (features.runparams().flavor == Flavor::Html
|
2010-01-19 19:43:15 +00:00
|
|
|
&& layout_->htmltitle()) {
|
2012-04-26 14:29:58 +00:00
|
|
|
features.setHTMLTitle(owner_->asString(AS_STR_INSETS | AS_STR_SKIPDELETE));
|
2010-01-19 19:43:15 +00:00
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2007-04-24 10:01:03 +00:00
|
|
|
// check the params.
|
2007-10-19 08:57:22 +00:00
|
|
|
if (!params_.spacing().isDefault())
|
2007-04-24 10:01:03 +00:00
|
|
|
features.require("setspace");
|
|
|
|
|
|
|
|
// then the layouts
|
2009-11-17 22:18:28 +00:00
|
|
|
features.useLayout(layout_->name());
|
2007-04-24 10:01:03 +00:00
|
|
|
|
|
|
|
// then the fonts
|
2007-10-19 16:01:32 +00:00
|
|
|
fontlist_.validate(features);
|
2007-04-24 10:01:03 +00:00
|
|
|
|
2007-10-19 16:01:32 +00:00
|
|
|
// then the indentation
|
2007-10-19 08:57:22 +00:00
|
|
|
if (!params_.leftIndent().zero())
|
2007-04-24 10:01:03 +00:00
|
|
|
features.require("ParagraphLeftIndent");
|
|
|
|
|
|
|
|
// then the insets
|
2007-10-18 15:29:51 +00:00
|
|
|
InsetList::const_iterator icit = insetlist_.begin();
|
|
|
|
InsetList::const_iterator iend = insetlist_.end();
|
2007-04-24 10:01:03 +00:00
|
|
|
for (; icit != iend; ++icit) {
|
2008-11-29 00:23:21 +00:00
|
|
|
if (icit->inset) {
|
2016-10-17 01:25:35 +00:00
|
|
|
features.inDeletedInset(owner_->isDeleted(icit->pos));
|
2017-11-19 07:59:48 +00:00
|
|
|
if (icit->inset->lyxCode() == FOOT_CODE) {
|
|
|
|
// FIXME: an item inset would make things much easier.
|
|
|
|
if ((layout_->latextype == LATEX_LIST_ENVIRONMENT
|
|
|
|
|| (layout_->latextype == LATEX_ITEM_ENVIRONMENT
|
|
|
|
&& layout_->margintype == MARGIN_FIRST_DYNAMIC))
|
|
|
|
&& (icit->pos < begin_of_body_
|
|
|
|
|| (icit->pos == begin_of_body_
|
|
|
|
&& (icit->pos == 0 || text_[icit->pos - 1] != ' '))))
|
|
|
|
features.saveNoteEnv("description");
|
|
|
|
}
|
2007-04-24 10:01:03 +00:00
|
|
|
icit->inset->validate(features);
|
2016-10-17 01:25:35 +00:00
|
|
|
features.inDeletedInset(false);
|
2009-11-17 22:18:28 +00:00
|
|
|
if (layout_->needprotect &&
|
2007-10-13 09:04:52 +00:00
|
|
|
icit->inset->lyxCode() == FOOT_CODE)
|
2016-01-26 20:33:46 +00:00
|
|
|
features.require("NeedLyXFootnoteCode");
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// then the contents
|
2018-01-11 12:43:35 +00:00
|
|
|
BufferParams const bp = features.runparams().is_child
|
|
|
|
? features.buffer().masterParams() : features.buffer().params();
|
2007-10-24 09:46:38 +00:00
|
|
|
for (pos_type i = 0; i < int(text_.size()) ; ++i) {
|
2017-08-09 15:25:02 +00:00
|
|
|
char_type c = text_[i];
|
2018-04-28 11:31:29 +00:00
|
|
|
CharInfo const & ci = Encodings::unicodeCharInfo(c);
|
2017-08-09 15:25:02 +00:00
|
|
|
if (c == 0x0022) {
|
|
|
|
if (features.runparams().isFullUnicode() && bp.useNonTeXFonts)
|
|
|
|
features.require("textquotedblp");
|
2017-08-10 09:47:52 +00:00
|
|
|
else if (bp.main_font_encoding() != "T1"
|
|
|
|
|| ((&owner_->getFontSettings(bp, i))->language()->internalFontEncoding()))
|
2017-08-09 15:25:02 +00:00
|
|
|
features.require("textquotedbl");
|
2018-04-28 11:31:29 +00:00
|
|
|
} else if (ci.textfeature() && contains(ci.textpreamble(), '=')) {
|
|
|
|
// features that depend on the font or input encoding
|
|
|
|
string feats = ci.textpreamble();
|
2018-04-22 17:06:46 +00:00
|
|
|
string fontenc = (&owner_->getFontSettings(bp, i))->language()->fontenc(bp);
|
2018-04-22 08:08:07 +00:00
|
|
|
if (fontenc.empty())
|
|
|
|
fontenc = features.runparams().main_fontenc;
|
2018-04-28 11:31:29 +00:00
|
|
|
while (!feats.empty()) {
|
|
|
|
string feat;
|
|
|
|
feats = split(feats, feat, ',');
|
|
|
|
if (contains(feat, "!=")) {
|
|
|
|
// a feature that is required except for the spcified
|
|
|
|
// font or input encodings
|
|
|
|
string realfeature;
|
|
|
|
string const contexts = ltrim(split(feat, realfeature, '!'), "=");
|
|
|
|
// multiple encodings are separated by semicolon
|
|
|
|
vector<string> context = getVectorFromString(contexts, ";");
|
|
|
|
// require feature if the context matches neither current font
|
|
|
|
// nor input encoding
|
|
|
|
if (std::find(context.begin(), context.end(), fontenc) == context.end()
|
|
|
|
&& std::find(context.begin(), context.end(),
|
|
|
|
features.runparams().encoding->name()) == context.end())
|
|
|
|
features.require(realfeature);
|
|
|
|
} else if (contains(feat, '=')) {
|
|
|
|
// a feature that is required only for the spcified
|
|
|
|
// font or input encodings
|
|
|
|
string realfeature;
|
|
|
|
string const contexts = split(feat, realfeature, '=');
|
|
|
|
// multiple encodings are separated by semicolon
|
|
|
|
vector<string> context = getVectorFromString(contexts, ";");
|
|
|
|
// require feature if the context matches either current font
|
|
|
|
// or input encoding
|
|
|
|
if (std::find(context.begin(), context.end(), fontenc) != context.end()
|
|
|
|
|| std::find(context.begin(), context.end(),
|
|
|
|
features.runparams().encoding->name()) != context.end())
|
|
|
|
features.require(realfeature);
|
|
|
|
}
|
|
|
|
}
|
2018-04-22 08:08:07 +00:00
|
|
|
} else if (!bp.use_dash_ligatures
|
|
|
|
&& (c == 0x2013 || c == 0x2014)
|
|
|
|
&& bp.useNonTeXFonts
|
2020-11-30 22:00:40 +00:00
|
|
|
&& features.runparams().flavor == Flavor::XeTeX)
|
2017-12-16 15:11:25 +00:00
|
|
|
// XeTeX's dash behaviour is determined via a global setting
|
|
|
|
features.require("xetexdashbreakstate");
|
2017-08-09 15:25:02 +00:00
|
|
|
BufferEncodings::validate(c, features);
|
2007-04-24 10:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Paragraph
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
2008-03-06 21:31:27 +00:00
|
|
|
namespace {
|
|
|
|
Layout const emptyParagraphLayout;
|
|
|
|
}
|
|
|
|
|
2010-09-14 14:00:29 +00:00
|
|
|
Paragraph::Paragraph()
|
2008-03-06 21:31:27 +00:00
|
|
|
: d(new Paragraph::Private(this, emptyParagraphLayout))
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2001-06-25 00:06:33 +00:00
|
|
|
itemdepth = 0;
|
2007-10-19 08:57:22 +00:00
|
|
|
d->params_.clear();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-13 13:43:44 +00:00
|
|
|
Paragraph::Paragraph(Paragraph const & par)
|
2007-10-24 07:08:55 +00:00
|
|
|
: itemdepth(par.itemdepth),
|
2007-10-19 08:57:22 +00:00
|
|
|
d(new Paragraph::Private(*par.d, this))
|
2001-05-08 10:50:09 +00:00
|
|
|
{
|
2008-02-26 13:07:59 +00:00
|
|
|
registerWords();
|
2001-05-08 10:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-30 09:07:32 +00:00
|
|
|
Paragraph::Paragraph(Paragraph const & par, pos_type beg, pos_type end)
|
|
|
|
: itemdepth(par.itemdepth),
|
|
|
|
d(new Paragraph::Private(*par.d, this, beg, end))
|
|
|
|
{
|
|
|
|
registerWords();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-19 16:36:52 +00:00
|
|
|
Paragraph & Paragraph::operator=(Paragraph const & par)
|
2003-06-04 07:14:05 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
// needed as we will destroy the private part before copying it
|
2004-03-19 16:36:52 +00:00
|
|
|
if (&par != this) {
|
|
|
|
itemdepth = par.itemdepth;
|
|
|
|
|
2008-02-26 13:07:59 +00:00
|
|
|
deregisterWords();
|
2007-10-19 08:57:22 +00:00
|
|
|
delete d;
|
|
|
|
d = new Private(*par.d, this);
|
2008-02-26 13:07:59 +00:00
|
|
|
registerWords();
|
2004-03-19 16:36:52 +00:00
|
|
|
}
|
|
|
|
return *this;
|
2003-06-04 07:14:05 +00:00
|
|
|
}
|
|
|
|
|
2003-11-13 13:43:44 +00:00
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
Paragraph::~Paragraph()
|
2001-05-08 10:50:09 +00:00
|
|
|
{
|
2008-02-26 13:07:59 +00:00
|
|
|
deregisterWords();
|
2007-10-19 08:57:22 +00:00
|
|
|
delete d;
|
2001-05-08 10:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-10-23 16:48:55 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
// this shall be called just before every "os << ..." action.
|
|
|
|
void flushString(ostream & os, docstring & s)
|
|
|
|
{
|
|
|
|
os << to_utf8(s);
|
|
|
|
s.erase();
|
|
|
|
}
|
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace
|
2009-10-23 16:48:55 +00:00
|
|
|
|
|
|
|
|
2008-02-27 20:43:16 +00:00
|
|
|
void Paragraph::write(ostream & os, BufferParams const & bparams,
|
2020-10-31 17:18:51 +00:00
|
|
|
depth_type & depth) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2001-05-08 13:28:44 +00:00
|
|
|
// The beginning or end of a deeper (i.e. nested) area?
|
2020-10-31 17:18:51 +00:00
|
|
|
if (depth != d->params_.depth()) {
|
|
|
|
if (d->params_.depth() > depth) {
|
|
|
|
while (d->params_.depth() > depth) {
|
2004-08-16 11:27:51 +00:00
|
|
|
os << "\n\\begin_deeper";
|
2020-10-31 17:18:51 +00:00
|
|
|
++depth;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
2001-05-08 13:28:44 +00:00
|
|
|
} else {
|
2020-10-31 17:18:51 +00:00
|
|
|
while (d->params_.depth() < depth) {
|
2004-08-16 11:27:51 +00:00
|
|
|
os << "\n\\end_deeper";
|
2020-10-31 17:18:51 +00:00
|
|
|
--depth;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
}
|
2001-05-08 13:28:44 +00:00
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2001-05-08 13:28:44 +00:00
|
|
|
// First write the layout
|
2008-03-06 22:06:24 +00:00
|
|
|
os << "\n\\begin_layout " << to_utf8(d->layout_->name()) << '\n';
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2008-02-20 10:21:00 +00:00
|
|
|
d->params_.write(os);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2007-10-28 18:51:54 +00:00
|
|
|
Font font1(inherit_font, bparams.language);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2003-02-08 19:18:01 +00:00
|
|
|
Change running_change = Change(Change::UNCHANGED);
|
2003-03-03 21:15:49 +00:00
|
|
|
|
2009-10-23 16:48:55 +00:00
|
|
|
// this string is used as a buffer to avoid repetitive calls
|
|
|
|
// to to_utf8(), which turn out to be expensive (JMarc)
|
|
|
|
docstring write_buffer;
|
|
|
|
|
2000-07-15 23:51:46 +00:00
|
|
|
int column = 0;
|
2006-03-11 13:31:41 +00:00
|
|
|
for (pos_type i = 0; i <= size(); ++i) {
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2015-02-24 09:17:45 +00:00
|
|
|
Change const & change = lookupChange(i);
|
2009-10-23 16:48:55 +00:00
|
|
|
if (change != running_change)
|
|
|
|
flushString(os, write_buffer);
|
2009-07-23 20:08:05 +00:00
|
|
|
Changes::lyxMarkChange(os, bparams, column, running_change, change);
|
2003-02-08 19:18:01 +00:00
|
|
|
running_change = change;
|
2003-03-03 21:15:49 +00:00
|
|
|
|
2006-03-11 13:31:41 +00:00
|
|
|
if (i == size())
|
|
|
|
break;
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
// Write font changes
|
2009-06-19 15:32:51 +00:00
|
|
|
Font font2 = getFontSettings(bparams, i);
|
1999-09-27 18:44:28 +00:00
|
|
|
if (font2 != font1) {
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2001-08-11 18:31:14 +00:00
|
|
|
font2.lyxWriteChanges(font1, os);
|
1999-09-27 18:44:28 +00:00
|
|
|
column = 0;
|
|
|
|
font1 = font2;
|
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type const c = d->text_[i];
|
1999-09-27 18:44:28 +00:00
|
|
|
switch (c) {
|
1999-11-15 12:01:38 +00:00
|
|
|
case META_INSET:
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset const * inset = getInset(i)) {
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2001-06-28 10:25:20 +00:00
|
|
|
if (inset->directWrite()) {
|
1999-09-27 18:44:28 +00:00
|
|
|
// international char, let it write
|
|
|
|
// code directly so it's shorter in
|
|
|
|
// the file
|
2008-02-27 20:43:16 +00:00
|
|
|
inset->write(os);
|
1999-09-27 18:44:28 +00:00
|
|
|
} else {
|
2005-01-06 16:52:08 +00:00
|
|
|
if (i)
|
|
|
|
os << '\n';
|
|
|
|
os << "\\begin_inset ";
|
2008-02-27 20:43:16 +00:00
|
|
|
inset->write(os);
|
2004-08-16 11:27:51 +00:00
|
|
|
os << "\n\\end_inset\n\n";
|
1999-09-27 18:44:28 +00:00
|
|
|
column = 0;
|
|
|
|
}
|
2014-06-29 19:40:17 +00:00
|
|
|
// FIXME This can be removed again once the mystery
|
|
|
|
// crash has been resolved.
|
|
|
|
os << flush;
|
2008-02-09 10:41:49 +00:00
|
|
|
}
|
|
|
|
break;
|
1999-12-07 00:44:53 +00:00
|
|
|
case '\\':
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2004-08-16 11:27:51 +00:00
|
|
|
os << "\n\\backslash\n";
|
1999-09-27 18:44:28 +00:00
|
|
|
column = 0;
|
|
|
|
break;
|
|
|
|
case '.':
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2007-10-24 07:08:55 +00:00
|
|
|
if (i + 1 < size() && d->text_[i + 1] == ' ') {
|
1999-12-07 00:44:53 +00:00
|
|
|
os << ".\n";
|
1999-11-04 01:40:20 +00:00
|
|
|
column = 0;
|
|
|
|
} else
|
2002-11-27 10:30:28 +00:00
|
|
|
os << '.';
|
1999-09-27 18:44:28 +00:00
|
|
|
break;
|
|
|
|
default:
|
1999-11-15 12:01:38 +00:00
|
|
|
if ((column > 70 && c == ' ')
|
2000-02-29 02:19:17 +00:00
|
|
|
|| column > 79) {
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2002-11-27 10:30:28 +00:00
|
|
|
os << '\n';
|
1999-09-27 18:44:28 +00:00
|
|
|
column = 0;
|
|
|
|
}
|
|
|
|
// this check is to amend a bug. LyX sometimes
|
|
|
|
// inserts '\0' this could cause problems.
|
2008-01-14 23:44:05 +00:00
|
|
|
if (c != '\0')
|
2009-10-23 16:48:55 +00:00
|
|
|
write_buffer.push_back(c);
|
2008-01-14 23:44:05 +00:00
|
|
|
else
|
2008-04-07 20:43:02 +00:00
|
|
|
LYXERR0("NUL char in structure.");
|
2000-01-24 18:34:46 +00:00
|
|
|
++column;
|
1999-09-27 18:44:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2003-02-08 19:18:01 +00:00
|
|
|
|
2009-10-23 16:48:55 +00:00
|
|
|
flushString(os, write_buffer);
|
2003-07-27 21:39:54 +00:00
|
|
|
os << "\n\\end_layout\n";
|
2014-06-03 17:35:18 +00:00
|
|
|
// FIXME This can be removed again once the mystery
|
|
|
|
// crash has been resolved.
|
|
|
|
os << flush;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
void Paragraph::validate(LaTeXFeatures & features) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2009-11-17 22:18:28 +00:00
|
|
|
d->validate(features);
|
2018-04-30 07:06:15 +00:00
|
|
|
bool fragile = features.runparams().moving_arg;
|
|
|
|
fragile |= layout().needprotect;
|
2019-04-21 14:44:29 +00:00
|
|
|
if (inInset().getLayout().isNeedProtect())
|
|
|
|
fragile = true;
|
2018-04-30 07:06:15 +00:00
|
|
|
if (needsCProtection(fragile))
|
2018-04-13 15:46:37 +00:00
|
|
|
features.require("cprotect");
|
2003-02-08 19:18:01 +00:00
|
|
|
}
|
|
|
|
|
2003-03-03 21:15:49 +00:00
|
|
|
|
2020-10-31 17:18:51 +00:00
|
|
|
void Paragraph::insert(pos_type pos, docstring const & str,
|
2007-05-28 22:27:45 +00:00
|
|
|
Font const & font, Change const & change)
|
2003-11-04 12:01:15 +00:00
|
|
|
{
|
2005-07-16 12:02:31 +00:00
|
|
|
for (size_t i = 0, n = str.size(); i != n ; ++i)
|
2020-10-31 17:18:51 +00:00
|
|
|
insertChar(pos + i, str[i], font, change);
|
2003-11-04 12:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
void Paragraph::appendChar(char_type c, Font const & font,
|
2007-10-22 13:09:16 +00:00
|
|
|
Change const & change)
|
|
|
|
{
|
|
|
|
// track change
|
2007-10-24 07:08:55 +00:00
|
|
|
d->changes_.insert(change, d->text_.size());
|
2007-10-22 13:09:16 +00:00
|
|
|
// when appending characters, no need to update tables
|
2007-10-24 07:08:55 +00:00
|
|
|
d->text_.push_back(c);
|
|
|
|
setFont(d->text_.size() - 1, font);
|
2011-08-20 13:51:38 +00:00
|
|
|
d->requestSpellCheck(d->text_.size() - 1);
|
2007-10-22 13:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Paragraph::appendString(docstring const & s, Font const & font,
|
|
|
|
Change const & change)
|
|
|
|
{
|
2007-10-31 07:48:13 +00:00
|
|
|
pos_type end = s.size();
|
2007-10-24 07:08:55 +00:00
|
|
|
size_t oldsize = d->text_.size();
|
2007-10-22 20:05:41 +00:00
|
|
|
size_t newsize = oldsize + end;
|
2007-10-24 07:08:55 +00:00
|
|
|
size_t capacity = d->text_.capacity();
|
2007-10-22 20:05:41 +00:00
|
|
|
if (newsize >= capacity)
|
2007-12-12 19:28:07 +00:00
|
|
|
d->text_.reserve(max(capacity + 100, newsize));
|
2007-10-22 20:05:41 +00:00
|
|
|
|
2007-10-24 09:01:51 +00:00
|
|
|
// when appending characters, no need to update tables
|
|
|
|
d->text_.append(s);
|
|
|
|
|
2007-10-22 13:09:16 +00:00
|
|
|
// FIXME: Optimize this!
|
2008-11-16 12:08:29 +00:00
|
|
|
for (size_t i = oldsize; i != newsize; ++i) {
|
2007-10-22 13:09:16 +00:00
|
|
|
// track change
|
|
|
|
d->changes_.insert(change, i);
|
2011-08-20 13:51:38 +00:00
|
|
|
d->requestSpellCheck(i);
|
2007-10-22 13:09:16 +00:00
|
|
|
}
|
2007-10-29 12:21:58 +00:00
|
|
|
d->fontlist_.set(oldsize, font);
|
|
|
|
d->fontlist_.set(newsize - 1, font);
|
2007-10-22 13:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
void Paragraph::insertChar(pos_type pos, char_type c,
|
2007-05-28 22:27:45 +00:00
|
|
|
bool trackChanges)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insertChar(pos, c, Change(trackChanges ?
|
2007-05-28 22:27:45 +00:00
|
|
|
Change::INSERTED : Change::UNCHANGED));
|
2006-10-20 11:44:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
void Paragraph::insertChar(pos_type pos, char_type c,
|
2007-05-28 22:27:45 +00:00
|
|
|
Font const & font, bool trackChanges)
|
2006-10-20 11:44:58 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insertChar(pos, c, Change(trackChanges ?
|
2007-05-28 22:27:45 +00:00
|
|
|
Change::INSERTED : Change::UNCHANGED));
|
2006-10-20 11:44:58 +00:00
|
|
|
setFont(pos, font);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
1999-11-15 12:01:38 +00:00
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
void Paragraph::insertChar(pos_type pos, char_type c,
|
2007-05-28 22:27:45 +00:00
|
|
|
Font const & font, Change const & change)
|
2000-06-28 13:35:52 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
d->insertChar(pos, c, change);
|
2004-08-05 15:14:29 +00:00
|
|
|
setFont(pos, font);
|
2000-06-28 13:35:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-28 18:51:54 +00:00
|
|
|
void Paragraph::resetFonts(Font const & font)
|
|
|
|
{
|
2007-10-29 12:21:58 +00:00
|
|
|
d->fontlist_.clear();
|
|
|
|
d->fontlist_.set(0, font);
|
|
|
|
d->fontlist_.set(d->text_.size() - 1, font);
|
2007-10-28 18:51:54 +00:00
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
// Gets uninstantiated font setting at position.
|
2008-10-19 07:03:44 +00:00
|
|
|
Font const & Paragraph::getFontSettings(BufferParams const & bparams,
|
2002-03-21 17:27:08 +00:00
|
|
|
pos_type pos) const
|
2001-04-04 21:47:26 +00:00
|
|
|
{
|
2004-02-20 11:00:41 +00:00
|
|
|
if (pos > size()) {
|
2008-04-07 20:43:02 +00:00
|
|
|
LYXERR0("pos: " << pos << " size: " << size());
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(false);
|
2004-02-20 11:00:41 +00:00
|
|
|
}
|
2002-03-13 18:23:38 +00:00
|
|
|
|
2007-10-19 15:42:53 +00:00
|
|
|
FontList::const_iterator cit = d->fontlist_.fontIterator(pos);
|
|
|
|
if (cit != d->fontlist_.end())
|
2003-07-28 12:51:24 +00:00
|
|
|
return cit->font();
|
2001-07-27 12:03:36 +00:00
|
|
|
|
2003-07-28 12:51:24 +00:00
|
|
|
if (pos == size() && !empty())
|
|
|
|
return getFontSettings(bparams, pos - 1);
|
|
|
|
|
2008-10-19 07:03:44 +00:00
|
|
|
// Optimisation: avoid a full font instantiation if there is no
|
|
|
|
// language change from previous call.
|
|
|
|
static Font previous_font;
|
2020-03-16 06:12:16 +00:00
|
|
|
static Language const * previous_lang = nullptr;
|
2008-10-19 07:03:44 +00:00
|
|
|
Language const * lang = getParLanguage(bparams);
|
|
|
|
if (lang != previous_lang) {
|
|
|
|
previous_lang = lang;
|
|
|
|
previous_font = Font(inherit_font, lang);
|
|
|
|
}
|
|
|
|
return previous_font;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2003-07-28 12:51:24 +00:00
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
FontSpan Paragraph::fontSpan(pos_type pos) const
|
2003-07-27 10:42:11 +00:00
|
|
|
{
|
2016-03-25 09:16:33 +00:00
|
|
|
LBUFERR(pos <= size());
|
|
|
|
|
|
|
|
if (pos == size())
|
|
|
|
return FontSpan(pos, pos);
|
2013-04-27 18:00:15 +00:00
|
|
|
|
|
|
|
pos_type start = 0;
|
2007-10-19 08:57:22 +00:00
|
|
|
FontList::const_iterator cit = d->fontlist_.begin();
|
|
|
|
FontList::const_iterator end = d->fontlist_.end();
|
2005-06-10 14:55:01 +00:00
|
|
|
for (; cit != end; ++cit) {
|
2005-11-07 11:28:11 +00:00
|
|
|
if (cit->pos() >= pos) {
|
|
|
|
if (pos >= beginOfBody())
|
2007-12-12 19:28:07 +00:00
|
|
|
return FontSpan(max(start, beginOfBody()),
|
2005-11-07 11:28:11 +00:00
|
|
|
cit->pos());
|
|
|
|
else
|
2006-04-05 23:56:29 +00:00
|
|
|
return FontSpan(start,
|
2007-12-12 19:28:07 +00:00
|
|
|
min(beginOfBody() - 1,
|
2005-11-07 11:28:11 +00:00
|
|
|
cit->pos()));
|
|
|
|
}
|
2005-06-10 14:55:01 +00:00
|
|
|
start = cit->pos() + 1;
|
|
|
|
}
|
2003-07-28 12:51:24 +00:00
|
|
|
|
2003-07-27 10:42:11 +00:00
|
|
|
// This should not happen, but if so, we take no chances.
|
2013-04-27 18:00:15 +00:00
|
|
|
LYXERR0("Paragraph::fontSpan: position not found in fontinfo table!");
|
|
|
|
LASSERT(false, return FontSpan(pos, pos));
|
2003-07-27 10:42:11 +00:00
|
|
|
}
|
|
|
|
|
2000-12-29 12:48:02 +00:00
|
|
|
|
2000-03-17 10:14:46 +00:00
|
|
|
// Gets uninstantiated font setting at position 0
|
2008-10-19 07:03:44 +00:00
|
|
|
Font const & Paragraph::getFirstFontSettings(BufferParams const & bparams) const
|
2000-03-17 10:14:46 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
if (!empty() && !d->fontlist_.empty())
|
2007-10-19 14:35:05 +00:00
|
|
|
return d->fontlist_.begin()->font();
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2008-10-19 07:03:44 +00:00
|
|
|
// Optimisation: avoid a full font instantiation if there is no
|
|
|
|
// language change from previous call.
|
|
|
|
static Font previous_font;
|
2020-03-16 06:12:16 +00:00
|
|
|
static Language const * previous_lang = nullptr;
|
2008-10-19 07:03:44 +00:00
|
|
|
if (bparams.language != previous_lang) {
|
|
|
|
previous_lang = bparams.language;
|
|
|
|
previous_font = Font(inherit_font, bparams.language);
|
|
|
|
}
|
|
|
|
|
|
|
|
return previous_font;
|
2000-03-17 10:14:46 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2000-06-08 23:16:16 +00:00
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
// Gets the fully instantiated font at a given position in a paragraph
|
2007-04-29 23:33:02 +00:00
|
|
|
// This is basically the same function as Text::GetFont() in text2.cpp.
|
1999-09-27 18:44:28 +00:00
|
|
|
// The difference is that this one is used for generating the LaTeX file,
|
|
|
|
// and thus cosmetic "improvements" are disallowed: This has to deliver
|
|
|
|
// the true picture of the buffer. (Asger)
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
|
|
|
|
Font const & outerfont) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(pos >= 0);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2007-08-18 13:08:36 +00:00
|
|
|
Font font = getFontSettings(bparams, pos);
|
2002-06-24 20:28:12 +00:00
|
|
|
|
2003-11-13 13:43:44 +00:00
|
|
|
pos_type const body_pos = beginOfBody();
|
2008-10-19 07:42:41 +00:00
|
|
|
FontInfo & fi = font.fontInfo();
|
2003-03-09 12:37:22 +00:00
|
|
|
if (pos < body_pos)
|
2008-10-19 07:42:41 +00:00
|
|
|
fi.realize(d->layout_->labelfont);
|
2001-08-03 18:28:11 +00:00
|
|
|
else
|
2008-10-19 07:42:41 +00:00
|
|
|
fi.realize(d->layout_->font);
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2008-10-19 07:42:41 +00:00
|
|
|
fi.realize(outerfont.fontInfo());
|
|
|
|
fi.realize(bparams.getFont().fontInfo());
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2003-10-21 16:15:14 +00:00
|
|
|
return font;
|
2001-08-03 18:28:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const Paragraph::getLabelFont
|
|
|
|
(BufferParams const & bparams, Font const & outerfont) const
|
2001-08-03 18:28:11 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
FontInfo tmpfont = d->layout_->labelfont;
|
2007-10-28 23:32:18 +00:00
|
|
|
tmpfont.realize(outerfont.fontInfo());
|
|
|
|
tmpfont.realize(bparams.getFont().fontInfo());
|
|
|
|
return Font(tmpfont, getParLanguage(bparams));
|
2001-08-03 18:28:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const Paragraph::getLayoutFont
|
|
|
|
(BufferParams const & bparams, Font const & outerfont) const
|
2001-08-03 18:28:11 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
FontInfo tmpfont = d->layout_->font;
|
2007-10-28 18:51:54 +00:00
|
|
|
tmpfont.realize(outerfont.fontInfo());
|
|
|
|
tmpfont.realize(bparams.getFont().fontInfo());
|
|
|
|
return Font(tmpfont, getParLanguage(bparams));
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-15 12:26:29 +00:00
|
|
|
char_type Paragraph::getUChar(BufferParams const & bparams,
|
|
|
|
OutputParams const & rp,
|
|
|
|
pos_type pos) const
|
2001-02-11 09:58:20 +00:00
|
|
|
{
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type c = d->text_[pos];
|
2018-07-15 12:26:29 +00:00
|
|
|
|
2018-10-30 11:33:35 +00:00
|
|
|
// Return unchanged character in LTR languages
|
2019-07-11 06:25:18 +00:00
|
|
|
// or if we use poylglossia/bidi (XeTeX).
|
2019-07-11 08:31:10 +00:00
|
|
|
if (rp.useBidiPackage()
|
2019-07-11 06:25:18 +00:00
|
|
|
|| !getFontSettings(bparams, pos).isRightToLeft())
|
2001-02-11 09:58:20 +00:00
|
|
|
return c;
|
|
|
|
|
2018-10-30 11:33:35 +00:00
|
|
|
// Without polyglossia/bidi, we need to account for some special cases.
|
|
|
|
// FIXME This needs to be audited!
|
|
|
|
// Check if:
|
|
|
|
// * The input is as expected for all delimiters
|
|
|
|
// => checked for Hebrew!
|
|
|
|
// * The output matches the display in the LyX workarea
|
|
|
|
// => checked for Hebrew!
|
|
|
|
// * The special cases below are really necessary
|
|
|
|
// => checked for Hebrew!
|
|
|
|
// * In arabic_arabi, brackets are transformed to Arabic
|
|
|
|
// Ornate Parentheses. Is this is really wanted?
|
2018-07-15 12:26:29 +00:00
|
|
|
|
2018-10-30 11:33:35 +00:00
|
|
|
string const & lang = getFontSettings(bparams, pos).language()->lang();
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type uc = c;
|
2018-07-15 12:26:29 +00:00
|
|
|
|
2018-10-30 11:33:35 +00:00
|
|
|
// 1. In the following languages, parentheses need to be reversed.
|
2019-07-11 06:25:18 +00:00
|
|
|
// Also with polyglodia/luabidi
|
|
|
|
bool const reverseparens = (lang == "hebrew" || rp.use_polyglossia);
|
2018-10-30 11:33:35 +00:00
|
|
|
|
|
|
|
// 2. In the following languages, brackets don't need to be reversed.
|
2018-07-15 12:26:29 +00:00
|
|
|
bool const reversebrackets = lang != "arabic_arabtex"
|
|
|
|
&& lang != "arabic_arabi"
|
2018-10-30 11:33:35 +00:00
|
|
|
&& lang != "farsi";
|
2018-07-15 12:26:29 +00:00
|
|
|
|
2018-10-30 11:33:35 +00:00
|
|
|
// Now swap delimiters if needed.
|
2001-02-11 09:58:20 +00:00
|
|
|
switch (c) {
|
2018-10-30 11:33:35 +00:00
|
|
|
case '(':
|
|
|
|
if (reverseparens)
|
|
|
|
uc = ')';
|
|
|
|
break;
|
|
|
|
case ')':
|
|
|
|
if (reverseparens)
|
|
|
|
uc = '(';
|
|
|
|
break;
|
2001-02-11 09:58:20 +00:00
|
|
|
case '[':
|
2018-07-15 12:26:29 +00:00
|
|
|
if (reversebrackets)
|
|
|
|
uc = ']';
|
2001-02-11 09:58:20 +00:00
|
|
|
break;
|
|
|
|
case ']':
|
2018-07-15 12:26:29 +00:00
|
|
|
if (reversebrackets)
|
|
|
|
uc = '[';
|
2001-02-11 09:58:20 +00:00
|
|
|
break;
|
|
|
|
case '{':
|
|
|
|
uc = '}';
|
|
|
|
break;
|
|
|
|
case '}':
|
|
|
|
uc = '{';
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
uc = '>';
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
uc = '<';
|
|
|
|
break;
|
|
|
|
}
|
2012-07-23 12:56:00 +00:00
|
|
|
|
|
|
|
return uc;
|
2001-02-11 09:58:20 +00:00
|
|
|
}
|
|
|
|
|
2001-04-04 21:47:26 +00:00
|
|
|
|
2007-04-29 18:17:15 +00:00
|
|
|
void Paragraph::setFont(pos_type pos, Font const & font)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2013-04-25 21:27:10 +00:00
|
|
|
LASSERT(pos <= size(), return);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2000-01-11 01:59:00 +00:00
|
|
|
// First, reduce font against layout/label font
|
2007-04-26 04:41:58 +00:00
|
|
|
// Update: The setCharFont() routine in text2.cpp already
|
2000-01-11 01:59:00 +00:00
|
|
|
// reduces font, so we don't need to do that here. (Asger)
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2007-10-19 14:35:05 +00:00
|
|
|
d->fontlist_.set(pos, font);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2001-03-09 00:56:42 +00:00
|
|
|
|
2003-04-29 10:56:15 +00:00
|
|
|
void Paragraph::makeSameLayout(Paragraph const & par)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
d->layout_ = par.d->layout_;
|
2008-02-20 10:21:00 +00:00
|
|
|
d->params_ = par.d->params_;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-01-21 21:11:27 +00:00
|
|
|
bool Paragraph::stripLeadingSpaces(bool trackChanges)
|
2000-05-26 16:13:01 +00:00
|
|
|
{
|
2003-06-07 17:45:43 +00:00
|
|
|
if (isFreeSpacing())
|
2007-02-20 08:34:04 +00:00
|
|
|
return false;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2007-01-14 18:27:27 +00:00
|
|
|
int pos = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
while (pos < size() && (isNewline(pos) || isLineSeparator(pos))) {
|
|
|
|
if (eraseChar(pos, trackChanges))
|
|
|
|
++count;
|
|
|
|
else
|
|
|
|
++pos;
|
2000-05-26 16:13:01 +00:00
|
|
|
}
|
2001-04-27 07:19:08 +00:00
|
|
|
|
2007-02-20 08:34:04 +00:00
|
|
|
return count > 0 || pos > 0;
|
2000-05-26 16:13:01 +00:00
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2003-04-29 10:56:15 +00:00
|
|
|
bool Paragraph::hasSameLayout(Paragraph const & par) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
return par.d->layout_ == d->layout_
|
2008-03-06 21:31:27 +00:00
|
|
|
&& d->params_.sameLayout(par.d->params_);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
1999-11-15 12:01:38 +00:00
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
depth_type Paragraph::getDepth() const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.depth();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
depth_type Paragraph::getMaxDepthAfter() const
|
2002-02-28 15:07:11 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
if (d->layout_->isEnvironment())
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.depth() + 1;
|
2002-02-28 15:07:11 +00:00
|
|
|
else
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.depth();
|
2002-02-28 15:07:11 +00:00
|
|
|
}
|
|
|
|
|
2003-03-11 16:38:37 +00:00
|
|
|
|
2019-07-10 12:50:08 +00:00
|
|
|
LyXAlignment Paragraph::getAlign(BufferParams const & bparams) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-02-20 10:21:00 +00:00
|
|
|
if (d->params_.align() == LYX_ALIGN_LAYOUT)
|
2019-07-10 12:50:08 +00:00
|
|
|
return getDefaultAlign(bparams);
|
2006-12-17 10:11:28 +00:00
|
|
|
else
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.align();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-10 12:50:08 +00:00
|
|
|
LyXAlignment Paragraph::getDefaultAlign(BufferParams const & bparams) const
|
|
|
|
{
|
|
|
|
LyXAlignment res = layout().align;
|
|
|
|
if (isRTL(bparams)) {
|
|
|
|
// Swap sides
|
|
|
|
if (res == LYX_ALIGN_LEFT)
|
|
|
|
res = LYX_ALIGN_RIGHT;
|
|
|
|
else if (res == LYX_ALIGN_RIGHT)
|
|
|
|
res = LYX_ALIGN_LEFT;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-23 16:45:38 +00:00
|
|
|
docstring const & Paragraph::labelString() const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.labelString();
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-01-11 01:59:00 +00:00
|
|
|
// the next two functions are for the manual labels
|
2006-10-20 19:26:23 +00:00
|
|
|
docstring const Paragraph::getLabelWidthString() const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2009-05-25 08:13:56 +00:00
|
|
|
if (d->layout_->margintype == MARGIN_MANUAL
|
|
|
|
|| d->layout_->latextype == LATEX_BIB_ENVIRONMENT)
|
2008-02-20 10:21:00 +00:00
|
|
|
return d->params_.labelWidthString();
|
1999-09-27 18:44:28 +00:00
|
|
|
else
|
2006-10-20 19:26:23 +00:00
|
|
|
return _("Senseless with this layout!");
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-20 19:26:23 +00:00
|
|
|
void Paragraph::setLabelWidthString(docstring const & s)
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-02-20 10:21:00 +00:00
|
|
|
d->params_.labelWidthString(s);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-14 14:00:29 +00:00
|
|
|
docstring Paragraph::expandLabel(Layout const & layout,
|
2010-01-21 18:46:20 +00:00
|
|
|
BufferParams const & bparams) const
|
2010-09-14 14:00:29 +00:00
|
|
|
{
|
|
|
|
return expandParagraphLabel(layout, bparams, true);
|
2010-01-21 18:46:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
docstring Paragraph::expandParagraphLabel(Layout const & layout,
|
2007-01-15 16:58:14 +00:00
|
|
|
BufferParams const & bparams, bool process_appendix) const
|
|
|
|
{
|
2008-02-28 01:42:02 +00:00
|
|
|
DocumentClass const & tclass = bparams.documentClass();
|
2009-07-12 20:09:53 +00:00
|
|
|
string const & lang = getParLanguage(bparams)->code();
|
2009-07-12 22:14:49 +00:00
|
|
|
bool const in_appendix = process_appendix && d->params_.appendix();
|
|
|
|
docstring fmt = translateIfPossible(layout.labelstring(in_appendix), lang);
|
2007-01-15 16:58:14 +00:00
|
|
|
|
2013-02-09 16:09:56 +00:00
|
|
|
if (fmt.empty() && !layout.counter.empty())
|
2009-07-12 20:09:53 +00:00
|
|
|
return tclass.counters().theCounter(layout.counter, lang);
|
2007-08-16 11:12:56 +00:00
|
|
|
|
2007-01-15 16:58:14 +00:00
|
|
|
// handle 'inherited level parts' in 'fmt',
|
|
|
|
// i.e. the stuff between '@' in '@Section@.\arabic{subsection}'
|
|
|
|
size_t const i = fmt.find('@', 0);
|
|
|
|
if (i != docstring::npos) {
|
|
|
|
size_t const j = fmt.find('@', i + 1);
|
|
|
|
if (j != docstring::npos) {
|
|
|
|
docstring parent(fmt, i + 1, j - i - 1);
|
2007-10-03 16:57:01 +00:00
|
|
|
docstring label = from_ascii("??");
|
2007-10-03 02:39:11 +00:00
|
|
|
if (tclass.hasLayout(parent))
|
2015-09-20 18:32:45 +00:00
|
|
|
label = expandParagraphLabel(tclass[parent], bparams,
|
2007-08-16 11:12:56 +00:00
|
|
|
process_appendix);
|
2010-09-14 14:00:29 +00:00
|
|
|
fmt = docstring(fmt, 0, i) + label
|
2007-08-16 11:12:56 +00:00
|
|
|
+ docstring(fmt, j + 1, docstring::npos);
|
2007-01-15 16:58:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-12 20:09:53 +00:00
|
|
|
return tclass.counters().counterLabel(fmt, lang);
|
2007-01-15 16:58:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-06 20:01:30 +00:00
|
|
|
void Paragraph::applyLayout(Layout const & new_layout)
|
2001-04-04 21:47:26 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
d->layout_ = &new_layout;
|
2008-02-20 10:21:00 +00:00
|
|
|
LyXAlignment const oldAlign = d->params_.align();
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2008-03-06 22:06:24 +00:00
|
|
|
if (!(oldAlign & d->layout_->alignpossible)) {
|
2010-09-14 14:00:29 +00:00
|
|
|
frontend::Alert::warning(_("Alignment not permitted"),
|
2007-07-11 16:39:26 +00:00
|
|
|
_("The new layout does not permit the alignment previously used.\nSetting to default."));
|
2008-02-20 10:21:00 +00:00
|
|
|
d->params_.align(LYX_ALIGN_LAYOUT);
|
2007-07-11 16:39:26 +00:00
|
|
|
}
|
2001-04-04 21:47:26 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
|
2004-03-24 17:06:17 +00:00
|
|
|
pos_type Paragraph::beginOfBody() const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2007-10-23 13:25:05 +00:00
|
|
|
return d->begin_of_body_;
|
2003-11-13 13:43:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Paragraph::setBeginOfBody()
|
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
if (d->layout_->labeltype != LABEL_MANUAL) {
|
2007-10-23 13:25:05 +00:00
|
|
|
d->begin_of_body_ = 0;
|
2003-11-13 13:43:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-02-14 00:41:44 +00:00
|
|
|
|
1999-11-15 12:01:38 +00:00
|
|
|
// Unroll the first two cycles of the loop
|
|
|
|
// and remember the previous character to
|
2003-10-17 10:31:47 +00:00
|
|
|
// remove unnecessary getChar() calls
|
2001-11-26 16:42:04 +00:00
|
|
|
pos_type i = 0;
|
2003-11-13 13:43:44 +00:00
|
|
|
pos_type end = size();
|
2020-03-06 10:49:32 +00:00
|
|
|
bool prev_char_deleted = false;
|
|
|
|
if (i < end && (!(isNewline(i) || isEnvSeparator(i)) || isDeleted(i))) {
|
1999-11-04 01:40:20 +00:00
|
|
|
++i;
|
2003-11-13 13:43:44 +00:00
|
|
|
if (i < end) {
|
2015-09-20 08:42:35 +00:00
|
|
|
char_type previous_char = d->text_[i];
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
if (!(isNewline(i) || isEnvSeparator(i))) {
|
1999-11-04 01:40:20 +00:00
|
|
|
++i;
|
2020-03-06 10:49:32 +00:00
|
|
|
while (i < end && (previous_char != ' ' || prev_char_deleted)) {
|
2015-09-20 08:42:35 +00:00
|
|
|
char_type temp = d->text_[i];
|
2020-03-06 10:49:32 +00:00
|
|
|
prev_char_deleted = isDeleted(i);
|
|
|
|
if (!isDeleted(i) && (isNewline(i) || isEnvSeparator(i)))
|
2003-03-12 19:16:42 +00:00
|
|
|
break;
|
|
|
|
++i;
|
|
|
|
previous_char = temp;
|
|
|
|
}
|
1999-11-04 01:40:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2007-10-23 13:25:05 +00:00
|
|
|
d->begin_of_body_ = i;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2003-02-17 15:16:14 +00:00
|
|
|
|
2008-03-15 03:19:45 +00:00
|
|
|
bool Paragraph::allowParagraphCustomization() const
|
|
|
|
{
|
2008-09-13 17:01:54 +00:00
|
|
|
return inInset().allowParagraphCustomization();
|
2008-03-15 03:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-10 17:41:52 +00:00
|
|
|
bool Paragraph::usePlainLayout() const
|
Fix bug 4037 and related problems. The patch has been cleaned up a bit
from the one posted to the list.
The basic idea has two parts. First, we hard code an "empty layout"
(called PlainLayout, for want of a better name) in TextClass and read it
before doing anything else. It can therefore be customized by classes,
if they want---say, to make it left-aligned. Second, InsetText's are
divided into three types: (i) normal ones, that use the "default" layout
defined by the text class; (ii) highly restrictive ones, such as ERT and
(not quite an inset) table cells, which demand the empty layout; (iii)
middling ones, which default to an empty layout and use the empty layout
in place of the default. (This is so we don't get the same problem we
had with ERT in e.g. footnotes.) The type of inset is signaled by new
methods InsetText::forceEmptyLayout() and InsetText::useEmptyLayout().
(The latter might better be called: useEmptyLayoutInsteadOfDefault(),
but that's silly.) The old InsetText::forceDefaultParagraphs() has been
split into these, plus a new method InsetText::allowParagraphCustomization().
A lot of the changes just adapt to this change.
The other big change is in GuiToolbar: We want to show LyXDefault and
the "default" layout only when they're active.
There are a handful of places where I'm not entirely sure whether we
should be using forceEmptyLayout or !allowParagraphCustomization() or
both. The InsetCaption is one of these. These places, and some others,
are marked with FIXMEs, so I'd appreciate it if people would search
through the patch and let me know whether these need changing. If they
don't, the FIXMEs can be deleted.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@22966 a592a061-630c-0410-9148-cb99ea01b6c8
2008-02-12 17:31:07 +00:00
|
|
|
{
|
2008-09-13 17:01:54 +00:00
|
|
|
return inInset().usePlainLayout();
|
2004-04-08 15:03:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-26 11:04:42 +00:00
|
|
|
bool Paragraph::isPassThru() const
|
|
|
|
{
|
2012-11-28 18:02:07 +00:00
|
|
|
return inInset().isPassThru() || d->layout_->pass_thru;
|
2011-01-26 11:04:42 +00:00
|
|
|
}
|
|
|
|
|
2003-09-19 07:25:36 +00:00
|
|
|
namespace {
|
|
|
|
|
2003-12-01 13:35:49 +00:00
|
|
|
// paragraphs inside floats need different alignment tags to avoid
|
2004-01-28 16:21:29 +00:00
|
|
|
// unwanted space
|
2003-09-19 07:25:36 +00:00
|
|
|
|
2007-10-13 09:04:52 +00:00
|
|
|
bool noTrivlistCentering(InsetCode code)
|
2003-09-19 07:25:36 +00:00
|
|
|
{
|
2008-09-18 14:51:16 +00:00
|
|
|
return code == FLOAT_CODE
|
|
|
|
|| code == WRAP_CODE
|
|
|
|
|| code == CELL_CODE;
|
2003-09-19 07:25:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string correction(string const & orig)
|
|
|
|
{
|
|
|
|
if (orig == "flushleft")
|
|
|
|
return "raggedright";
|
|
|
|
if (orig == "flushright")
|
|
|
|
return "raggedleft";
|
|
|
|
if (orig == "center")
|
|
|
|
return "centering";
|
|
|
|
return orig;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-01 13:45:11 +00:00
|
|
|
bool corrected_env(otexstream & os, string const & suffix, string const & env,
|
|
|
|
InsetCode code, bool const lastpar, int & col)
|
2003-09-19 07:25:36 +00:00
|
|
|
{
|
2014-12-01 13:45:11 +00:00
|
|
|
string macro = suffix + "{";
|
2008-09-18 14:51:16 +00:00
|
|
|
if (noTrivlistCentering(code)) {
|
|
|
|
if (lastpar) {
|
|
|
|
// the last paragraph in non-trivlist-aligned
|
|
|
|
// context is special (to avoid unwanted whitespace)
|
2014-12-01 13:45:11 +00:00
|
|
|
if (suffix == "\\begin") {
|
|
|
|
macro = "\\" + correction(env) + "{}";
|
|
|
|
os << from_ascii(macro);
|
|
|
|
col += macro.size();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2008-09-18 14:51:16 +00:00
|
|
|
}
|
2014-12-01 13:45:11 +00:00
|
|
|
macro += correction(env);
|
2008-09-18 14:51:16 +00:00
|
|
|
} else
|
2014-12-01 13:45:11 +00:00
|
|
|
macro += env;
|
|
|
|
macro += "}";
|
|
|
|
if (suffix == "\\par\\end") {
|
|
|
|
os << breakln;
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
os << from_ascii(macro);
|
|
|
|
col += macro.size();
|
|
|
|
if (suffix == "\\begin") {
|
|
|
|
os << breakln;
|
|
|
|
col = 0;
|
2006-12-08 18:20:38 +00:00
|
|
|
}
|
2014-12-01 13:45:11 +00:00
|
|
|
return true;
|
2006-12-08 18:20:38 +00:00
|
|
|
}
|
|
|
|
|
2017-07-23 11:11:54 +00:00
|
|
|
} // namespace
|
2003-09-19 07:25:36 +00:00
|
|
|
|
2002-08-15 07:53:46 +00:00
|
|
|
|
2007-10-23 13:25:05 +00:00
|
|
|
int Paragraph::Private::startTeXParParams(BufferParams const & bparams,
|
2011-02-10 20:02:48 +00:00
|
|
|
otexstream & os, OutputParams const & runparams) const
|
2002-01-19 20:24:04 +00:00
|
|
|
{
|
|
|
|
int column = 0;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2015-05-02 14:34:57 +00:00
|
|
|
bool canindent =
|
|
|
|
(bparams.paragraph_separation == BufferParams::ParagraphIndentSeparation) ?
|
|
|
|
(layout_->toggle_indent != ITOGGLE_NEVER) :
|
|
|
|
(layout_->toggle_indent == ITOGGLE_ALWAYS);
|
|
|
|
|
|
|
|
if (canindent && params_.noindent() && !layout_->pass_thru) {
|
2002-01-19 20:24:04 +00:00
|
|
|
os << "\\noindent ";
|
|
|
|
column += 10;
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2007-10-23 13:25:05 +00:00
|
|
|
LyXAlignment const curAlign = params_.align();
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2007-10-23 13:25:05 +00:00
|
|
|
if (curAlign == layout_->align)
|
2007-06-28 00:48:06 +00:00
|
|
|
return column;
|
|
|
|
|
|
|
|
switch (curAlign) {
|
2002-07-01 14:31:57 +00:00
|
|
|
case LYX_ALIGN_NONE:
|
|
|
|
case LYX_ALIGN_BLOCK:
|
|
|
|
case LYX_ALIGN_LAYOUT:
|
|
|
|
case LYX_ALIGN_SPECIAL:
|
2010-06-05 08:26:00 +00:00
|
|
|
case LYX_ALIGN_DECIMAL:
|
2002-07-01 14:31:57 +00:00
|
|
|
break;
|
|
|
|
case LYX_ALIGN_LEFT:
|
|
|
|
case LYX_ALIGN_RIGHT:
|
|
|
|
case LYX_ALIGN_CENTER:
|
2008-09-18 14:51:16 +00:00
|
|
|
if (runparams.moving_arg) {
|
2002-07-01 14:31:57 +00:00
|
|
|
os << "\\protect";
|
2004-05-17 11:28:31 +00:00
|
|
|
column += 8;
|
2002-07-01 14:31:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2002-08-10 15:21:07 +00:00
|
|
|
|
2008-09-18 14:51:16 +00:00
|
|
|
string const begin_tag = "\\begin";
|
2009-08-09 14:33:35 +00:00
|
|
|
InsetCode code = ownerCode();
|
2008-09-18 14:51:16 +00:00
|
|
|
bool const lastpar = runparams.isLastPar;
|
2019-01-07 16:02:06 +00:00
|
|
|
// RTL in classic (PDF)LaTeX (without the Bidi package)
|
2019-07-10 17:10:16 +00:00
|
|
|
// Luabibdi (used by LuaTeX) behaves like classic
|
2019-01-07 12:54:23 +00:00
|
|
|
bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft()
|
2019-07-11 08:31:10 +00:00
|
|
|
&& !runparams.useBidiPackage();
|
2008-09-18 14:51:16 +00:00
|
|
|
|
2007-06-28 00:48:06 +00:00
|
|
|
switch (curAlign) {
|
2002-01-19 20:24:04 +00:00
|
|
|
case LYX_ALIGN_NONE:
|
|
|
|
case LYX_ALIGN_BLOCK:
|
|
|
|
case LYX_ALIGN_LAYOUT:
|
|
|
|
case LYX_ALIGN_SPECIAL:
|
2010-06-05 08:26:00 +00:00
|
|
|
case LYX_ALIGN_DECIMAL:
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
case LYX_ALIGN_LEFT: {
|
2019-01-07 16:02:06 +00:00
|
|
|
if (rtl_classic)
|
|
|
|
// Classic (PDF)LaTeX switches the left/right logic in RTL mode
|
2014-12-01 13:45:11 +00:00
|
|
|
corrected_env(os, begin_tag, "flushright", code, lastpar, column);
|
2019-01-07 16:02:06 +00:00
|
|
|
else
|
|
|
|
corrected_env(os, begin_tag, "flushleft", code, lastpar, column);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
} case LYX_ALIGN_RIGHT: {
|
2019-01-07 16:02:06 +00:00
|
|
|
if (rtl_classic)
|
|
|
|
// Classic (PDF)LaTeX switches the left/right logic in RTL mode
|
2014-12-01 13:45:11 +00:00
|
|
|
corrected_env(os, begin_tag, "flushleft", code, lastpar, column);
|
2019-01-07 16:02:06 +00:00
|
|
|
else
|
|
|
|
corrected_env(os, begin_tag, "flushright", code, lastpar, column);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
} case LYX_ALIGN_CENTER: {
|
2014-12-01 13:45:11 +00:00
|
|
|
corrected_env(os, begin_tag, "center", code, lastpar, column);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-09-19 07:25:36 +00:00
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2002-01-19 20:24:04 +00:00
|
|
|
return column;
|
|
|
|
}
|
|
|
|
|
2002-08-15 07:53:46 +00:00
|
|
|
|
2011-06-22 16:21:03 +00:00
|
|
|
bool Paragraph::Private::endTeXParParams(BufferParams const & bparams,
|
2011-02-10 20:02:48 +00:00
|
|
|
otexstream & os, OutputParams const & runparams) const
|
2002-01-19 20:24:04 +00:00
|
|
|
{
|
2009-06-18 06:52:38 +00:00
|
|
|
LyXAlignment const curAlign = params_.align();
|
|
|
|
|
|
|
|
if (curAlign == layout_->align)
|
2011-06-22 16:21:03 +00:00
|
|
|
return false;
|
2009-06-18 06:52:38 +00:00
|
|
|
|
|
|
|
switch (curAlign) {
|
2002-07-01 14:31:57 +00:00
|
|
|
case LYX_ALIGN_NONE:
|
|
|
|
case LYX_ALIGN_BLOCK:
|
|
|
|
case LYX_ALIGN_LAYOUT:
|
|
|
|
case LYX_ALIGN_SPECIAL:
|
2010-06-05 08:26:00 +00:00
|
|
|
case LYX_ALIGN_DECIMAL:
|
2002-07-01 14:31:57 +00:00
|
|
|
break;
|
|
|
|
case LYX_ALIGN_LEFT:
|
|
|
|
case LYX_ALIGN_RIGHT:
|
|
|
|
case LYX_ALIGN_CENTER:
|
2011-06-22 16:21:03 +00:00
|
|
|
if (runparams.moving_arg)
|
2002-07-01 14:31:57 +00:00
|
|
|
os << "\\protect";
|
|
|
|
break;
|
|
|
|
}
|
2002-08-10 15:21:07 +00:00
|
|
|
|
2014-12-01 13:45:11 +00:00
|
|
|
bool output = false;
|
|
|
|
int col = 0;
|
|
|
|
string const end_tag = "\\par\\end";
|
2009-08-09 14:33:35 +00:00
|
|
|
InsetCode code = ownerCode();
|
2008-09-18 14:51:16 +00:00
|
|
|
bool const lastpar = runparams.isLastPar;
|
2019-01-07 16:02:06 +00:00
|
|
|
// RTL in classic (PDF)LaTeX (without the Bidi package)
|
2019-07-10 17:10:16 +00:00
|
|
|
// Luabibdi (used by LuaTeX) behaves like classic
|
2019-01-07 12:54:23 +00:00
|
|
|
bool const rtl_classic = owner_->getParLanguage(bparams)->rightToLeft()
|
2019-07-11 08:31:10 +00:00
|
|
|
&& !runparams.useBidiPackage();
|
2008-09-18 14:51:16 +00:00
|
|
|
|
2009-06-18 06:52:38 +00:00
|
|
|
switch (curAlign) {
|
2002-01-19 20:24:04 +00:00
|
|
|
case LYX_ALIGN_NONE:
|
|
|
|
case LYX_ALIGN_BLOCK:
|
|
|
|
case LYX_ALIGN_LAYOUT:
|
|
|
|
case LYX_ALIGN_SPECIAL:
|
2010-06-05 08:26:00 +00:00
|
|
|
case LYX_ALIGN_DECIMAL:
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
case LYX_ALIGN_LEFT: {
|
2019-01-07 16:02:06 +00:00
|
|
|
if (rtl_classic)
|
|
|
|
// Classic (PDF)LaTeX switches the left/right logic in RTL mode
|
2014-12-01 13:45:11 +00:00
|
|
|
output = corrected_env(os, end_tag, "flushright", code, lastpar, col);
|
2019-01-07 16:02:06 +00:00
|
|
|
else
|
|
|
|
output = corrected_env(os, end_tag, "flushleft", code, lastpar, col);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
} case LYX_ALIGN_RIGHT: {
|
2019-01-07 16:02:06 +00:00
|
|
|
if (rtl_classic)
|
|
|
|
// Classic (PDF)LaTeX switches the left/right logic in RTL mode
|
2014-12-01 13:45:11 +00:00
|
|
|
output = corrected_env(os, end_tag, "flushleft", code, lastpar, col);
|
2019-01-07 16:02:06 +00:00
|
|
|
else
|
|
|
|
output = corrected_env(os, end_tag, "flushright", code, lastpar, col);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
2003-09-19 07:25:36 +00:00
|
|
|
} case LYX_ALIGN_CENTER: {
|
2014-12-01 13:45:11 +00:00
|
|
|
corrected_env(os, end_tag, "center", code, lastpar, col);
|
2002-01-19 20:24:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2003-09-19 07:25:36 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 13:45:11 +00:00
|
|
|
return output || lastpar;
|
2002-01-19 20:24:04 +00:00
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
|
|
|
|
// This one spits out the text of the paragraph
|
2010-06-15 15:49:24 +00:00
|
|
|
void Paragraph::latex(BufferParams const & bparams,
|
2008-11-16 00:12:21 +00:00
|
|
|
Font const & outerfont,
|
2011-02-10 20:02:48 +00:00
|
|
|
otexstream & os,
|
2008-11-16 00:12:21 +00:00
|
|
|
OutputParams const & runparams,
|
2010-06-15 15:37:39 +00:00
|
|
|
int start_pos, int end_pos, bool force) const
|
1999-09-27 18:44:28 +00:00
|
|
|
{
|
2008-10-06 10:14:41 +00:00
|
|
|
LYXERR(Debug::LATEX, "Paragraph::latex... " << this);
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2008-10-31 14:58:53 +00:00
|
|
|
// FIXME This check should not be needed. Perhaps issue an
|
|
|
|
// error if it triggers.
|
2009-08-09 15:38:55 +00:00
|
|
|
Layout const & style = inInset().forcePlainLayout() ?
|
2008-10-31 14:58:53 +00:00
|
|
|
bparams.documentClass().plainLayout() : *d->layout_;
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2010-06-15 15:37:39 +00:00
|
|
|
if (!force && style.inpreamble)
|
2010-06-15 15:49:24 +00:00
|
|
|
return;
|
2010-06-15 15:37:39 +00:00
|
|
|
|
|
|
|
bool const allowcust = allowParagraphCustomization();
|
|
|
|
|
2007-01-07 17:58:36 +00:00
|
|
|
// Current base font for all inherited font changes, without any
|
|
|
|
// change caused by an individual character, except for the language:
|
|
|
|
// It is set to the language of the first character.
|
|
|
|
// As long as we are in the label, this font is the base font of the
|
2007-01-07 18:40:06 +00:00
|
|
|
// label. Before the first body character it is set to the base font
|
2007-01-07 17:58:36 +00:00
|
|
|
// of the body.
|
2007-04-29 18:17:15 +00:00
|
|
|
Font basefont;
|
2005-02-08 13:18:05 +00:00
|
|
|
|
2019-03-11 14:24:22 +00:00
|
|
|
// If there is an open font-encoding changing command (script wrapper),
|
|
|
|
// alien_script is set to its name
|
|
|
|
string alien_script;
|
|
|
|
string script;
|
|
|
|
|
2000-01-11 01:59:00 +00:00
|
|
|
// Maybe we have to create a optional argument.
|
2003-11-13 13:43:44 +00:00
|
|
|
pos_type body_pos = beginOfBody();
|
2003-01-08 09:03:32 +00:00
|
|
|
unsigned int column = 0;
|
2001-06-27 14:10:35 +00:00
|
|
|
|
2020-08-14 16:01:26 +00:00
|
|
|
// If we are inside an non inheritFont() inset, the real outerfont is local_font
|
|
|
|
Font const real_outerfont = (!inInset().inheritFont()
|
|
|
|
&& runparams.local_font != nullptr)
|
|
|
|
? Font(runparams.local_font->fontInfo()) : outerfont;
|
2020-07-15 07:11:05 +00:00
|
|
|
|
2003-03-09 12:37:22 +00:00
|
|
|
if (body_pos > 0) {
|
2010-01-24 10:32:22 +00:00
|
|
|
// the optional argument is kept in curly brackets in
|
|
|
|
// case it contains a ']'
|
2011-11-13 10:40:07 +00:00
|
|
|
// This is not strictly needed, but if this is changed it
|
|
|
|
// would be a file format change, and tex2lyx would need
|
|
|
|
// to be adjusted, since it unconditionally removes the
|
|
|
|
// braces when it parses \item.
|
2010-01-24 10:32:22 +00:00
|
|
|
os << "[{";
|
|
|
|
column += 2;
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont = getLabelFont(bparams, real_outerfont);
|
1999-09-27 18:44:28 +00:00
|
|
|
} else {
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont = getLayoutFont(bparams, real_outerfont);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Which font is currently active?
|
2007-04-29 18:17:15 +00:00
|
|
|
Font running_font(basefont);
|
1999-09-27 18:44:28 +00:00
|
|
|
// Do we have an open font change?
|
|
|
|
bool open_font = false;
|
|
|
|
|
2007-05-08 17:46:03 +00:00
|
|
|
Change runningChange = Change(Change::UNCHANGED);
|
2003-03-03 21:15:49 +00:00
|
|
|
|
2009-08-03 18:31:20 +00:00
|
|
|
Encoding const * const prev_encoding = runparams.encoding;
|
|
|
|
|
2011-02-10 20:02:48 +00:00
|
|
|
os.texrow().start(id(), 0);
|
1999-11-04 01:40:20 +00:00
|
|
|
|
2002-01-19 20:24:04 +00:00
|
|
|
// if the paragraph is empty, the loop will not be entered at all
|
2002-08-10 15:21:07 +00:00
|
|
|
if (empty()) {
|
2017-12-23 12:25:13 +00:00
|
|
|
// For InTitle commands, we have already opened a group
|
|
|
|
// in output_latex::TeXOnePar.
|
2017-12-26 12:11:00 +00:00
|
|
|
if (style.isCommand() && !style.intitle) {
|
2002-01-19 20:24:04 +00:00
|
|
|
os << '{';
|
|
|
|
++column;
|
|
|
|
}
|
2012-11-25 18:10:16 +00:00
|
|
|
if (!style.leftdelim().empty()) {
|
|
|
|
os << style.leftdelim();
|
|
|
|
column += style.leftdelim().size();
|
|
|
|
}
|
2008-10-31 14:58:53 +00:00
|
|
|
if (allowcust)
|
2011-02-10 20:02:48 +00:00
|
|
|
column += d->startTeXParParams(bparams, os, runparams);
|
2002-01-19 20:24:04 +00:00
|
|
|
}
|
|
|
|
|
2017-06-03 15:26:05 +00:00
|
|
|
// Whether a \par can be issued for insets typeset inline with text.
|
|
|
|
// Yes if greater than 0. This has to be static.
|
|
|
|
THREAD_LOCAL_STATIC int parInline = 0;
|
|
|
|
|
2001-11-26 16:42:04 +00:00
|
|
|
for (pos_type i = 0; i < size(); ++i) {
|
1999-09-27 18:44:28 +00:00
|
|
|
// First char in paragraph or after label?
|
2003-03-09 12:37:22 +00:00
|
|
|
if (i == body_pos) {
|
|
|
|
if (body_pos > 0) {
|
1999-09-27 18:44:28 +00:00
|
|
|
if (open_font) {
|
2017-06-03 15:26:05 +00:00
|
|
|
bool needPar = false;
|
2007-01-09 19:25:40 +00:00
|
|
|
column += running_font.latexWriteEndChanges(
|
2007-05-06 20:26:02 +00:00
|
|
|
os, bparams, runparams,
|
2020-08-14 16:01:26 +00:00
|
|
|
basefont, basefont, needPar);
|
1999-09-27 18:44:28 +00:00
|
|
|
open_font = false;
|
|
|
|
}
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont = getLayoutFont(bparams, real_outerfont);
|
1999-09-27 18:44:28 +00:00
|
|
|
running_font = basefont;
|
2007-02-09 23:52:22 +00:00
|
|
|
|
2007-05-08 17:46:03 +00:00
|
|
|
column += Changes::latexMarkChange(os, bparams,
|
2009-10-12 16:22:05 +00:00
|
|
|
runningChange, Change(Change::UNCHANGED),
|
|
|
|
runparams);
|
2007-05-08 17:46:03 +00:00
|
|
|
runningChange = Change(Change::UNCHANGED);
|
2007-02-09 23:52:22 +00:00
|
|
|
|
2010-01-24 10:32:22 +00:00
|
|
|
os << "}] ";
|
|
|
|
column +=3;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
2017-12-23 12:25:13 +00:00
|
|
|
// For InTitle commands, we have already opened a group
|
|
|
|
// in output_latex::TeXOnePar.
|
2017-12-26 12:11:00 +00:00
|
|
|
if (style.isCommand() && !style.intitle) {
|
2000-03-06 02:42:40 +00:00
|
|
|
os << '{';
|
2000-01-20 01:41:55 +00:00
|
|
|
++column;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2012-11-25 18:10:16 +00:00
|
|
|
if (!style.leftdelim().empty()) {
|
|
|
|
os << style.leftdelim();
|
|
|
|
column += style.leftdelim().size();
|
|
|
|
}
|
|
|
|
|
2008-10-31 14:58:53 +00:00
|
|
|
if (allowcust)
|
2007-10-23 13:25:05 +00:00
|
|
|
column += d->startTeXParParams(bparams, os,
|
2008-09-18 14:51:16 +00:00
|
|
|
runparams);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
2002-03-21 17:27:08 +00:00
|
|
|
|
2016-10-23 16:23:41 +00:00
|
|
|
runparams.wasDisplayMath = runparams.inDisplayMath;
|
2016-10-20 23:35:39 +00:00
|
|
|
runparams.inDisplayMath = false;
|
|
|
|
bool deleted_display_math = false;
|
2017-10-22 11:12:33 +00:00
|
|
|
Change const & change = runparams.inDeletedInset
|
|
|
|
? runparams.changeOfDeletedInset : lookupChange(i);
|
2016-10-20 23:35:39 +00:00
|
|
|
|
2019-12-28 12:43:17 +00:00
|
|
|
char_type const c = d->text_[i];
|
|
|
|
|
2016-10-20 23:35:39 +00:00
|
|
|
// Check whether a display math inset follows
|
2019-12-28 12:43:17 +00:00
|
|
|
if (c == META_INSET
|
2016-10-20 23:35:39 +00:00
|
|
|
&& i >= start_pos && (end_pos == -1 || i < end_pos)) {
|
2019-12-28 12:43:17 +00:00
|
|
|
if (isDeleted(i))
|
2020-11-29 23:03:35 +00:00
|
|
|
runparams.ctObject = getInset(i)->getCtObject(runparams);
|
2019-12-28 12:43:17 +00:00
|
|
|
|
2016-10-20 23:35:39 +00:00
|
|
|
InsetMath const * im = getInset(i)->asInsetMath();
|
|
|
|
if (im && im->asHullInset()
|
|
|
|
&& im->asHullInset()->outerDisplay()) {
|
|
|
|
runparams.inDisplayMath = true;
|
|
|
|
// runparams.inDeletedInset will be set by
|
|
|
|
// latexInset later, but we need this info
|
|
|
|
// before it is called. On the other hand, we
|
|
|
|
// cannot set it here because it is a counter.
|
|
|
|
deleted_display_math = isDeleted(i);
|
|
|
|
}
|
2017-10-22 11:12:33 +00:00
|
|
|
if (bparams.output_changes && deleted_display_math
|
|
|
|
&& runningChange == change
|
|
|
|
&& change.type == Change::DELETED
|
|
|
|
&& !os.afterParbreak()) {
|
|
|
|
// A display math in the same paragraph follows.
|
|
|
|
// We have to close and then reopen \lyxdeleted,
|
|
|
|
// otherwise the math will be shifted up.
|
|
|
|
OutputParams rp = runparams;
|
|
|
|
if (open_font) {
|
|
|
|
bool needPar = false;
|
|
|
|
column += running_font.latexWriteEndChanges(
|
|
|
|
os, bparams, rp, basefont,
|
2020-08-14 16:01:26 +00:00
|
|
|
basefont, needPar);
|
2017-10-22 11:12:33 +00:00
|
|
|
open_font = false;
|
|
|
|
}
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont = (body_pos > i) ? getLabelFont(bparams, real_outerfont)
|
|
|
|
: getLayoutFont(bparams, real_outerfont);
|
2017-10-22 11:12:33 +00:00
|
|
|
running_font = basefont;
|
|
|
|
column += Changes::latexMarkChange(os, bparams,
|
|
|
|
Change(Change::INSERTED), change, rp);
|
|
|
|
}
|
2016-10-20 23:35:39 +00:00
|
|
|
}
|
|
|
|
|
2014-03-29 22:52:36 +00:00
|
|
|
if (bparams.output_changes && runningChange != change) {
|
2019-03-11 14:24:22 +00:00
|
|
|
if (!alien_script.empty()) {
|
|
|
|
column += 1;
|
|
|
|
os << "}";
|
|
|
|
alien_script.clear();
|
|
|
|
}
|
2007-05-08 17:46:03 +00:00
|
|
|
if (open_font) {
|
2017-06-03 15:26:05 +00:00
|
|
|
bool needPar = false;
|
2007-05-08 17:46:03 +00:00
|
|
|
column += running_font.latexWriteEndChanges(
|
2017-06-03 15:26:05 +00:00
|
|
|
os, bparams, runparams,
|
2020-08-14 16:01:26 +00:00
|
|
|
basefont, basefont, needPar);
|
2007-05-08 17:46:03 +00:00
|
|
|
open_font = false;
|
|
|
|
}
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont = (body_pos > i) ? getLabelFont(bparams, real_outerfont)
|
|
|
|
: getLayoutFont(bparams, real_outerfont);
|
2007-05-08 17:46:03 +00:00
|
|
|
running_font = basefont;
|
2009-10-12 16:22:05 +00:00
|
|
|
column += Changes::latexMarkChange(os, bparams, runningChange,
|
|
|
|
change, runparams);
|
2007-05-08 17:46:03 +00:00
|
|
|
runningChange = change;
|
|
|
|
}
|
2007-02-09 23:52:22 +00:00
|
|
|
|
|
|
|
// do not output text which is marked deleted
|
|
|
|
// if change tracking output is disabled
|
2014-03-29 22:52:36 +00:00
|
|
|
if (!bparams.output_changes && change.deleted()) {
|
2007-02-09 23:52:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
++column;
|
2007-05-28 22:27:45 +00:00
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
// Fully instantiated font
|
2020-08-16 08:47:46 +00:00
|
|
|
Font current_font = getFont(bparams, i, outerfont);
|
2020-08-12 09:04:17 +00:00
|
|
|
// Previous font
|
|
|
|
Font const prev_font = (i > 0) ?
|
|
|
|
getFont(bparams, i - 1, outerfont)
|
|
|
|
: current_font;
|
2001-04-27 07:19:08 +00:00
|
|
|
|
2007-04-29 18:17:15 +00:00
|
|
|
Font const last_font = running_font;
|
2020-05-17 12:54:59 +00:00
|
|
|
bool const in_ct_deletion = (bparams.output_changes
|
2020-05-17 13:16:23 +00:00
|
|
|
&& runningChange == change
|
|
|
|
&& change.type == Change::DELETED
|
|
|
|
&& !os.afterParbreak());
|
2020-08-15 10:27:58 +00:00
|
|
|
// Insets where font switches are used (rather than font commands)
|
|
|
|
bool const fontswitch_inset =
|
|
|
|
c == META_INSET
|
|
|
|
&& getInset(i)
|
|
|
|
&& getInset(i)->allowMultiPar()
|
2020-12-02 13:31:26 +00:00
|
|
|
&& getInset(i)->lyxCode() != ERT_CODE
|
|
|
|
&& getInset(i)->producesOutput();
|
1999-09-27 18:44:28 +00:00
|
|
|
|
2020-08-16 08:47:08 +00:00
|
|
|
bool closeLanguage = false;
|
|
|
|
bool lang_switched_at_inset = false;
|
|
|
|
if (fontswitch_inset) {
|
|
|
|
// Some insets cannot be inside a font change command.
|
|
|
|
// However, even such insets *can* be placed in \L or \R
|
|
|
|
// or their equivalents (for RTL language switches),
|
|
|
|
// so we don't close the language in those cases
|
|
|
|
// (= differing isRightToLeft()).
|
|
|
|
// ArabTeX, though, doesn't seem to handle this special behavior.
|
|
|
|
closeLanguage = basefont.isRightToLeft() == current_font.isRightToLeft()
|
|
|
|
|| basefont.language()->lang() == "arabic_arabtex"
|
|
|
|
|| current_font.language()->lang() == "arabic_arabtex";
|
|
|
|
// We need to check prev_font as language changes directly at inset
|
|
|
|
// will only be started inside the inset.
|
|
|
|
lang_switched_at_inset = prev_font.language() != current_font.language();
|
|
|
|
}
|
|
|
|
|
2007-02-12 20:51:00 +00:00
|
|
|
// Do we need to close the previous font?
|
2020-08-21 09:07:22 +00:00
|
|
|
bool langClosed = false;
|
2002-04-11 13:35:03 +00:00
|
|
|
if (open_font &&
|
2020-08-12 09:04:17 +00:00
|
|
|
((current_font != running_font
|
|
|
|
|| current_font.language() != running_font.language())
|
2020-08-15 10:27:58 +00:00
|
|
|
|| (fontswitch_inset
|
2020-08-16 08:47:46 +00:00
|
|
|
&& (current_font == prev_font))))
|
2002-04-11 13:35:03 +00:00
|
|
|
{
|
2019-03-11 14:24:22 +00:00
|
|
|
// ensure there is no open script-wrapper
|
|
|
|
if (!alien_script.empty()) {
|
|
|
|
column += 1;
|
|
|
|
os << "}";
|
|
|
|
alien_script.clear();
|
|
|
|
}
|
2020-05-17 12:54:59 +00:00
|
|
|
if (in_ct_deletion) {
|
|
|
|
// We have to close and then reopen \lyxdeleted,
|
|
|
|
// as strikeout needs to be on lowest level.
|
|
|
|
os << '}';
|
|
|
|
column += 1;
|
|
|
|
}
|
2020-08-16 08:47:46 +00:00
|
|
|
if (closeLanguage)
|
|
|
|
// Force language closing
|
|
|
|
current_font.setLanguage(basefont.language());
|
2020-09-26 10:12:09 +00:00
|
|
|
Font const nextfont = (i == body_pos-1) ? basefont : current_font;
|
2020-12-03 07:50:43 +00:00
|
|
|
bool needPar = false;
|
2007-01-09 19:25:40 +00:00
|
|
|
column += running_font.latexWriteEndChanges(
|
2017-06-03 15:26:05 +00:00
|
|
|
os, bparams, runparams, basefont,
|
2020-09-26 10:12:09 +00:00
|
|
|
nextfont, needPar);
|
2020-05-17 12:54:59 +00:00
|
|
|
if (in_ct_deletion) {
|
|
|
|
// We have to close and then reopen \lyxdeleted,
|
|
|
|
// as strikeout needs to be on lowest level.
|
|
|
|
OutputParams rp = runparams;
|
|
|
|
column += Changes::latexMarkChange(os, bparams,
|
|
|
|
Change(Change::UNCHANGED), Change(Change::DELETED), rp);
|
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
open_font = false;
|
2020-09-26 10:12:09 +00:00
|
|
|
// Has the language been closed in the latexWriteEndChanges() call above?
|
|
|
|
langClosed = running_font.language() != basefont.language()
|
|
|
|
&& running_font.language() != nextfont.language()
|
|
|
|
&& (running_font.language()->encoding()->package() != Encoding::CJK);
|
|
|
|
running_font = basefont;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 23:45:35 +00:00
|
|
|
// if necessary, close language environment before opening CJK
|
|
|
|
string const running_lang = running_font.language()->babel();
|
|
|
|
string const lang_end_command = lyxrc.language_command_end;
|
|
|
|
if (!lang_end_command.empty() && !bparams.useNonTeXFonts
|
|
|
|
&& !running_lang.empty()
|
|
|
|
&& running_lang == openLanguageName()
|
|
|
|
&& current_font.language()->encoding()->package() == Encoding::CJK) {
|
|
|
|
string end_tag = subst(lang_end_command, "$$lang", running_lang);
|
|
|
|
os << from_ascii(end_tag);
|
|
|
|
column += end_tag.length();
|
|
|
|
popLanguageName();
|
2007-12-08 11:21:00 +00:00
|
|
|
}
|
|
|
|
|
2007-10-23 18:23:03 +00:00
|
|
|
// Switch file encoding if necessary (and allowed)
|
2020-08-17 11:25:02 +00:00
|
|
|
if ((!fontswitch_inset || closeLanguage)
|
|
|
|
&& !runparams.pass_thru && !style.pass_thru &&
|
2008-07-01 15:16:09 +00:00
|
|
|
runparams.encoding->package() != Encoding::none &&
|
2016-07-31 07:03:26 +00:00
|
|
|
current_font.language()->encoding()->package() != Encoding::none) {
|
Introduce a wrapper class for odocstream to help ensuring that no
blank lines may be inadvertently output. This is achieved by using two
special iomanip-like variables (breakln and safebreakln) in the lyx::
namespace. When they are inserted in the stream, a newline is output
only if not already at the beginning of a line. The difference between
breakln and safebreakln is that, if needed, the former outputs '\n'
and the latter "%\n".
In future, the new class will also be used for counting the number of
newlines issued. Even if the infractrure for doing that is already in
place, the counting is essentially still done the old way.
There are still places in the code where the functionality of the
class could be used, most probably. ATM, it is used for InsetTabular,
InsetListings, InsetFloat, and InsetText.
The Comment and GreyedOut insets required a special treatment and a
new InsetLayout parameter (Display) has been introduced. The default
for Display is "true", meaning that the corresponding latex
environment is of "display" type, i.e., it stands on its own, whereas
"false" means that the contents appear inline with the text. The
latter is the case for both Comment and GreyedOut insets.
Mostly, the only visible effects on latex exports should be the
disappearing of some redundant % chars and the appearing/disappearing
of null {} latex groups after a comment or lyxgreyedout environments
(they are related to the presence or absence of a space immediately
after those environments), as well as the fact that math environments
are now started on their own lines.
As a last thing, only the latex code between \begin{document} and
\end{document} goes through the new class, the preamble being directly
output through odocstream, as usual.
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@37360 a592a061-630c-0410-9148-cb99ea01b6c8
2011-01-29 02:41:13 +00:00
|
|
|
pair<bool, int> const enc_switch =
|
|
|
|
switchEncoding(os.os(), bparams, runparams,
|
2016-07-31 07:03:26 +00:00
|
|
|
*(current_font.language()->encoding()));
|
2007-07-05 19:19:41 +00:00
|
|
|
if (enc_switch.first) {
|
|
|
|
column += enc_switch.second;
|
2016-07-31 07:03:26 +00:00
|
|
|
runparams.encoding = current_font.language()->encoding();
|
2007-05-06 20:26:02 +00:00
|
|
|
}
|
2007-03-18 10:59:16 +00:00
|
|
|
}
|
|
|
|
|
2016-10-20 23:35:39 +00:00
|
|
|
// A display math inset inside an ulem command will be output
|
2017-10-22 11:12:33 +00:00
|
|
|
// as a box of width \linewidth, so we have to either disable
|
2016-10-20 23:35:39 +00:00
|
|
|
// indentation if the inset starts a paragraph, or start a new
|
|
|
|
// line to accommodate such box. This has to be done before
|
|
|
|
// writing any font changing commands.
|
|
|
|
if (runparams.inDisplayMath && !deleted_display_math
|
|
|
|
&& runparams.inulemcmd) {
|
|
|
|
if (os.afterParbreak())
|
|
|
|
os << "\\noindent";
|
|
|
|
else
|
|
|
|
os << "\\\\\n";
|
|
|
|
}
|
|
|
|
|
2007-02-11 23:52:07 +00:00
|
|
|
// Do we need to change font?
|
2020-08-17 11:11:46 +00:00
|
|
|
if ((current_font != running_font ||
|
2020-05-17 12:54:59 +00:00
|
|
|
current_font.language() != running_font.language())
|
|
|
|
&& i != body_pos - 1)
|
2007-02-11 23:52:07 +00:00
|
|
|
{
|
2020-08-17 11:11:46 +00:00
|
|
|
if (!fontswitch_inset) {
|
|
|
|
if (in_ct_deletion) {
|
|
|
|
// We have to close and then reopen \lyxdeleted,
|
|
|
|
// as strikeout needs to be on lowest level.
|
|
|
|
OutputParams rp = runparams;
|
2020-12-03 07:50:43 +00:00
|
|
|
bool needPar = false;
|
2020-08-17 11:11:46 +00:00
|
|
|
column += running_font.latexWriteEndChanges(
|
|
|
|
os, bparams, rp, basefont,
|
|
|
|
basefont, needPar);
|
|
|
|
os << '}';
|
|
|
|
column += 1;
|
|
|
|
}
|
|
|
|
otexstringstream ots;
|
|
|
|
InsetText const * textinset = inInset().asInsetText();
|
|
|
|
bool const cprotect = textinset
|
|
|
|
? textinset->hasCProtectContent(runparams.moving_arg)
|
|
|
|
&& !textinset->text().isMainText()
|
|
|
|
: false;
|
|
|
|
column += current_font.latexWriteStartChanges(ots, bparams,
|
|
|
|
runparams, basefont, last_font, false,
|
|
|
|
cprotect);
|
|
|
|
// Check again for display math in ulem commands as a
|
|
|
|
// font change may also occur just before a math inset.
|
|
|
|
if (runparams.inDisplayMath && !deleted_display_math
|
|
|
|
&& runparams.inulemcmd) {
|
|
|
|
if (os.afterParbreak())
|
|
|
|
os << "\\noindent";
|
|
|
|
else
|
|
|
|
os << "\\\\\n";
|
|
|
|
}
|
|
|
|
running_font = current_font;
|
|
|
|
open_font = true;
|
|
|
|
docstring fontchange = ots.str();
|
|
|
|
os << fontchange;
|
|
|
|
// check whether the fontchange ends with a \\textcolor
|
|
|
|
// modifier and the text starts with a space. If so we
|
|
|
|
// need to add } in order to prevent \\textcolor from gobbling
|
|
|
|
// the space (bug 4473).
|
|
|
|
docstring const last_modifier = rsplit(fontchange, '\\');
|
|
|
|
if (prefixIs(last_modifier, from_ascii("textcolor")) && c == ' ')
|
|
|
|
os << from_ascii("{}");
|
|
|
|
else if (ots.terminateCommand())
|
|
|
|
os << termcmd;
|
|
|
|
if (in_ct_deletion) {
|
|
|
|
// We have to close and then reopen \lyxdeleted,
|
|
|
|
// as strikeout needs to be on lowest level.
|
|
|
|
OutputParams rp = runparams;
|
|
|
|
column += Changes::latexMarkChange(os, bparams,
|
|
|
|
Change(Change::UNCHANGED), change, rp);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
running_font = current_font;
|
2020-08-21 09:07:22 +00:00
|
|
|
open_font = !langClosed;
|
2019-12-27 12:56:53 +00:00
|
|
|
}
|
2007-02-11 23:52:07 +00:00
|
|
|
}
|
|
|
|
|
2008-11-16 18:14:14 +00:00
|
|
|
// FIXME: think about end_pos implementation...
|
|
|
|
if (c == ' ' && i >= start_pos && (end_pos == -1 || i < end_pos)) {
|
2007-10-22 13:09:16 +00:00
|
|
|
// FIXME: integrate this case in latexSpecialChar
|
1999-09-27 18:44:28 +00:00
|
|
|
// Do not print the separation of the optional argument
|
2008-03-06 21:31:27 +00:00
|
|
|
// if style.pass_thru is false. This works because
|
2007-10-22 13:09:16 +00:00
|
|
|
// latexSpecialChar ignores spaces if
|
2008-03-06 21:31:27 +00:00
|
|
|
// style.pass_thru is false.
|
2003-03-09 12:37:22 +00:00
|
|
|
if (i != body_pos - 1) {
|
2018-04-22 17:06:46 +00:00
|
|
|
if (d->simpleTeXBlanks(bparams, runparams, os,
|
2016-07-31 07:03:26 +00:00
|
|
|
i, column, current_font, style)) {
|
Add machinery to output arbitrary unicode characters with LaTeX commands
read from a text file.
* src/encoding.[Ch]
(Encoding::latexChar): New, output a character to LaTeX
(Encoding::validate): New, add needed preamble stuff for a character
(Encodings::read): Read new unicodesymbols file
(Encodings::isCombiningChar): New, is a character a combining char?
* src/paragraph_pimpl.C
(isEncoding): Delete, no longer needed
(getEncoding): New, get the real encoding of a font
(Paragraph::Pimpl::latexSurrogatePair): New, output a surrogate pair
to LaTeX
(Paragraph::Pimpl::simpleTeXBlanks): Use latexSurrogatePair if needed
(Paragraph::Pimpl::simpleTeXSpecialChars): Ditto, and replace several
hardcoded characters with a call of encoding.latexChar()
(Paragraph::Pimpl::validate): replace several hardcoded characters
with a call of encoding.validate()
* src/support/debugstream.h
(basic_debugstream::disable): New, disable the stream completely
(basic_debugstream::enable): New, reenable the stream
* src/lyx_main.[Ch]: Adjust to changes above
* src/paragraph.C: Ditto
* lib/unicodesymbols: New file with UCS4 -> LaTeX command mapping.
It is far from complete yet, but contains most accents on latin
characters.
* lib/Makefile.am: add lib/unicodesymbols
* development/scons/scons_manifest.py: ditto
* development/tools/unicodesymbols.py: Helper script to update
lib/unicodesymbols with new symbols
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16920 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-28 21:27:45 +00:00
|
|
|
// A surrogate pair was output. We
|
2007-10-22 13:09:16 +00:00
|
|
|
// must not call latexSpecialChar
|
|
|
|
// in this iteration, since it would output
|
Add machinery to output arbitrary unicode characters with LaTeX commands
read from a text file.
* src/encoding.[Ch]
(Encoding::latexChar): New, output a character to LaTeX
(Encoding::validate): New, add needed preamble stuff for a character
(Encodings::read): Read new unicodesymbols file
(Encodings::isCombiningChar): New, is a character a combining char?
* src/paragraph_pimpl.C
(isEncoding): Delete, no longer needed
(getEncoding): New, get the real encoding of a font
(Paragraph::Pimpl::latexSurrogatePair): New, output a surrogate pair
to LaTeX
(Paragraph::Pimpl::simpleTeXBlanks): Use latexSurrogatePair if needed
(Paragraph::Pimpl::simpleTeXSpecialChars): Ditto, and replace several
hardcoded characters with a call of encoding.latexChar()
(Paragraph::Pimpl::validate): replace several hardcoded characters
with a call of encoding.validate()
* src/support/debugstream.h
(basic_debugstream::disable): New, disable the stream completely
(basic_debugstream::enable): New, reenable the stream
* src/lyx_main.[Ch]: Adjust to changes above
* src/paragraph.C: Ditto
* lib/unicodesymbols: New file with UCS4 -> LaTeX command mapping.
It is far from complete yet, but contains most accents on latin
characters.
* lib/Makefile.am: add lib/unicodesymbols
* development/scons/scons_manifest.py: ditto
* development/tools/unicodesymbols.py: Helper script to update
lib/unicodesymbols with new symbols
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16920 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-28 21:27:45 +00:00
|
|
|
// the combining character again.
|
2007-10-22 13:09:16 +00:00
|
|
|
++i;
|
Add machinery to output arbitrary unicode characters with LaTeX commands
read from a text file.
* src/encoding.[Ch]
(Encoding::latexChar): New, output a character to LaTeX
(Encoding::validate): New, add needed preamble stuff for a character
(Encodings::read): Read new unicodesymbols file
(Encodings::isCombiningChar): New, is a character a combining char?
* src/paragraph_pimpl.C
(isEncoding): Delete, no longer needed
(getEncoding): New, get the real encoding of a font
(Paragraph::Pimpl::latexSurrogatePair): New, output a surrogate pair
to LaTeX
(Paragraph::Pimpl::simpleTeXBlanks): Use latexSurrogatePair if needed
(Paragraph::Pimpl::simpleTeXSpecialChars): Ditto, and replace several
hardcoded characters with a call of encoding.latexChar()
(Paragraph::Pimpl::validate): replace several hardcoded characters
with a call of encoding.validate()
* src/support/debugstream.h
(basic_debugstream::disable): New, disable the stream completely
(basic_debugstream::enable): New, reenable the stream
* src/lyx_main.[Ch]: Adjust to changes above
* src/paragraph.C: Ditto
* lib/unicodesymbols: New file with UCS4 -> LaTeX command mapping.
It is far from complete yet, but contains most accents on latin
characters.
* lib/Makefile.am: add lib/unicodesymbols
* development/scons/scons_manifest.py: ditto
* development/tools/unicodesymbols.py: Helper script to update
lib/unicodesymbols with new symbols
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@16920 a592a061-630c-0410-9148-cb99ea01b6c8
2007-01-28 21:27:45 +00:00
|
|
|
continue;
|
2007-10-22 13:09:16 +00:00
|
|
|
}
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-09 23:52:22 +00:00
|
|
|
OutputParams rp = runparams;
|
2008-03-06 21:31:27 +00:00
|
|
|
rp.free_spacing = style.free_spacing;
|
2016-07-31 07:03:26 +00:00
|
|
|
rp.local_font = ¤t_font;
|
2008-03-06 21:31:27 +00:00
|
|
|
rp.intitle = style.intitle;
|
2007-10-22 13:09:16 +00:00
|
|
|
|
|
|
|
// Two major modes: LaTeX or plain
|
|
|
|
// Handle here those cases common to both modes
|
|
|
|
// and then split to handle the two modes separately.
|
2008-11-16 00:12:21 +00:00
|
|
|
if (c == META_INSET) {
|
2008-11-16 18:14:14 +00:00
|
|
|
if (i >= start_pos && (end_pos == -1 || i < end_pos)) {
|
2017-06-03 15:26:05 +00:00
|
|
|
// Greyedout notes and, in general, all insets
|
|
|
|
// with InsetLayout::isDisplay() == false,
|
|
|
|
// are typeset inline with the text. So, we
|
|
|
|
// can add a \par to the last paragraph of
|
|
|
|
// such insets only if nothing else follows.
|
|
|
|
bool incremented = false;
|
|
|
|
Inset const * inset = getInset(i);
|
|
|
|
InsetText const * textinset = inset
|
|
|
|
? inset->asInsetText()
|
2020-03-16 06:12:16 +00:00
|
|
|
: nullptr;
|
2017-06-03 15:26:05 +00:00
|
|
|
if (i + 1 == size() && textinset
|
|
|
|
&& !inset->getLayout().isDisplay()) {
|
|
|
|
ParagraphList const & pars =
|
|
|
|
textinset->text().paragraphs();
|
|
|
|
pit_type const pit = pars.size() - 1;
|
2018-02-24 05:04:34 +00:00
|
|
|
Font const lastfont =
|
2017-06-03 15:26:05 +00:00
|
|
|
pit < 0 || pars[pit].empty()
|
|
|
|
? pars[pit].getLayoutFont(
|
|
|
|
bparams,
|
2020-07-15 07:11:05 +00:00
|
|
|
real_outerfont)
|
2017-06-03 15:26:05 +00:00
|
|
|
: pars[pit].getFont(bparams,
|
|
|
|
pars[pit].size() - 1,
|
2020-07-15 07:11:05 +00:00
|
|
|
real_outerfont);
|
2018-02-24 05:04:34 +00:00
|
|
|
if (lastfont.fontInfo().size() !=
|
2017-06-03 15:26:05 +00:00
|
|
|
basefont.fontInfo().size()) {
|
|
|
|
++parInline;
|
|
|
|
incremented = true;
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 05:06:20 +00:00
|
|
|
// We need to restore parts of this after insets with
|
2020-08-14 16:01:26 +00:00
|
|
|
// allowMultiPar() true
|
|
|
|
Font const save_basefont = basefont;
|
2011-02-10 20:02:48 +00:00
|
|
|
d->latexInset(bparams, os, rp, running_font,
|
2020-07-15 07:11:05 +00:00
|
|
|
basefont, real_outerfont, open_font,
|
2020-08-16 08:47:08 +00:00
|
|
|
runningChange, style, i, column, fontswitch_inset,
|
|
|
|
closeLanguage, lang_switched_at_inset);
|
2020-08-15 10:27:58 +00:00
|
|
|
if (fontswitch_inset) {
|
2020-08-15 05:06:20 +00:00
|
|
|
if (open_font) {
|
|
|
|
bool needPar = false;
|
|
|
|
column += running_font.latexWriteEndChanges(
|
|
|
|
os, bparams, runparams,
|
|
|
|
basefont, basefont, needPar);
|
|
|
|
open_font = false;
|
|
|
|
}
|
|
|
|
basefont.fontInfo().setSize(save_basefont.fontInfo().size());
|
|
|
|
basefont.fontInfo().setFamily(save_basefont.fontInfo().family());
|
|
|
|
basefont.fontInfo().setSeries(save_basefont.fontInfo().series());
|
2020-08-12 09:04:17 +00:00
|
|
|
}
|
2017-06-03 15:26:05 +00:00
|
|
|
if (incremented)
|
|
|
|
--parInline;
|
2020-01-12 17:35:15 +00:00
|
|
|
|
2020-11-29 23:03:35 +00:00
|
|
|
if (runparams.ctObject == CtObject::DisplayObject
|
|
|
|
|| runparams.ctObject == CtObject::UDisplayObject) {
|
2020-01-12 17:35:15 +00:00
|
|
|
// Close \lyx*deleted and force its
|
|
|
|
// reopening (if needed)
|
|
|
|
os << '}';
|
|
|
|
column++;
|
|
|
|
runningChange = Change(Change::UNCHANGED);
|
2020-11-29 23:03:35 +00:00
|
|
|
runparams.ctObject = CtObject::Normal;
|
2020-01-12 17:35:15 +00:00
|
|
|
}
|
2008-11-16 18:14:14 +00:00
|
|
|
}
|
2016-10-20 23:58:45 +00:00
|
|
|
} else if (i >= start_pos && (end_pos == -1 || i < end_pos)) {
|
2019-03-11 14:24:22 +00:00
|
|
|
if (!bparams.useNonTeXFonts)
|
|
|
|
script = Encodings::isKnownScriptChar(c);
|
|
|
|
if (script != alien_script) {
|
|
|
|
if (!alien_script.empty()) {
|
|
|
|
os << "}";
|
|
|
|
alien_script.clear();
|
|
|
|
}
|
|
|
|
string fontenc = running_font.language()->fontenc(bparams);
|
|
|
|
if (!script.empty()
|
|
|
|
&& !Encodings::fontencSupportsScript(fontenc, script)) {
|
|
|
|
column += script.length() + 2;
|
|
|
|
os << "\\" << script << "{";
|
|
|
|
alien_script = script;
|
|
|
|
}
|
|
|
|
}
|
2016-10-20 23:58:45 +00:00
|
|
|
try {
|
2019-05-25 23:45:35 +00:00
|
|
|
d->latexSpecialChar(os, bparams, rp, running_font,
|
2019-03-11 14:24:22 +00:00
|
|
|
alien_script, style, i, end_pos, column);
|
2016-10-20 23:58:45 +00:00
|
|
|
} catch (EncodingException & e) {
|
2007-12-24 13:55:01 +00:00
|
|
|
if (runparams.dryrun) {
|
2007-12-30 21:28:38 +00:00
|
|
|
os << "<" << _("LyX Warning: ")
|
|
|
|
<< _("uncodable character") << " '";
|
2007-12-24 13:55:01 +00:00
|
|
|
os.put(c);
|
2007-12-30 21:28:38 +00:00
|
|
|
os << "'>";
|
2007-12-24 13:55:01 +00:00
|
|
|
} else {
|
|
|
|
// add location information and throw again.
|
|
|
|
e.par_id = id();
|
|
|
|
e.pos = i;
|
2020-10-09 17:42:51 +00:00
|
|
|
throw;
|
2007-12-24 13:55:01 +00:00
|
|
|
}
|
2007-12-18 17:51:20 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-20 01:28:20 +00:00
|
|
|
|
2008-07-04 14:28:13 +00:00
|
|
|
// Set the encoding to that returned from latexSpecialChar (see
|
2007-07-20 01:28:20 +00:00
|
|
|
// comment for encoding member in OutputParams.h)
|
|
|
|
runparams.encoding = rp.encoding;
|
2016-10-20 23:35:39 +00:00
|
|
|
|
|
|
|
// Also carry on the info on a closed ulem command for insets
|
|
|
|
// such as Note that do not produce any output, so that no
|
|
|
|
// command is ever executed but its opening was recorded.
|
|
|
|
runparams.inulemcmd = rp.inulemcmd;
|
2019-03-14 13:24:43 +00:00
|
|
|
|
2020-07-03 14:18:53 +00:00
|
|
|
// These need to be passed upstream as well
|
|
|
|
runparams.need_maketitle = rp.need_maketitle;
|
|
|
|
runparams.have_maketitle = rp.have_maketitle;
|
|
|
|
|
2019-03-14 13:24:43 +00:00
|
|
|
// And finally, pass the post_macros upstream
|
|
|
|
runparams.post_macro = rp.post_macro;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2019-08-16 09:48:57 +00:00
|
|
|
// Close wrapper for alien script
|
2019-03-11 14:24:22 +00:00
|
|
|
if (!alien_script.empty()) {
|
|
|
|
os << "}";
|
|
|
|
alien_script.clear();
|
2019-05-25 23:45:35 +00:00
|
|
|
}
|
2019-03-11 14:24:22 +00:00
|
|
|
|
2020-12-02 13:32:05 +00:00
|
|
|
Font const font = empty()
|
|
|
|
? getLayoutFont(bparams, real_outerfont)
|
|
|
|
: getFont(bparams, size() - 1, real_outerfont);
|
|
|
|
|
|
|
|
InsetText const * textinset = inInset().asInsetText();
|
|
|
|
|
|
|
|
bool const maintext = textinset
|
|
|
|
? textinset->text().isMainText()
|
|
|
|
: false;
|
|
|
|
|
|
|
|
size_t const numpars = textinset
|
|
|
|
? textinset->text().paragraphs().size()
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
bool needPar = false;
|
|
|
|
|
|
|
|
if (style.resfont.size() != font.fontInfo().size()
|
|
|
|
&& (!runparams.isLastPar || maintext
|
|
|
|
|| (numpars > 1 && d->ownerCode() != CELL_CODE
|
|
|
|
&& (inInset().getLayout().isDisplay()
|
|
|
|
|| parInline)))
|
|
|
|
&& !style.isCommand()) {
|
|
|
|
needPar = true;
|
|
|
|
}
|
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
// If we have an open font definition, we have to close it
|
|
|
|
if (open_font) {
|
2017-06-03 15:26:05 +00:00
|
|
|
// Make sure that \\par is done with the font of the last
|
|
|
|
// character if this has another size as the default.
|
|
|
|
// This is necessary because LaTeX (and LyX on the screen)
|
|
|
|
// calculates the space between the baselines according
|
|
|
|
// to this font. (Matthias)
|
|
|
|
//
|
|
|
|
// We must not change the font for the last paragraph
|
|
|
|
// of non-multipar insets, tabular cells or commands,
|
|
|
|
// since this produces unwanted whitespace.
|
2001-07-27 12:03:36 +00:00
|
|
|
#ifdef FIXED_LANGUAGE_END_DETECTION
|
2001-04-27 07:19:08 +00:00
|
|
|
if (next_) {
|
2010-06-15 15:37:39 +00:00
|
|
|
running_font.latexWriteEndChanges(os, bparams,
|
|
|
|
runparams, basefont,
|
2017-06-03 15:26:05 +00:00
|
|
|
next_->getFont(bparams, 0, outerfont),
|
|
|
|
needPar);
|
2001-04-27 07:19:08 +00:00
|
|
|
} else {
|
2007-05-06 20:26:02 +00:00
|
|
|
running_font.latexWriteEndChanges(os, bparams,
|
2017-06-03 15:26:05 +00:00
|
|
|
runparams, basefont, basefont, needPar);
|
2001-04-27 07:19:08 +00:00
|
|
|
}
|
2001-07-27 12:03:36 +00:00
|
|
|
#else
|
2007-08-10 11:47:12 +00:00
|
|
|
//FIXME: For now we ALWAYS have to close the foreign font settings if they are
|
|
|
|
//FIXME: there as we start another \selectlanguage with the next paragraph if
|
|
|
|
//FIXME: we are in need of this. This should be fixed sometime (Jug)
|
2007-05-06 20:26:02 +00:00
|
|
|
running_font.latexWriteEndChanges(os, bparams, runparams,
|
2020-08-14 16:01:26 +00:00
|
|
|
basefont, basefont, needPar);
|
2001-07-27 12:03:36 +00:00
|
|
|
#endif
|
2020-12-02 13:32:05 +00:00
|
|
|
}
|
|
|
|
if (needPar) {
|
|
|
|
// The \par could not be inserted at the same nesting
|
|
|
|
// level of the font size change, so do it now.
|
|
|
|
os << "{\\" << font.latexSize() << "\\par}";
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
2009-10-12 16:22:05 +00:00
|
|
|
column += Changes::latexMarkChange(os, bparams, runningChange,
|
|
|
|
Change(Change::UNCHANGED), runparams);
|
2007-02-09 23:52:22 +00:00
|
|
|
|
2000-01-11 01:59:00 +00:00
|
|
|
// Needed if there is an optional argument but no contents.
|
2003-03-09 12:37:22 +00:00
|
|
|
if (body_pos > 0 && body_pos == size()) {
|
2010-01-24 10:32:22 +00:00
|
|
|
os << "}]~";
|
1999-11-04 01:40:20 +00:00
|
|
|
}
|
1999-11-15 12:01:38 +00:00
|
|
|
|
2012-11-25 18:10:16 +00:00
|
|
|
if (!style.rightdelim().empty()) {
|
|
|
|
os << style.rightdelim();
|
|
|
|
column += style.rightdelim().size();
|
|
|
|
}
|
|
|
|
|
2011-02-10 20:02:48 +00:00
|
|
|
if (allowcust && d->endTeXParParams(bparams, os, runparams)
|
2009-09-16 20:50:40 +00:00
|
|
|
&& runparams.encoding != prev_encoding) {
|
2009-08-03 18:31:20 +00:00
|
|
|
runparams.encoding = prev_encoding;
|
2015-11-12 15:55:04 +00:00
|
|
|
os << setEncoding(prev_encoding->iconvName());
|
2009-09-16 20:50:40 +00:00
|
|
|
}
|
2001-06-27 14:10:35 +00:00
|
|
|
|
2008-10-06 10:14:41 +00:00
|
|
|
LYXERR(Debug::LATEX, "Paragraph::latex... done " << this);
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-30 13:05:31 +00:00
|
|
|
bool Paragraph::emptyTag() const
|
|
|
|
{
|
|
|
|
for (pos_type i = 0; i < size(); ++i) {
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset const * inset = getInset(i)) {
|
2007-10-13 09:04:52 +00:00
|
|
|
InsetCode lyx_code = inset->lyxCode();
|
2009-07-16 10:08:13 +00:00
|
|
|
// FIXME testing like that is wrong. What is
|
|
|
|
// the intent?
|
2007-10-13 09:04:52 +00:00
|
|
|
if (lyx_code != TOC_CODE &&
|
|
|
|
lyx_code != INCLUDE_CODE &&
|
|
|
|
lyx_code != GRAPHICS_CODE &&
|
|
|
|
lyx_code != ERT_CODE &&
|
|
|
|
lyx_code != LISTINGS_CODE &&
|
|
|
|
lyx_code != FLOAT_CODE &&
|
|
|
|
lyx_code != TABULAR_CODE) {
|
2004-10-30 13:05:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type c = d->text_[i];
|
2005-01-06 15:40:49 +00:00
|
|
|
if (c != ' ' && c != '\t')
|
2004-10-30 13:05:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-09 23:35:40 +00:00
|
|
|
string Paragraph::getID(Buffer const &, OutputParams const &)
|
2008-02-27 20:43:16 +00:00
|
|
|
const
|
2004-05-14 15:47:35 +00:00
|
|
|
{
|
|
|
|
for (pos_type i = 0; i < size(); ++i) {
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset const * inset = getInset(i)) {
|
2007-10-13 09:04:52 +00:00
|
|
|
InsetCode lyx_code = inset->lyxCode();
|
|
|
|
if (lyx_code == LABEL_CODE) {
|
2007-10-23 18:51:04 +00:00
|
|
|
InsetLabel const * const il = static_cast<InsetLabel const *>(inset);
|
|
|
|
docstring const & id = il->getParam("name");
|
2019-05-09 23:35:40 +00:00
|
|
|
return "id='" + to_utf8(xml::cleanID(id)) + "'";
|
2004-05-14 15:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-08 21:27:49 +00:00
|
|
|
pos_type Paragraph::firstWordDocBook(XMLStream & xs, OutputParams const & runparams) const
|
2004-10-24 23:53:42 +00:00
|
|
|
{
|
|
|
|
pos_type i;
|
|
|
|
for (i = 0; i < size(); ++i) {
|
2008-02-09 10:41:49 +00:00
|
|
|
if (Inset const * inset = getInset(i)) {
|
2020-06-08 21:27:49 +00:00
|
|
|
inset->docbook(xs, runparams);
|
2004-10-24 23:53:42 +00:00
|
|
|
} else {
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type c = d->text_[i];
|
2004-10-24 23:53:42 +00:00
|
|
|
if (c == ' ')
|
|
|
|
break;
|
2020-06-08 21:27:49 +00:00
|
|
|
xs << c;
|
2007-05-28 22:27:45 +00:00
|
|
|
}
|
2004-10-24 23:53:42 +00:00
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2004-10-30 22:14:02 +00:00
|
|
|
|
2019-05-09 23:35:40 +00:00
|
|
|
pos_type Paragraph::firstWordLyXHTML(XMLStream & xs, OutputParams const & runparams)
|
2009-06-05 17:44:35 +00:00
|
|
|
const
|
|
|
|
{
|
|
|
|
pos_type i;
|
|
|
|
for (i = 0; i < size(); ++i) {
|
|
|
|
if (Inset const * inset = getInset(i)) {
|
2009-11-19 20:25:40 +00:00
|
|
|
inset->xhtml(xs, runparams);
|
2009-06-05 17:44:35 +00:00
|
|
|
} else {
|
|
|
|
char_type c = d->text_[i];
|
|
|
|
if (c == ' ')
|
|
|
|
break;
|
2009-12-10 20:19:41 +00:00
|
|
|
xs << c;
|
2009-06-05 17:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 15:32:43 +00:00
|
|
|
bool Paragraph::Private::onlyText(Buffer const & buf, Font const & outerfont, pos_type initial) const
|
2004-10-30 22:14:02 +00:00
|
|
|
{
|
2007-04-29 18:17:15 +00:00
|
|
|
Font font_old;
|
2007-10-24 15:32:43 +00:00
|
|
|
pos_type size = text_.size();
|
|
|
|
for (pos_type i = initial; i < size; ++i) {
|
|
|
|
Font font = owner_->getFont(buf.params(), i, outerfont);
|
|
|
|
if (text_[i] == META_INSET)
|
2004-10-30 22:14:02 +00:00
|
|
|
return false;
|
2005-01-06 15:40:49 +00:00
|
|
|
if (i != initial && font != font_old)
|
2004-10-30 22:14:02 +00:00
|
|
|
return false;
|
|
|
|
font_old = font;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-08 21:27:49 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void doFontSwitchDocBook(vector<xml::FontTag> & tagsToOpen,
|
|
|
|
vector<xml::EndFontTag> & tagsToClose,
|
|
|
|
bool & flag, FontState curstate, xml::FontTypes type)
|
2003-10-30 08:47:16 +00:00
|
|
|
{
|
2020-07-08 16:15:34 +00:00
|
|
|
if (curstate == FONT_ON) {
|
|
|
|
tagsToOpen.push_back(docbookStartFontTag(type));
|
|
|
|
flag = true;
|
|
|
|
} else if (flag) {
|
|
|
|
tagsToClose.push_back(docbookEndFontTag(type));
|
|
|
|
flag = false;
|
|
|
|
}
|
2020-06-08 21:27:49 +00:00
|
|
|
}
|
2003-10-30 08:47:16 +00:00
|
|
|
|
2020-06-08 21:27:49 +00:00
|
|
|
class OptionalFontType {
|
|
|
|
public:
|
|
|
|
xml::FontTypes ft;
|
2020-08-01 05:57:38 +00:00
|
|
|
bool has_value;
|
2003-10-30 08:47:16 +00:00
|
|
|
|
2020-08-01 05:57:38 +00:00
|
|
|
OptionalFontType(): ft(xml::FT_EMPH), has_value(false) {} // A possible value at random for ft.
|
|
|
|
OptionalFontType(xml::FontTypes ft): ft(ft), has_value(true) {}
|
2020-06-08 21:27:49 +00:00
|
|
|
};
|
2003-10-30 08:47:16 +00:00
|
|
|
|
2020-06-08 21:27:49 +00:00
|
|
|
OptionalFontType fontShapeToXml(FontShape fs)
|
|
|
|
{
|
2020-07-08 16:15:34 +00:00
|
|
|
switch (fs) {
|
|
|
|
case ITALIC_SHAPE:
|
2020-06-08 21:27:49 +00:00
|
|
|
return {xml::FT_ITALIC};
|
2020-07-08 16:15:34 +00:00
|
|
|
case SLANTED_SHAPE:
|
|
|
|
return {xml::FT_SLANTED};
|
|
|
|
case SMALLCAPS_SHAPE:
|
|
|
|
return {xml::FT_SMALLCAPS};
|
|
|
|
case UP_SHAPE:
|
|
|
|
case INHERIT_SHAPE:
|
|
|
|
return {};
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
return {};
|
|
|
|
}
|
2020-06-08 21:27:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OptionalFontType fontFamilyToXml(FontFamily fm)
|
|
|
|
{
|
2020-07-08 16:15:34 +00:00
|
|
|
switch (fm) {
|
|
|
|
case ROMAN_FAMILY:
|
|
|
|
return {xml::FT_ROMAN};
|
|
|
|
case SANS_FAMILY:
|
|
|
|
return {xml::FT_SANS};
|
|
|
|
case TYPEWRITER_FAMILY:
|
|
|
|
return {xml::FT_TYPE};
|
|
|
|
case INHERIT_FAMILY:
|
|
|
|
return {};
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
return {};
|
|
|
|
}
|
2020-06-08 21:27:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
OptionalFontType fontSizeToXml(FontSize fs)
|
|
|
|
{
|
|
|
|
switch (fs) {
|
|
|
|
case TINY_SIZE:
|
|
|
|
return {xml::FT_SIZE_TINY};
|
|
|
|
case SCRIPT_SIZE:
|
|
|
|
return {xml::FT_SIZE_SCRIPT};
|
|
|
|
case FOOTNOTE_SIZE:
|
|
|
|
return {xml::FT_SIZE_FOOTNOTE};
|
|
|
|
case SMALL_SIZE:
|
|
|
|
return {xml::FT_SIZE_SMALL};
|
|
|
|
case LARGE_SIZE:
|
|
|
|
return {xml::FT_SIZE_LARGE};
|
|
|
|
case LARGER_SIZE:
|
|
|
|
return {xml::FT_SIZE_LARGER};
|
|
|
|
case LARGEST_SIZE:
|
|
|
|
return {xml::FT_SIZE_LARGEST};
|
|
|
|
case HUGE_SIZE:
|
|
|
|
return {xml::FT_SIZE_HUGE};
|
|
|
|
case HUGER_SIZE:
|
|
|
|
return {xml::FT_SIZE_HUGER};
|
|
|
|
case INCREASE_SIZE:
|
|
|
|
return {xml::FT_SIZE_INCREASE};
|
|
|
|
case DECREASE_SIZE:
|
|
|
|
return {xml::FT_SIZE_DECREASE};
|
|
|
|
case INHERIT_SIZE:
|
|
|
|
case NORMAL_SIZE:
|
|
|
|
return {};
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
return {};
|
2003-10-30 08:47:16 +00:00
|
|
|
}
|
2020-06-08 21:27:49 +00:00
|
|
|
}
|
2003-10-30 08:47:16 +00:00
|
|
|
|
2020-07-30 21:15:54 +00:00
|
|
|
struct DocBookFontState
|
2020-06-08 21:27:49 +00:00
|
|
|
{
|
2020-08-01 05:57:38 +00:00
|
|
|
FontShape curr_fs = INHERIT_SHAPE;
|
|
|
|
FontFamily curr_fam = INHERIT_FAMILY;
|
|
|
|
FontSize curr_size = INHERIT_SIZE;
|
|
|
|
|
2020-07-08 16:15:34 +00:00
|
|
|
// track whether we have opened these tags
|
|
|
|
bool emph_flag = false;
|
|
|
|
bool bold_flag = false;
|
|
|
|
bool noun_flag = false;
|
|
|
|
bool ubar_flag = false;
|
|
|
|
bool dbar_flag = false;
|
|
|
|
bool sout_flag = false;
|
2020-07-30 21:15:54 +00:00
|
|
|
bool xout_flag = false;
|
2020-07-08 16:15:34 +00:00
|
|
|
bool wave_flag = false;
|
|
|
|
// shape tags
|
|
|
|
bool shap_flag = false;
|
|
|
|
// family tags
|
|
|
|
bool faml_flag = false;
|
|
|
|
// size tags
|
|
|
|
bool size_flag = false;
|
2020-07-30 21:15:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
std::tuple<vector<xml::FontTag>, vector<xml::EndFontTag>> computeDocBookFontSwitch(FontInfo const & font_old,
|
|
|
|
Font const & font,
|
|
|
|
std::string const & default_family,
|
2020-08-01 19:40:26 +00:00
|
|
|
DocBookFontState & fs)
|
2020-07-30 21:15:54 +00:00
|
|
|
{
|
|
|
|
vector<xml::FontTag> tagsToOpen;
|
|
|
|
vector<xml::EndFontTag> tagsToClose;
|
|
|
|
|
|
|
|
// emphasis
|
|
|
|
FontState curstate = font.fontInfo().emph();
|
|
|
|
if (font_old.emph() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.emph_flag, curstate, xml::FT_EMPH);
|
|
|
|
|
|
|
|
// noun
|
|
|
|
curstate = font.fontInfo().noun();
|
|
|
|
if (font_old.noun() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.noun_flag, curstate, xml::FT_NOUN);
|
|
|
|
|
|
|
|
// underbar
|
|
|
|
curstate = font.fontInfo().underbar();
|
|
|
|
if (font_old.underbar() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.ubar_flag, curstate, xml::FT_UBAR);
|
|
|
|
|
|
|
|
// strikeout
|
|
|
|
curstate = font.fontInfo().strikeout();
|
|
|
|
if (font_old.strikeout() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.sout_flag, curstate, xml::FT_SOUT);
|
|
|
|
|
2020-08-01 19:40:26 +00:00
|
|
|
// xout
|
|
|
|
curstate = font.fontInfo().xout();
|
|
|
|
if (font_old.xout() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.xout_flag, curstate, xml::FT_XOUT);
|
|
|
|
|
2020-07-30 21:15:54 +00:00
|
|
|
// double underbar
|
|
|
|
curstate = font.fontInfo().uuline();
|
|
|
|
if (font_old.uuline() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.dbar_flag, curstate, xml::FT_DBAR);
|
|
|
|
|
|
|
|
// wavy line
|
|
|
|
curstate = font.fontInfo().uwave();
|
|
|
|
if (font_old.uwave() != curstate)
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.wave_flag, curstate, xml::FT_WAVE);
|
|
|
|
|
|
|
|
// bold
|
|
|
|
// a little hackish, but allows us to reuse what we have.
|
|
|
|
curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF);
|
|
|
|
if (font_old.series() != font.fontInfo().series())
|
|
|
|
doFontSwitchDocBook(tagsToOpen, tagsToClose, fs.bold_flag, curstate, xml::FT_BOLD);
|
|
|
|
|
|
|
|
// Font shape
|
|
|
|
fs.curr_fs = font.fontInfo().shape();
|
|
|
|
FontShape old_fs = font_old.shape();
|
|
|
|
if (old_fs != fs.curr_fs) {
|
|
|
|
if (fs.shap_flag) {
|
|
|
|
OptionalFontType tag = fontShapeToXml(old_fs);
|
2020-08-01 19:40:26 +00:00
|
|
|
if (tag.has_value)
|
2020-07-30 21:15:54 +00:00
|
|
|
tagsToClose.push_back(docbookEndFontTag(tag.ft));
|
|
|
|
fs.shap_flag = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalFontType tag = fontShapeToXml(fs.curr_fs);
|
2020-08-01 19:40:26 +00:00
|
|
|
if (tag.has_value)
|
2020-07-30 21:15:54 +00:00
|
|
|
tagsToOpen.push_back(docbookStartFontTag(tag.ft));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Font family
|
|
|
|
fs.curr_fam = font.fontInfo().family();
|
|
|
|
FontFamily old_fam = font_old.family();
|
|
|
|
if (old_fam != fs.curr_fam) {
|
|
|
|
if (fs.faml_flag) {
|
|
|
|
OptionalFontType tag = fontFamilyToXml(old_fam);
|
2020-08-01 19:40:26 +00:00
|
|
|
if (tag.has_value)
|
2020-07-30 21:15:54 +00:00
|
|
|
tagsToClose.push_back(docbookEndFontTag(tag.ft));
|
|
|
|
fs.faml_flag = false;
|
|
|
|
}
|
|
|
|
switch (fs.curr_fam) {
|
|
|
|
case ROMAN_FAMILY:
|
|
|
|
// we will treat a "default" font family as roman, since we have
|
|
|
|
// no other idea what to do.
|
|
|
|
if (default_family != "rmdefault" && default_family != "default") {
|
|
|
|
tagsToOpen.push_back(docbookStartFontTag(xml::FT_ROMAN));
|
|
|
|
fs.faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SANS_FAMILY:
|
|
|
|
if (default_family != "sfdefault") {
|
|
|
|
tagsToOpen.push_back(docbookStartFontTag(xml::FT_SANS));
|
|
|
|
fs.faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TYPEWRITER_FAMILY:
|
|
|
|
if (default_family != "ttdefault") {
|
|
|
|
tagsToOpen.push_back(docbookStartFontTag(xml::FT_TYPE));
|
|
|
|
fs.faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INHERIT_FAMILY:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Font size
|
|
|
|
fs.curr_size = font.fontInfo().size();
|
|
|
|
FontSize old_size = font_old.size();
|
|
|
|
if (old_size != fs.curr_size) {
|
|
|
|
if (fs.size_flag) {
|
|
|
|
OptionalFontType tag = fontSizeToXml(old_size);
|
2020-08-01 19:40:26 +00:00
|
|
|
if (tag.has_value)
|
2020-07-30 21:15:54 +00:00
|
|
|
tagsToClose.push_back(docbookEndFontTag(tag.ft));
|
|
|
|
fs.size_flag = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalFontType tag = fontSizeToXml(fs.curr_size);
|
|
|
|
if (tag.has_value) {
|
|
|
|
tagsToOpen.push_back(docbookStartFontTag(tag.ft));
|
|
|
|
fs.size_flag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-31 00:23:22 +00:00
|
|
|
return std::tuple<vector<xml::FontTag>, vector<xml::EndFontTag>>(tagsToOpen, tagsToClose);
|
2020-07-30 21:15:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-01 19:40:26 +00:00
|
|
|
} // anonymous namespace
|
2020-07-30 21:15:54 +00:00
|
|
|
|
|
|
|
|
2020-08-26 19:19:38 +00:00
|
|
|
std::vector<docstring> Paragraph::simpleDocBookOnePar(Buffer const & buf,
|
|
|
|
OutputParams const & runparams,
|
|
|
|
Font const & outerfont,
|
2020-08-30 21:56:16 +00:00
|
|
|
pos_type initial,
|
2020-08-30 22:18:35 +00:00
|
|
|
bool is_last_par,
|
|
|
|
bool ignore_fonts) const
|
2020-07-30 21:15:54 +00:00
|
|
|
{
|
2020-08-26 19:19:38 +00:00
|
|
|
// Track whether we have opened these tags
|
2020-07-30 21:15:54 +00:00
|
|
|
DocBookFontState fs;
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-07-30 21:15:54 +00:00
|
|
|
Layout const & style = *d->layout_;
|
2020-07-08 16:15:34 +00:00
|
|
|
FontInfo font_old =
|
|
|
|
style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
|
|
|
|
|
|
|
|
string const default_family =
|
|
|
|
buf.masterBuffer()->params().fonts_default_family;
|
|
|
|
|
|
|
|
vector<xml::FontTag> tagsToOpen;
|
|
|
|
vector<xml::EndFontTag> tagsToClose;
|
|
|
|
|
2020-08-26 19:19:38 +00:00
|
|
|
std::vector<docstring> generatedParagraphs;
|
2020-09-10 23:28:59 +00:00
|
|
|
DocBookFontState old_fs = fs;
|
2020-08-26 19:19:38 +00:00
|
|
|
odocstringstream os;
|
2020-08-29 17:05:59 +00:00
|
|
|
auto * xs = new XMLStream(os); // XMLStream has no copy constructor: to create a new object, the only solution
|
|
|
|
// is to hold a pointer to the XMLStream (xs = XMLStream(os) is not allowed once the first object is built).
|
2020-08-26 19:19:38 +00:00
|
|
|
|
2020-10-05 14:22:58 +00:00
|
|
|
// When a font tag ends with a space, output it after the closing font tag. This requires to store delayed
|
|
|
|
// characters at some point.
|
|
|
|
std::vector<char_type> delayedChars;
|
|
|
|
|
2020-08-26 19:19:38 +00:00
|
|
|
// Parsing main loop.
|
2020-07-08 16:15:34 +00:00
|
|
|
for (pos_type i = initial; i < size(); ++i) {
|
2020-08-26 19:19:38 +00:00
|
|
|
// Don't show deleted material in the output.
|
2020-07-08 16:15:34 +00:00
|
|
|
if (isDeleted(i))
|
|
|
|
continue;
|
|
|
|
|
2020-08-30 21:38:40 +00:00
|
|
|
// If this is an InsetNewline, generate a new paragraph. Also reset the fonts, so that tags are closed in
|
|
|
|
// this paragraph.
|
2020-11-18 00:51:05 +00:00
|
|
|
if (getInset(i) && getInset(i)->lyxCode() == NEWLINE_CODE) {
|
2020-08-30 22:18:35 +00:00
|
|
|
if (!ignore_fonts)
|
|
|
|
xs->closeFontTags();
|
2020-09-19 21:55:07 +00:00
|
|
|
|
|
|
|
// Output one paragraph (i.e. one string entry in generatedParagraphs).
|
2020-08-26 19:19:38 +00:00
|
|
|
generatedParagraphs.push_back(os.str());
|
2020-09-19 21:55:07 +00:00
|
|
|
|
|
|
|
// Create a new XMLStream for the new paragraph, completely independent from the previous one. This implies
|
|
|
|
// that the string stream must be reset.
|
|
|
|
os.str(from_ascii(""));
|
2020-08-26 19:19:38 +00:00
|
|
|
delete xs;
|
|
|
|
xs = new XMLStream(os);
|
2020-09-19 21:55:07 +00:00
|
|
|
|
|
|
|
// Restore the fonts for the new paragraph, so that the right tags are opened for the new entry.
|
2020-09-10 23:28:59 +00:00
|
|
|
if (!ignore_fonts) {
|
2020-08-30 22:18:35 +00:00
|
|
|
font_old = outerfont.fontInfo();
|
2020-09-10 23:28:59 +00:00
|
|
|
fs = old_fs;
|
|
|
|
}
|
2020-08-26 19:19:38 +00:00
|
|
|
}
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-08-30 22:18:35 +00:00
|
|
|
// Determine which tags should be opened or closed regarding fonts.
|
2020-08-26 19:19:38 +00:00
|
|
|
Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
|
2020-08-30 22:18:35 +00:00
|
|
|
if (!ignore_fonts) {
|
|
|
|
tie(tagsToOpen, tagsToClose) = computeDocBookFontSwitch(font_old, font, default_family, fs);
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-08-30 22:18:35 +00:00
|
|
|
// FIXME XHTML
|
|
|
|
// Other such tags? What about the other text ranges?
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-08-30 22:18:35 +00:00
|
|
|
vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
|
|
|
|
vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
|
|
|
|
for (; cit != cen; ++cit)
|
|
|
|
*xs << *cit;
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-10-05 14:22:58 +00:00
|
|
|
// Deal with the delayed characters *after* closing font tags.
|
|
|
|
if (!delayedChars.empty()) {
|
|
|
|
for (char_type c: delayedChars)
|
|
|
|
*xs << c;
|
|
|
|
delayedChars.clear();
|
|
|
|
}
|
|
|
|
|
2020-08-30 22:18:35 +00:00
|
|
|
vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
|
|
|
|
vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
|
|
|
|
for (; sit != sen; ++sit)
|
|
|
|
*xs << *sit;
|
2020-07-08 16:15:34 +00:00
|
|
|
|
2020-08-30 22:18:35 +00:00
|
|
|
tagsToClose.clear();
|
|
|
|
tagsToOpen.clear();
|
|
|
|
}
|
2020-07-08 16:15:34 +00:00
|
|
|
|
|
|
|
if (Inset const * inset = getInset(i)) {
|
|
|
|
if (!runparams.for_toc || inset->isInToc()) {
|
|
|
|
OutputParams np = runparams;
|
|
|
|
np.local_font = &font;
|
2020-08-15 22:59:43 +00:00
|
|
|
|
|
|
|
// TODO: special case will bite here.
|
|
|
|
np.docbook_in_par = true;
|
2020-08-26 19:19:38 +00:00
|
|
|
inset->docbook(*xs, np);
|
2020-07-08 16:15:34 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
char_type c = getUChar(buf.masterBuffer()->params(), runparams, i);
|
2020-10-07 02:43:31 +00:00
|
|
|
if (lyx::isSpace(c) && !ignore_fonts)
|
2020-10-05 14:22:58 +00:00
|
|
|
delayedChars.push_back(c);
|
|
|
|
else
|
|
|
|
*xs << c;
|
2020-07-08 16:15:34 +00:00
|
|
|
}
|
|
|
|
font_old = font.fontInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME, this code is just imported from XHTML
|
|
|
|
// I'm worried about what happens if a branch, say, is itself
|
|
|
|
// wrapped in some font stuff. I think that will not work.
|
2020-08-30 22:18:35 +00:00
|
|
|
if (!ignore_fonts)
|
|
|
|
xs->closeFontTags();
|
2020-08-30 21:56:16 +00:00
|
|
|
|
2020-10-05 14:22:58 +00:00
|
|
|
// Deal with the delayed characters *after* closing font tags.
|
|
|
|
if (!delayedChars.empty())
|
|
|
|
for (char_type c: delayedChars)
|
|
|
|
*xs << c;
|
|
|
|
|
|
|
|
// In listings, new lines (i.e. \n characters in the output) are very important. Avoid generating one for the
|
|
|
|
// last line to get a clean output.
|
2020-08-30 21:56:16 +00:00
|
|
|
if (runparams.docbook_in_listing && !is_last_par)
|
2020-08-26 19:19:38 +00:00
|
|
|
*xs << xml::CR();
|
|
|
|
|
|
|
|
// Finalise the last (and most likely only) paragraph.
|
|
|
|
generatedParagraphs.push_back(os.str());
|
|
|
|
delete xs;
|
|
|
|
|
|
|
|
return generatedParagraphs;
|
2003-10-30 08:47:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-07 06:34:15 +00:00
|
|
|
namespace {
|
2019-05-09 23:35:40 +00:00
|
|
|
|
|
|
|
void doFontSwitchXHTML(vector<xml::FontTag> & tagsToOpen,
|
|
|
|
vector<xml::EndFontTag> & tagsToClose,
|
|
|
|
bool & flag, FontState curstate, xml::FontTypes type)
|
2013-03-27 16:49:03 +00:00
|
|
|
{
|
|
|
|
if (curstate == FONT_ON) {
|
2019-05-09 23:35:40 +00:00
|
|
|
tagsToOpen.push_back(xhtmlStartFontTag(type));
|
2013-03-27 16:49:03 +00:00
|
|
|
flag = true;
|
2013-05-10 20:58:38 +00:00
|
|
|
} else if (flag) {
|
2019-05-09 23:35:40 +00:00
|
|
|
tagsToClose.push_back(xhtmlEndFontTag(type));
|
2013-03-27 16:49:03 +00:00
|
|
|
flag = false;
|
|
|
|
}
|
|
|
|
}
|
2019-05-09 23:35:40 +00:00
|
|
|
|
|
|
|
} // anonymous namespace
|
2013-03-27 16:49:03 +00:00
|
|
|
|
|
|
|
|
2009-06-12 17:23:17 +00:00
|
|
|
docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf,
|
2020-06-15 21:28:27 +00:00
|
|
|
XMLStream & xs,
|
|
|
|
OutputParams const & runparams,
|
|
|
|
Font const & outerfont,
|
|
|
|
bool start_paragraph, bool close_paragraph,
|
|
|
|
pos_type initial) const
|
2009-06-05 17:44:35 +00:00
|
|
|
{
|
2009-06-12 17:23:17 +00:00
|
|
|
docstring retval;
|
|
|
|
|
2013-05-10 20:58:38 +00:00
|
|
|
// track whether we have opened these tags
|
2009-06-05 17:44:35 +00:00
|
|
|
bool emph_flag = false;
|
|
|
|
bool bold_flag = false;
|
2013-03-27 16:49:03 +00:00
|
|
|
bool noun_flag = false;
|
|
|
|
bool ubar_flag = false;
|
|
|
|
bool dbar_flag = false;
|
|
|
|
bool sout_flag = false;
|
2017-04-04 22:01:19 +00:00
|
|
|
bool xout_flag = false;
|
2013-03-27 16:49:03 +00:00
|
|
|
bool wave_flag = false;
|
2013-05-10 20:58:38 +00:00
|
|
|
// shape tags
|
|
|
|
bool shap_flag = false;
|
2013-05-13 15:58:52 +00:00
|
|
|
// family tags
|
|
|
|
bool faml_flag = false;
|
2013-05-13 16:22:41 +00:00
|
|
|
// size tags
|
|
|
|
bool size_flag = false;
|
2009-06-05 17:44:35 +00:00
|
|
|
|
|
|
|
Layout const & style = *d->layout_;
|
2009-12-10 20:03:35 +00:00
|
|
|
|
2016-07-10 03:12:32 +00:00
|
|
|
if (start_paragraph)
|
2016-07-10 03:53:18 +00:00
|
|
|
xs.startDivision(allowEmpty());
|
2011-04-03 01:56:20 +00:00
|
|
|
|
2009-06-05 17:44:35 +00:00
|
|
|
FontInfo font_old =
|
|
|
|
style.labeltype == LABEL_MANUAL ? style.labelfont : style.font;
|
|
|
|
|
2013-05-13 16:22:41 +00:00
|
|
|
FontShape curr_fs = INHERIT_SHAPE;
|
|
|
|
FontFamily curr_fam = INHERIT_FAMILY;
|
2019-06-14 14:42:02 +00:00
|
|
|
FontSize curr_size = INHERIT_SIZE;
|
2017-07-03 17:53:14 +00:00
|
|
|
|
|
|
|
string const default_family =
|
|
|
|
buf.masterBuffer()->params().fonts_default_family;
|
2013-05-10 20:58:38 +00:00
|
|
|
|
2019-05-09 23:35:40 +00:00
|
|
|
vector<xml::FontTag> tagsToOpen;
|
|
|
|
vector<xml::EndFontTag> tagsToClose;
|
2017-07-03 17:53:14 +00:00
|
|
|
|
2009-06-05 17:44:35 +00:00
|
|
|
// parsing main loop
|
|
|
|
for (pos_type i = initial; i < size(); ++i) {
|
2010-01-20 22:42:27 +00:00
|
|
|
// let's not show deleted material in the output
|
|
|
|
if (isDeleted(i))
|
|
|
|
continue;
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2013-05-03 01:23:11 +00:00
|
|
|
Font const font = getFont(buf.masterBuffer()->params(), i, outerfont);
|
2009-06-05 17:44:35 +00:00
|
|
|
|
|
|
|
// emphasis
|
2013-03-27 16:49:03 +00:00
|
|
|
FontState curstate = font.fontInfo().emph();
|
|
|
|
if (font_old.emph() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, emph_flag, curstate, xml::FT_EMPH);
|
2013-03-27 16:49:03 +00:00
|
|
|
|
|
|
|
// noun
|
|
|
|
curstate = font.fontInfo().noun();
|
|
|
|
if (font_old.noun() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, noun_flag, curstate, xml::FT_NOUN);
|
2013-03-27 16:49:03 +00:00
|
|
|
|
|
|
|
// underbar
|
|
|
|
curstate = font.fontInfo().underbar();
|
|
|
|
if (font_old.underbar() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, ubar_flag, curstate, xml::FT_UBAR);
|
2017-07-03 17:53:14 +00:00
|
|
|
|
2013-03-27 16:49:03 +00:00
|
|
|
// strikeout
|
|
|
|
curstate = font.fontInfo().strikeout();
|
|
|
|
if (font_old.strikeout() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, sout_flag, curstate, xml::FT_SOUT);
|
2013-03-27 16:49:03 +00:00
|
|
|
|
2017-04-04 22:01:19 +00:00
|
|
|
// xout
|
|
|
|
curstate = font.fontInfo().xout();
|
|
|
|
if (font_old.xout() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, xout_flag, curstate, xml::FT_XOUT);
|
2017-04-04 22:01:19 +00:00
|
|
|
|
2013-03-27 16:49:03 +00:00
|
|
|
// double underbar
|
|
|
|
curstate = font.fontInfo().uuline();
|
|
|
|
if (font_old.uuline() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, dbar_flag, curstate, xml::FT_DBAR);
|
2013-03-27 16:49:03 +00:00
|
|
|
|
|
|
|
// wavy line
|
|
|
|
curstate = font.fontInfo().uwave();
|
|
|
|
if (font_old.uwave() != curstate)
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, wave_flag, curstate, xml::FT_WAVE);
|
2013-03-27 16:49:03 +00:00
|
|
|
|
2009-06-05 17:44:35 +00:00
|
|
|
// bold
|
2013-05-07 06:34:15 +00:00
|
|
|
// a little hackish, but allows us to reuse what we have.
|
|
|
|
curstate = (font.fontInfo().series() == BOLD_SERIES ? FONT_ON : FONT_OFF);
|
|
|
|
if (font_old.series() != font.fontInfo().series())
|
2019-05-09 23:35:40 +00:00
|
|
|
doFontSwitchXHTML(tagsToOpen, tagsToClose, bold_flag, curstate, xml::FT_BOLD);
|
2013-05-10 20:58:38 +00:00
|
|
|
|
2013-05-13 16:22:41 +00:00
|
|
|
// Font shape
|
2013-05-10 20:58:38 +00:00
|
|
|
curr_fs = font.fontInfo().shape();
|
|
|
|
FontShape old_fs = font_old.shape();
|
|
|
|
if (old_fs != curr_fs) {
|
2020-06-15 21:28:27 +00:00
|
|
|
if (shap_flag) {
|
|
|
|
switch (old_fs) {
|
|
|
|
case ITALIC_SHAPE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_ITALIC));
|
|
|
|
break;
|
|
|
|
case SLANTED_SHAPE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SLANTED));
|
|
|
|
break;
|
|
|
|
case SMALLCAPS_SHAPE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SMALLCAPS));
|
|
|
|
break;
|
|
|
|
case UP_SHAPE:
|
|
|
|
case INHERIT_SHAPE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
shap_flag = false;
|
|
|
|
}
|
|
|
|
switch (curr_fs) {
|
|
|
|
case ITALIC_SHAPE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_ITALIC));
|
|
|
|
shap_flag = true;
|
|
|
|
break;
|
|
|
|
case SLANTED_SHAPE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SLANTED));
|
|
|
|
shap_flag = true;
|
|
|
|
break;
|
|
|
|
case SMALLCAPS_SHAPE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SMALLCAPS));
|
|
|
|
shap_flag = true;
|
|
|
|
break;
|
|
|
|
case UP_SHAPE:
|
|
|
|
case INHERIT_SHAPE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
2013-05-13 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
2013-05-13 16:22:41 +00:00
|
|
|
// Font family
|
2013-05-13 15:58:52 +00:00
|
|
|
curr_fam = font.fontInfo().family();
|
|
|
|
FontFamily old_fam = font_old.family();
|
|
|
|
if (old_fam != curr_fam) {
|
2020-06-15 21:28:27 +00:00
|
|
|
if (faml_flag) {
|
|
|
|
switch (old_fam) {
|
|
|
|
case ROMAN_FAMILY:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_ROMAN));
|
|
|
|
break;
|
|
|
|
case SANS_FAMILY:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SANS));
|
|
|
|
break;
|
|
|
|
case TYPEWRITER_FAMILY:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_TYPE));
|
|
|
|
break;
|
|
|
|
case INHERIT_FAMILY:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
faml_flag = false;
|
|
|
|
}
|
|
|
|
switch (curr_fam) {
|
|
|
|
case ROMAN_FAMILY:
|
|
|
|
// we will treat a "default" font family as roman, since we have
|
|
|
|
// no other idea what to do.
|
|
|
|
if (default_family != "rmdefault" && default_family != "default") {
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_ROMAN));
|
|
|
|
faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SANS_FAMILY:
|
|
|
|
if (default_family != "sfdefault") {
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SANS));
|
|
|
|
faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TYPEWRITER_FAMILY:
|
|
|
|
if (default_family != "ttdefault") {
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_TYPE));
|
|
|
|
faml_flag = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INHERIT_FAMILY:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
2013-05-10 20:58:38 +00:00
|
|
|
}
|
2013-05-07 06:34:15 +00:00
|
|
|
|
2013-05-13 16:22:41 +00:00
|
|
|
// Font size
|
|
|
|
curr_size = font.fontInfo().size();
|
|
|
|
FontSize old_size = font_old.size();
|
|
|
|
if (old_size != curr_size) {
|
2020-06-15 21:28:27 +00:00
|
|
|
if (size_flag) {
|
|
|
|
switch (old_size) {
|
|
|
|
case TINY_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_TINY));
|
|
|
|
break;
|
|
|
|
case SCRIPT_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_SCRIPT));
|
|
|
|
break;
|
|
|
|
case FOOTNOTE_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_FOOTNOTE));
|
|
|
|
break;
|
|
|
|
case SMALL_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_SMALL));
|
|
|
|
break;
|
|
|
|
case LARGE_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_LARGE));
|
|
|
|
break;
|
|
|
|
case LARGER_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_LARGER));
|
|
|
|
break;
|
|
|
|
case LARGEST_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_LARGEST));
|
|
|
|
break;
|
|
|
|
case HUGE_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_HUGE));
|
|
|
|
break;
|
|
|
|
case HUGER_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_HUGER));
|
|
|
|
break;
|
|
|
|
case INCREASE_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_INCREASE));
|
|
|
|
break;
|
|
|
|
case DECREASE_SIZE:
|
|
|
|
tagsToClose.emplace_back(xhtmlEndFontTag(xml::FT_SIZE_DECREASE));
|
|
|
|
break;
|
|
|
|
case INHERIT_SIZE:
|
|
|
|
case NORMAL_SIZE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
size_flag = false;
|
|
|
|
}
|
|
|
|
switch (curr_size) {
|
|
|
|
case TINY_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_TINY));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case SCRIPT_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_SCRIPT));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case FOOTNOTE_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_FOOTNOTE));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case SMALL_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_SMALL));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case LARGE_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_LARGE));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case LARGER_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_LARGER));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case LARGEST_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_LARGEST));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case HUGE_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_HUGE));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case HUGER_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_HUGER));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case INCREASE_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_INCREASE));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case DECREASE_SIZE:
|
|
|
|
tagsToOpen.emplace_back(xhtmlStartFontTag(xml::FT_SIZE_DECREASE));
|
|
|
|
size_flag = true;
|
|
|
|
break;
|
|
|
|
case INHERIT_SIZE:
|
|
|
|
case NORMAL_SIZE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// the other tags are for internal use
|
|
|
|
LATTEST(false);
|
|
|
|
break;
|
|
|
|
}
|
2013-05-13 16:22:41 +00:00
|
|
|
}
|
|
|
|
|
2009-11-30 23:31:21 +00:00
|
|
|
// FIXME XHTML
|
|
|
|
// Other such tags? What about the other text ranges?
|
2009-06-05 17:44:35 +00:00
|
|
|
|
2019-05-09 23:35:40 +00:00
|
|
|
vector<xml::EndFontTag>::const_iterator cit = tagsToClose.begin();
|
|
|
|
vector<xml::EndFontTag>::const_iterator cen = tagsToClose.end();
|
2013-05-10 20:58:38 +00:00
|
|
|
for (; cit != cen; ++cit)
|
|
|
|
xs << *cit;
|
|
|
|
|
2019-05-09 23:35:40 +00:00
|
|
|
vector<xml::FontTag>::const_iterator sit = tagsToOpen.begin();
|
|
|
|
vector<xml::FontTag>::const_iterator sen = tagsToOpen.end();
|
2013-05-10 20:58:38 +00:00
|
|
|
for (; sit != sen; ++sit)
|
|
|
|
xs << *sit;
|
|
|
|
|
|
|
|
tagsToClose.clear();
|
|
|
|
tagsToOpen.clear();
|
|
|
|
|
2009-10-26 20:53:46 +00:00
|
|
|
Inset const * inset = getInset(i);
|
|
|
|
if (inset) {
|
2010-10-26 01:10:19 +00:00
|
|
|
if (!runparams.for_toc || inset->isInToc()) {
|
2009-12-10 18:30:48 +00:00
|
|
|
OutputParams np = runparams;
|
2013-03-19 15:30:09 +00:00
|
|
|
np.local_font = &font;
|
2016-07-10 03:12:32 +00:00
|
|
|
// If the paragraph has size 1, then we are in the "special
|
|
|
|
// case" where we do not output the containing paragraph info
|
|
|
|
if (!inset->getLayout().htmlisblock() && size() != 1)
|
2009-12-10 18:30:48 +00:00
|
|
|
np.html_in_par = true;
|
|
|
|
retval += inset->xhtml(xs, np);
|
|
|
|
}
|
2009-06-05 17:44:35 +00:00
|
|
|
} else {
|
2018-07-15 12:26:29 +00:00
|
|
|
char_type c = getUChar(buf.masterBuffer()->params(),
|
|
|
|
runparams, i);
|
2019-01-04 00:16:48 +00:00
|
|
|
if (c == ' ' && (style.free_spacing || runparams.free_spacing))
|
2019-05-09 23:35:40 +00:00
|
|
|
xs << XMLStream::ESCAPE_NONE << " ";
|
2019-01-04 00:12:58 +00:00
|
|
|
else
|
|
|
|
xs << c;
|
2009-06-05 17:44:35 +00:00
|
|
|
}
|
|
|
|
font_old = font.fontInfo();
|
|
|
|
}
|
|
|
|
|
2016-07-10 03:12:32 +00:00
|
|
|
// FIXME XHTML
|
|
|
|
// I'm worried about what happens if a branch, say, is itself
|
|
|
|
// wrapped in some font stuff. I think that will not work.
|
2009-11-19 18:24:19 +00:00
|
|
|
xs.closeFontTags();
|
2016-07-10 03:12:32 +00:00
|
|
|
if (close_paragraph)
|
2016-07-10 03:53:18 +00:00
|
|
|
xs.endDivision();
|
2016-07-10 03:12:32 +00:00
|
|
|
|
2009-06-12 17:23:17 +00:00
|
|
|
return retval;
|
2009-06-05 17:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-13 09:48:18 +00:00
|
|
|
bool Paragraph::isHfill(pos_type pos) const
|
|
|
|
{
|
2008-02-09 10:41:49 +00:00
|
|
|
Inset const * inset = getInset(pos);
|
2013-07-18 08:55:52 +00:00
|
|
|
return inset && inset->isHfill();
|
2007-10-13 09:48:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-11-26 16:42:04 +00:00
|
|
|
bool Paragraph::isNewline(pos_type pos) const
|
1999-11-15 12:01:38 +00:00
|
|
|
{
|
2016-11-07 09:14:39 +00:00
|
|
|
// U+2028 LINE SEPARATOR
|
|
|
|
// U+2029 PARAGRAPH SEPARATOR
|
|
|
|
char_type const c = d->text_[pos];
|
|
|
|
if (c == 0x2028 || c == 0x2029)
|
|
|
|
return true;
|
2008-02-09 10:41:49 +00:00
|
|
|
Inset const * inset = getInset(pos);
|
|
|
|
return inset && inset->lyxCode() == NEWLINE_CODE;
|
1999-11-15 12:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Fix bugs #8546 and #9055, and introduce new separator inset.
The algorithm used for breaking a paragraph in LaTeX export is changed
for avoiding spurious blank lines causing too much vertical space.
This change is tied to the introduction of a new inset (with two
different specializations) helping in either outputing LaTeX paragraph
breaks or separating environments in LyX. Both of the above goals were
previously achieved by the ---Separator--- layout and can now be
accomplished by the new inset in a more natural way. As an example,
after leaving an environment by hitting the Return key for two times,
a third return automatically inserts a parbreak inset, which is
equivalent to the old separator layout, i.e., it also introduces a
blank line in the output. If this blank line is not wanted, the
parbreak separator can be changed to a plain separator by a right
click of the mouse. Of course, an environment can still be separated
by the following one by using the Alt+P+Return shortcut (or the
corresponding menu key), but now the plain separator inset is used
instead of the old separator layout, such that no blank line occurs in
the LaTeX output.
Old documents are converted such that the LaTeX output remains unchanged.
As a result of this conversion, the old separator layout is replaced by
the new parbreak inset, which may also appear in places where the old
algorithm was introducing blank lines while the new one is not.
Note that not all blank lines were actually affecting the LaTeX output,
because a blank line is simply ignored by the TeX engine when it occurs
in the so called "vertical mode" (e.g., after an alignment environment).
The old ---Separator--- layout is now gone and old layout files using it
are also automatically converted.
Round trip conversions between old and new format should leave a document
unchanged. This means that the new behavior about paragraph breaking is
not "carried back" to the old format. Indeed, this would need introducing
special LaTeX commands in ERT that would accumulate in roundtrip
conversions, horribly cluttering the document. So, when converting a
modified document to old formats, the LaTeX output may slightly differ in
vertical spacing if the document is processed by an old version of LyX.
In other words, forward compatibility is guaranteed, but not backwards.
2014-05-10 21:25:11 +00:00
|
|
|
bool Paragraph::isEnvSeparator(pos_type pos) const
|
|
|
|
{
|
|
|
|
Inset const * inset = getInset(pos);
|
|
|
|
return inset && inset->lyxCode() == SEPARATOR_CODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-11-26 16:42:04 +00:00
|
|
|
bool Paragraph::isLineSeparator(pos_type pos) const
|
1999-11-15 12:01:38 +00:00
|
|
|
{
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type const c = d->text_[pos];
|
2008-02-09 10:41:49 +00:00
|
|
|
if (isLineSeparatorChar(c))
|
|
|
|
return true;
|
|
|
|
Inset const * inset = getInset(pos);
|
|
|
|
return inset && inset->isLineSeparator();
|
1999-11-15 12:01:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-27 12:01:35 +00:00
|
|
|
bool Paragraph::isWordSeparator(pos_type pos, bool const ignore_deleted) const
|
1999-11-15 12:01:38 +00:00
|
|
|
{
|
2011-01-30 07:17:48 +00:00
|
|
|
if (pos == size())
|
|
|
|
return true;
|
2019-12-27 12:01:35 +00:00
|
|
|
if (ignore_deleted && isDeleted(pos))
|
|
|
|
return false;
|
2011-04-08 13:20:26 +00:00
|
|
|
if (Inset const * inset = getInset(pos))
|
|
|
|
return !inset->isLetter();
|
|
|
|
// if we have a hard hyphen (no en- or emdash) or apostrophe
|
2011-03-18 09:17:09 +00:00
|
|
|
// we pass this to the spell checker
|
2011-04-08 13:20:26 +00:00
|
|
|
// FIXME: this method is subject to change, visit
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=355178
|
|
|
|
// to get an impression how complex this is.
|
|
|
|
if (isHardHyphenOrApostrophe(pos))
|
|
|
|
return false;
|
|
|
|
char_type const c = d->text_[pos];
|
|
|
|
// We want to pass the escape chars to the spellchecker
|
|
|
|
docstring const escape_chars = from_utf8(lyxrc.spellchecker_esc_chars);
|
|
|
|
return !isLetterChar(c) && !isDigitASCII(c) && !contains(escape_chars, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isHardHyphenOrApostrophe(pos_type pos) const
|
|
|
|
{
|
|
|
|
pos_type const psize = size();
|
|
|
|
if (pos >= psize)
|
|
|
|
return false;
|
|
|
|
char_type const c = d->text_[pos];
|
|
|
|
if (c != '-' && c != '\'')
|
|
|
|
return false;
|
2020-09-01 22:00:54 +00:00
|
|
|
pos_type nextpos = pos + 1;
|
|
|
|
pos_type prevpos = pos > 0 ? pos - 1 : 0;
|
2011-04-08 13:20:26 +00:00
|
|
|
if ((nextpos == psize || isSpace(nextpos))
|
|
|
|
&& (pos == 0 || isSpace(prevpos)))
|
|
|
|
return false;
|
2015-02-24 20:58:27 +00:00
|
|
|
return true;
|
1999-11-15 12:01:38 +00:00
|
|
|
}
|
2000-02-22 00:36:17 +00:00
|
|
|
|
2000-04-10 21:40:13 +00:00
|
|
|
|
2018-04-30 07:06:15 +00:00
|
|
|
bool Paragraph::needsCProtection(bool const fragile) const
|
2018-04-13 15:46:37 +00:00
|
|
|
{
|
2018-04-22 18:15:04 +00:00
|
|
|
// first check the layout of the paragraph, but only in insets
|
|
|
|
InsetText const * textinset = inInset().asInsetText();
|
|
|
|
bool const maintext = textinset
|
|
|
|
? textinset->text().isMainText()
|
|
|
|
: false;
|
|
|
|
|
|
|
|
if (!maintext && layout().needcprotect) {
|
2018-04-14 10:57:23 +00:00
|
|
|
// Environments need cprotection regardless the content
|
|
|
|
if (layout().latextype == LATEX_ENVIRONMENT)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Commands need cprotection if they contain specific chars
|
|
|
|
int const nchars_escape = 9;
|
|
|
|
static char_type const chars_escape[nchars_escape] = {
|
|
|
|
'&', '_', '$', '%', '#', '^', '{', '}', '\\'};
|
|
|
|
|
|
|
|
docstring const pars = asString();
|
|
|
|
for (int k = 0; k < nchars_escape; k++) {
|
|
|
|
if (contains(pars, chars_escape[k]))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now check whether we have insets that need cprotection
|
2019-04-21 14:44:29 +00:00
|
|
|
pos_type size = pos_type(d->text_.size());
|
|
|
|
for (pos_type i = 0; i < size; ++i) {
|
|
|
|
if (!isInset(i))
|
|
|
|
continue;
|
|
|
|
Inset const * ins = getInset(i);
|
|
|
|
if (ins->needsCProtection(maintext, fragile))
|
|
|
|
return true;
|
|
|
|
// Now check math environments
|
|
|
|
InsetMath const * im = getInset(i)->asInsetMath();
|
|
|
|
if (!im || im->cell(0).empty())
|
|
|
|
continue;
|
|
|
|
switch(im->cell(0)[0]->lyxCode()) {
|
|
|
|
case MATH_AMSARRAY_CODE:
|
|
|
|
case MATH_SUBSTACK_CODE:
|
|
|
|
case MATH_ENV_CODE:
|
|
|
|
case MATH_XYMATRIX_CODE:
|
|
|
|
// these need cprotection
|
2018-04-15 10:37:41 +00:00
|
|
|
return true;
|
2019-04-21 14:44:29 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-04-13 15:46:37 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-14 21:45:41 +00:00
|
|
|
FontSpan const & Paragraph::getSpellRange(pos_type pos) const
|
2010-12-22 07:29:16 +00:00
|
|
|
{
|
2015-07-14 21:45:41 +00:00
|
|
|
return d->speller_state_.getRange(pos);
|
2010-12-22 07:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-06-24 09:19:52 +00:00
|
|
|
bool Paragraph::isChar(pos_type pos) const
|
|
|
|
{
|
|
|
|
if (Inset const * inset = getInset(pos))
|
|
|
|
return inset->isChar();
|
|
|
|
char_type const c = d->text_[pos];
|
2010-12-07 00:13:19 +00:00
|
|
|
return !isLetterChar(c) && !isDigitASCII(c) && !lyx::isSpace(c);
|
2008-07-01 14:42:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isSpace(pos_type pos) const
|
|
|
|
{
|
|
|
|
if (Inset const * inset = getInset(pos))
|
|
|
|
return inset->isSpace();
|
|
|
|
char_type const c = d->text_[pos];
|
|
|
|
return lyx::isSpace(c);
|
2008-06-24 09:19:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-08 23:16:16 +00:00
|
|
|
Language const *
|
2002-03-21 17:27:08 +00:00
|
|
|
Paragraph::getParLanguage(BufferParams const & bparams) const
|
2000-03-17 10:14:46 +00:00
|
|
|
{
|
2003-07-27 21:59:06 +00:00
|
|
|
if (!empty())
|
2006-02-05 13:20:16 +00:00
|
|
|
return getFirstFontSettings(bparams).language();
|
2007-08-10 11:47:12 +00:00
|
|
|
// FIXME: we should check the prev par as well (Lgb)
|
2003-07-27 21:59:06 +00:00
|
|
|
return bparams.language;
|
2000-03-17 10:14:46 +00:00
|
|
|
}
|
|
|
|
|
2000-04-10 21:40:13 +00:00
|
|
|
|
2007-09-04 10:27:55 +00:00
|
|
|
bool Paragraph::isRTL(BufferParams const & bparams) const
|
2000-03-17 10:14:46 +00:00
|
|
|
{
|
2014-07-09 18:12:06 +00:00
|
|
|
return getParLanguage(bparams)->rightToLeft()
|
2009-07-16 10:08:13 +00:00
|
|
|
&& !inInset().getLayout().forceLTR();
|
2000-03-17 10:14:46 +00:00
|
|
|
}
|
2000-02-22 00:36:17 +00:00
|
|
|
|
2000-04-10 21:40:13 +00:00
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
void Paragraph::changeLanguage(BufferParams const & bparams,
|
2003-04-15 00:11:03 +00:00
|
|
|
Language const * from, Language const * to)
|
2000-02-22 00:36:17 +00:00
|
|
|
{
|
2006-11-12 17:02:43 +00:00
|
|
|
// change language including dummy font change at the end
|
|
|
|
for (pos_type i = 0; i <= size(); ++i) {
|
2007-04-29 18:17:15 +00:00
|
|
|
Font font = getFontSettings(bparams, i);
|
2000-04-10 21:40:13 +00:00
|
|
|
if (font.language() == from) {
|
|
|
|
font.setLanguage(to);
|
2001-06-25 00:06:33 +00:00
|
|
|
setFont(i, font);
|
2011-08-20 13:54:02 +00:00
|
|
|
d->requestSpellCheck(i);
|
2000-04-10 21:40:13 +00:00
|
|
|
}
|
|
|
|
}
|
2000-02-22 00:36:17 +00:00
|
|
|
}
|
|
|
|
|
2000-04-10 21:40:13 +00:00
|
|
|
|
2004-02-25 12:00:53 +00:00
|
|
|
bool Paragraph::isMultiLingual(BufferParams const & bparams) const
|
2000-02-22 00:36:17 +00:00
|
|
|
{
|
2010-02-08 17:15:00 +00:00
|
|
|
Language const * doc_language = bparams.language;
|
2018-02-24 05:04:34 +00:00
|
|
|
for (auto const & f : d->fontlist_)
|
|
|
|
if (f.font().language() != ignore_language &&
|
|
|
|
f.font().language() != latex_language &&
|
|
|
|
f.font().language() != doc_language)
|
2000-04-10 21:40:13 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
2000-02-22 00:36:17 +00:00
|
|
|
}
|
2000-05-19 16:46:01 +00:00
|
|
|
|
|
|
|
|
2018-02-24 05:04:34 +00:00
|
|
|
void Paragraph::getLanguages(std::set<Language const *> & langs) const
|
2010-02-08 17:15:00 +00:00
|
|
|
{
|
2018-02-24 05:04:34 +00:00
|
|
|
for (auto const & f : d->fontlist_) {
|
|
|
|
Language const * lang = f.font().language();
|
2010-02-08 17:15:00 +00:00
|
|
|
if (lang != ignore_language &&
|
|
|
|
lang != latex_language)
|
2018-02-24 05:04:34 +00:00
|
|
|
langs.insert(lang);
|
2010-02-08 17:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-22 14:01:33 +00:00
|
|
|
docstring Paragraph::asString(int options) const
|
2008-05-22 10:14:20 +00:00
|
|
|
{
|
2008-05-22 14:01:33 +00:00
|
|
|
return asString(0, size(), options);
|
2000-05-19 16:46:01 +00:00
|
|
|
}
|
2000-05-20 21:37:05 +00:00
|
|
|
|
|
|
|
|
2014-03-27 23:12:56 +00:00
|
|
|
docstring Paragraph::asString(pos_type beg, pos_type end, int options, const OutputParams *runparams) const
|
2000-05-20 21:37:05 +00:00
|
|
|
{
|
2007-01-19 16:23:13 +00:00
|
|
|
odocstringstream os;
|
2000-07-19 17:16:27 +00:00
|
|
|
|
2010-09-14 14:00:29 +00:00
|
|
|
if (beg == 0
|
2010-02-09 16:24:01 +00:00
|
|
|
&& options & AS_STR_LABEL
|
|
|
|
&& !d->params_.labelString().empty())
|
2008-02-20 10:21:00 +00:00
|
|
|
os << d->params_.labelString() << ' ';
|
2000-05-20 21:37:05 +00:00
|
|
|
|
2001-11-26 16:42:04 +00:00
|
|
|
for (pos_type i = beg; i < end; ++i) {
|
2010-09-29 19:31:16 +00:00
|
|
|
if ((options & AS_STR_SKIPDELETE) && isDeleted(i))
|
|
|
|
continue;
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type const c = d->text_[i];
|
2008-10-19 20:55:54 +00:00
|
|
|
if (isPrintable(c) || c == '\t'
|
2009-08-04 09:26:46 +00:00
|
|
|
|| (c == '\n' && (options & AS_STR_NEWLINES)))
|
2006-10-11 19:40:50 +00:00
|
|
|
os.put(c);
|
2009-08-04 09:26:46 +00:00
|
|
|
else if (c == META_INSET && (options & AS_STR_INSETS)) {
|
2014-03-27 23:12:56 +00:00
|
|
|
if (c == META_INSET && (options & AS_STR_PLAINTEXT)) {
|
2020-03-16 06:12:16 +00:00
|
|
|
LASSERT(runparams != nullptr, return docstring());
|
2014-03-27 23:12:56 +00:00
|
|
|
getInset(i)->plaintext(os, *runparams);
|
|
|
|
} else {
|
|
|
|
getInset(i)->toString(os);
|
|
|
|
}
|
2009-08-01 21:54:13 +00:00
|
|
|
}
|
2000-05-20 21:37:05 +00:00
|
|
|
}
|
|
|
|
|
2003-09-15 11:00:00 +00:00
|
|
|
return os.str();
|
2000-05-20 21:37:05 +00:00
|
|
|
}
|
2000-06-23 15:02:46 +00:00
|
|
|
|
|
|
|
|
2015-10-04 18:38:47 +00:00
|
|
|
void Paragraph::forOutliner(docstring & os, size_t const maxlen,
|
2017-01-08 20:57:02 +00:00
|
|
|
bool const shorten, bool const label) const
|
2010-12-20 21:55:09 +00:00
|
|
|
{
|
2015-10-04 18:38:47 +00:00
|
|
|
size_t tmplen = shorten ? maxlen + 1 : maxlen;
|
2017-01-08 20:57:02 +00:00
|
|
|
if (label && !labelString().empty())
|
|
|
|
os += labelString() + ' ';
|
2018-02-21 15:37:07 +00:00
|
|
|
if (!layout().isTocCaption())
|
|
|
|
return;
|
2015-10-04 18:38:47 +00:00
|
|
|
for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) {
|
2010-12-20 21:55:09 +00:00
|
|
|
if (isDeleted(i))
|
|
|
|
continue;
|
|
|
|
char_type const c = d->text_[i];
|
|
|
|
if (isPrintable(c))
|
|
|
|
os += c;
|
|
|
|
else if (c == META_INSET)
|
2015-10-04 18:38:47 +00:00
|
|
|
getInset(i)->forOutliner(os, tmplen, false);
|
2010-12-20 21:55:09 +00:00
|
|
|
}
|
2015-10-04 18:38:47 +00:00
|
|
|
if (shorten)
|
|
|
|
Text::shortenForOutliner(os, maxlen);
|
2010-12-20 21:55:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-13 17:01:54 +00:00
|
|
|
void Paragraph::setInsetOwner(Inset const * inset)
|
2000-06-23 15:02:46 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
d->inset_owner_ = inset;
|
2003-02-08 19:18:01 +00:00
|
|
|
}
|
|
|
|
|
2003-03-03 21:15:49 +00:00
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
int Paragraph::id() const
|
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->id_;
|
2001-06-25 00:06:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-05 13:16:55 +00:00
|
|
|
void Paragraph::setId(int id)
|
|
|
|
{
|
|
|
|
d->id_ = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-06 21:31:27 +00:00
|
|
|
Layout const & Paragraph::layout() const
|
2002-03-02 16:39:54 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
return *d->layout_;
|
2002-03-02 16:39:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-06 21:31:27 +00:00
|
|
|
void Paragraph::setLayout(Layout const & layout)
|
2001-06-25 00:06:33 +00:00
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
d->layout_ = &layout;
|
2008-02-23 16:45:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-28 14:11:24 +00:00
|
|
|
void Paragraph::setDefaultLayout(DocumentClass const & tc)
|
2010-09-14 14:00:29 +00:00
|
|
|
{
|
|
|
|
setLayout(tc.defaultLayout());
|
2008-10-28 14:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Paragraph::setPlainLayout(DocumentClass const & tc)
|
2010-09-14 14:00:29 +00:00
|
|
|
{
|
|
|
|
setLayout(tc.plainLayout());
|
2008-10-28 14:11:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-31 17:18:51 +00:00
|
|
|
void Paragraph::setPlainOrDefaultLayout(DocumentClass const & tc)
|
2008-02-23 16:45:38 +00:00
|
|
|
{
|
2008-07-10 17:41:52 +00:00
|
|
|
if (usePlainLayout())
|
2020-10-31 17:18:51 +00:00
|
|
|
setPlainLayout(tc);
|
2008-02-23 16:45:38 +00:00
|
|
|
else
|
2020-10-31 17:18:51 +00:00
|
|
|
setDefaultLayout(tc);
|
2001-06-25 00:06:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-13 17:01:54 +00:00
|
|
|
Inset const & Paragraph::inInset() const
|
2001-02-16 09:25:43 +00:00
|
|
|
{
|
2013-04-27 21:52:55 +00:00
|
|
|
LBUFERR(d->inset_owner_);
|
2008-09-13 17:01:54 +00:00
|
|
|
return *d->inset_owner_;
|
2001-02-16 09:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
ParagraphParameters & Paragraph::params()
|
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->params_;
|
2001-06-25 00:06:33 +00:00
|
|
|
}
|
|
|
|
|
2001-07-17 13:01:41 +00:00
|
|
|
|
2001-06-25 00:06:33 +00:00
|
|
|
ParagraphParameters const & Paragraph::params() const
|
2001-02-16 09:25:43 +00:00
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->params_;
|
2001-02-16 09:25:43 +00:00
|
|
|
}
|
2001-06-27 14:10:35 +00:00
|
|
|
|
2001-07-17 13:01:41 +00:00
|
|
|
|
2001-11-29 16:29:30 +00:00
|
|
|
bool Paragraph::isFreeSpacing() const
|
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
if (d->layout_->free_spacing)
|
2003-06-07 17:45:43 +00:00
|
|
|
return true;
|
2007-10-25 09:19:26 +00:00
|
|
|
return d->inset_owner_ && d->inset_owner_->isFreeSpacing();
|
2001-11-29 16:29:30 +00:00
|
|
|
}
|
2003-05-27 20:59:03 +00:00
|
|
|
|
|
|
|
|
2003-06-07 17:45:43 +00:00
|
|
|
bool Paragraph::allowEmpty() const
|
|
|
|
{
|
2008-03-06 22:06:24 +00:00
|
|
|
if (d->layout_->keepempty)
|
2003-06-07 17:45:43 +00:00
|
|
|
return true;
|
2007-10-25 09:19:26 +00:00
|
|
|
return d->inset_owner_ && d->inset_owner_->allowEmpty();
|
2003-06-07 17:45:43 +00:00
|
|
|
}
|
2003-10-24 09:45:07 +00:00
|
|
|
|
|
|
|
|
2012-07-17 21:59:04 +00:00
|
|
|
bool Paragraph::brokenBiblio() const
|
2006-12-29 23:54:48 +00:00
|
|
|
{
|
2019-04-21 09:17:44 +00:00
|
|
|
// There is a problem if there is no bibitem at position 0 in
|
|
|
|
// paragraphs that need one, if there is another bibitem in the
|
|
|
|
// paragraph or if this paragraph is not supposed to have
|
|
|
|
// a bibitem inset at all.
|
|
|
|
return ((d->layout_->labeltype == LABEL_BIBLIO
|
2012-07-17 21:59:04 +00:00
|
|
|
&& (d->insetlist_.find(BIBITEM_CODE) != 0
|
2019-04-21 09:17:44 +00:00
|
|
|
|| d->insetlist_.find(BIBITEM_CODE, 1) > 0))
|
|
|
|
|| (d->layout_->labeltype != LABEL_BIBLIO
|
|
|
|
&& d->insetlist_.find(BIBITEM_CODE) != -1));
|
2012-07-17 21:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Paragraph::fixBiblio(Buffer const & buffer)
|
|
|
|
{
|
|
|
|
// FIXME: when there was already an inset at 0, the return value is 1,
|
2020-08-04 14:52:58 +00:00
|
|
|
// which does not tell whether another inset has been removed; the
|
2012-07-17 21:59:04 +00:00
|
|
|
// cursor cannot be correctly updated.
|
2007-05-19 19:29:50 +00:00
|
|
|
|
2014-03-29 22:52:36 +00:00
|
|
|
bool const track_changes = buffer.params().track_changes;
|
2012-07-17 21:59:04 +00:00
|
|
|
int bibitem_pos = d->insetlist_.find(BIBITEM_CODE);
|
2007-05-14 09:24:17 +00:00
|
|
|
|
2019-04-21 09:17:44 +00:00
|
|
|
// The case where paragraph is not BIBLIO
|
|
|
|
if (d->layout_->labeltype != LABEL_BIBLIO) {
|
|
|
|
if (bibitem_pos == -1)
|
|
|
|
// No InsetBibitem => OK
|
|
|
|
return 0;
|
|
|
|
// There is an InsetBibitem: remove it!
|
|
|
|
d->insetlist_.release(bibitem_pos);
|
|
|
|
eraseChar(bibitem_pos, track_changes);
|
|
|
|
return (bibitem_pos == 0) ? -1 : -bibitem_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool const hasbibitem0 = bibitem_pos == 0;
|
2012-07-17 21:59:04 +00:00
|
|
|
if (hasbibitem0) {
|
|
|
|
bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1);
|
2019-04-21 09:17:44 +00:00
|
|
|
// There was an InsetBibitem at pos 0,
|
|
|
|
// and no other one => OK
|
2012-07-17 21:59:04 +00:00
|
|
|
if (bibitem_pos == -1)
|
2007-05-19 19:29:50 +00:00
|
|
|
return 0;
|
2012-07-17 21:59:04 +00:00
|
|
|
// there is a bibitem at the 0 position, but since
|
|
|
|
// there is a second one, we copy the second on the
|
|
|
|
// first. We're assuming there are at most two of
|
|
|
|
// these, which there should be.
|
|
|
|
// FIXME: why does it make sense to do that rather
|
|
|
|
// than keep the first? (JMarc)
|
2014-02-07 14:53:57 +00:00
|
|
|
Inset * inset = releaseInset(bibitem_pos);
|
2012-07-17 21:59:04 +00:00
|
|
|
d->insetlist_.begin()->inset = inset;
|
2020-08-04 14:52:58 +00:00
|
|
|
// This needs to be done to update the counter (#8499)
|
|
|
|
buffer.updateBuffer();
|
2012-07-17 21:59:04 +00:00
|
|
|
return -bibitem_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to create an inset at the beginning
|
2019-04-21 09:17:44 +00:00
|
|
|
Inset * inset = nullptr;
|
2012-07-17 21:59:04 +00:00
|
|
|
if (bibitem_pos > 0) {
|
|
|
|
// there was one somewhere in the paragraph, let's move it
|
|
|
|
inset = d->insetlist_.release(bibitem_pos);
|
|
|
|
eraseChar(bibitem_pos, track_changes);
|
|
|
|
} else
|
|
|
|
// make a fresh one
|
|
|
|
inset = new InsetBibitem(const_cast<Buffer *>(&buffer),
|
|
|
|
InsetCommandParams(BIBITEM_CODE));
|
2007-05-28 22:27:45 +00:00
|
|
|
|
2013-05-19 10:28:11 +00:00
|
|
|
Font font(inherit_font, buffer.params().language);
|
2017-07-03 17:53:14 +00:00
|
|
|
insertInset(0, inset, font, Change(track_changes ? Change::INSERTED
|
2012-07-17 21:59:04 +00:00
|
|
|
: Change::UNCHANGED));
|
2006-12-29 23:54:48 +00:00
|
|
|
|
2019-04-20 17:53:24 +00:00
|
|
|
// This is needed to get the counters right
|
|
|
|
buffer.updateBuffer();
|
2007-05-19 19:29:50 +00:00
|
|
|
return 1;
|
2006-12-29 23:54:48 +00:00
|
|
|
}
|
|
|
|
|
2007-07-09 20:52:34 +00:00
|
|
|
|
|
|
|
void Paragraph::checkAuthors(AuthorList const & authorList)
|
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
d->changes_.checkAuthors(authorList);
|
2007-07-09 20:52:34 +00:00
|
|
|
}
|
|
|
|
|
2007-10-18 15:29:51 +00:00
|
|
|
|
2009-08-04 22:44:23 +00:00
|
|
|
bool Paragraph::isChanged(pos_type pos) const
|
2007-10-18 15:29:51 +00:00
|
|
|
{
|
2009-08-04 22:44:23 +00:00
|
|
|
return lookupChange(pos).changed();
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isInserted(pos_type pos) const
|
|
|
|
{
|
2009-08-04 22:15:17 +00:00
|
|
|
return lookupChange(pos).inserted();
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isDeleted(pos_type pos) const
|
|
|
|
{
|
2009-08-04 22:15:17 +00:00
|
|
|
return lookupChange(pos).deleted();
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
InsetList const & Paragraph::insetList() const
|
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
return d->insetlist_;
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-16 02:14:08 +00:00
|
|
|
void Paragraph::setInsetBuffers(Buffer & b)
|
2008-07-23 12:49:22 +00:00
|
|
|
{
|
|
|
|
d->insetlist_.setBuffer(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-05 13:47:13 +00:00
|
|
|
void Paragraph::resetBuffer()
|
|
|
|
{
|
|
|
|
d->insetlist_.resetBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-18 15:29:51 +00:00
|
|
|
Inset * Paragraph::releaseInset(pos_type pos)
|
|
|
|
{
|
2007-10-19 08:57:22 +00:00
|
|
|
Inset * inset = d->insetlist_.release(pos);
|
2007-10-18 15:29:51 +00:00
|
|
|
/// does not honour change tracking!
|
|
|
|
eraseChar(pos, false);
|
|
|
|
return inset;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Inset * Paragraph::getInset(pos_type pos)
|
|
|
|
{
|
2008-02-11 08:31:14 +00:00
|
|
|
return (pos < pos_type(d->text_.size()) && d->text_[pos] == META_INSET)
|
2020-03-16 06:12:16 +00:00
|
|
|
? d->insetlist_.get(pos) : nullptr;
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Inset const * Paragraph::getInset(pos_type pos) const
|
|
|
|
{
|
2008-02-11 08:31:14 +00:00
|
|
|
return (pos < pos_type(d->text_.size()) && d->text_[pos] == META_INSET)
|
2020-03-16 06:12:16 +00:00
|
|
|
? d->insetlist_.get(pos) : nullptr;
|
2007-10-18 15:29:51 +00:00
|
|
|
}
|
|
|
|
|
2007-10-21 10:50:56 +00:00
|
|
|
|
2007-10-24 07:49:24 +00:00
|
|
|
void Paragraph::changeCase(BufferParams const & bparams, pos_type pos,
|
2008-01-28 10:50:24 +00:00
|
|
|
pos_type & right, TextCase action)
|
2007-10-24 07:49:24 +00:00
|
|
|
{
|
|
|
|
// process sequences of modified characters; in change
|
|
|
|
// tracking mode, this approach results in much better
|
|
|
|
// usability than changing case on a char-by-char basis
|
2014-03-24 08:15:00 +00:00
|
|
|
// We also need to track the current font, since font
|
|
|
|
// changes within sequences can occur.
|
|
|
|
vector<pair<char_type, Font> > changes;
|
2007-10-24 07:49:24 +00:00
|
|
|
|
2014-03-29 22:52:36 +00:00
|
|
|
bool const trackChanges = bparams.track_changes;
|
2007-10-24 07:49:24 +00:00
|
|
|
|
|
|
|
bool capitalize = true;
|
|
|
|
|
|
|
|
for (; pos < right; ++pos) {
|
|
|
|
char_type oldChar = d->text_[pos];
|
|
|
|
char_type newChar = oldChar;
|
|
|
|
|
|
|
|
// ignore insets and don't play with deleted text!
|
2007-10-24 11:24:53 +00:00
|
|
|
if (oldChar != META_INSET && !isDeleted(pos)) {
|
2007-10-24 07:49:24 +00:00
|
|
|
switch (action) {
|
|
|
|
case text_lowercase:
|
|
|
|
newChar = lowercase(oldChar);
|
|
|
|
break;
|
|
|
|
case text_capitalization:
|
|
|
|
if (capitalize) {
|
|
|
|
newChar = uppercase(oldChar);
|
|
|
|
capitalize = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case text_uppercase:
|
|
|
|
newChar = uppercase(oldChar);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-21 14:30:57 +00:00
|
|
|
if (isWordSeparator(pos) || isDeleted(pos)) {
|
2007-10-24 07:49:24 +00:00
|
|
|
// permit capitalization again
|
|
|
|
capitalize = true;
|
|
|
|
}
|
|
|
|
|
2009-06-22 16:38:11 +00:00
|
|
|
if (oldChar != newChar) {
|
2014-03-24 08:15:00 +00:00
|
|
|
changes.push_back(make_pair(newChar, getFontSettings(bparams, pos)));
|
2009-06-22 16:38:11 +00:00
|
|
|
if (pos != right - 1)
|
|
|
|
continue;
|
|
|
|
// step behind the changing area
|
|
|
|
pos++;
|
|
|
|
}
|
2007-10-24 07:49:24 +00:00
|
|
|
|
2009-06-22 16:38:11 +00:00
|
|
|
int erasePos = pos - changes.size();
|
2020-10-09 06:04:20 +00:00
|
|
|
for (auto const & change : changes) {
|
|
|
|
insertChar(pos, change.first, change.second, trackChanges);
|
2009-06-22 16:38:11 +00:00
|
|
|
if (!eraseChar(erasePos, trackChanges)) {
|
|
|
|
++erasePos;
|
|
|
|
++pos; // advance
|
|
|
|
++right; // expand selection
|
2007-10-24 07:49:24 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-22 16:38:11 +00:00
|
|
|
changes.clear();
|
2007-10-24 07:49:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-24 08:22:26 +00:00
|
|
|
|
2010-11-22 07:50:34 +00:00
|
|
|
int Paragraph::find(docstring const & str, bool cs, bool mw,
|
|
|
|
pos_type start_pos, bool del) const
|
2007-10-24 08:22:26 +00:00
|
|
|
{
|
2010-11-22 07:50:34 +00:00
|
|
|
pos_type pos = start_pos;
|
2007-10-24 08:22:26 +00:00
|
|
|
int const strsize = str.length();
|
|
|
|
int i = 0;
|
|
|
|
pos_type const parsize = d->text_.size();
|
2010-11-22 07:50:34 +00:00
|
|
|
for (i = 0; i < strsize && pos < parsize; ++i, ++pos) {
|
2011-03-15 13:19:55 +00:00
|
|
|
// Ignore "invisible" letters such as ligature breaks
|
|
|
|
// and hyphenation chars while searching
|
2010-11-22 07:50:34 +00:00
|
|
|
while (pos < parsize - 1 && isInset(pos)) {
|
2020-08-14 19:32:24 +00:00
|
|
|
Inset const * inset = getInset(pos);
|
|
|
|
if (!inset->isLetter())
|
|
|
|
break;
|
2011-03-15 13:36:48 +00:00
|
|
|
odocstringstream os;
|
2020-08-14 19:32:24 +00:00
|
|
|
inset->toString(os);
|
|
|
|
if (!os.str().empty())
|
2010-11-22 07:50:34 +00:00
|
|
|
break;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
if (cs && str[i] != d->text_[pos])
|
2007-10-24 08:22:26 +00:00
|
|
|
break;
|
2010-11-22 07:50:34 +00:00
|
|
|
if (!cs && uppercase(str[i]) != uppercase(d->text_[pos]))
|
2007-10-24 08:22:26 +00:00
|
|
|
break;
|
2010-11-22 07:50:34 +00:00
|
|
|
if (!del && isDeleted(pos))
|
2007-10-24 08:22:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i != strsize)
|
2010-11-22 07:50:34 +00:00
|
|
|
return 0;
|
2007-10-24 08:22:26 +00:00
|
|
|
|
|
|
|
// if necessary, check whether string matches word
|
|
|
|
if (mw) {
|
2010-11-22 07:50:34 +00:00
|
|
|
if (start_pos > 0 && !isWordSeparator(start_pos - 1))
|
|
|
|
return 0;
|
|
|
|
if (pos < parsize
|
|
|
|
&& !isWordSeparator(pos))
|
|
|
|
return 0;
|
2007-10-24 08:22:26 +00:00
|
|
|
}
|
|
|
|
|
2010-11-22 07:50:34 +00:00
|
|
|
return pos - start_pos;
|
2007-10-24 08:22:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-24 07:08:55 +00:00
|
|
|
char_type Paragraph::getChar(pos_type pos) const
|
|
|
|
{
|
|
|
|
return d->text_[pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pos_type Paragraph::size() const
|
|
|
|
{
|
|
|
|
return d->text_.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::empty() const
|
|
|
|
{
|
|
|
|
return d->text_.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isInset(pos_type pos) const
|
|
|
|
{
|
|
|
|
return d->text_[pos] == META_INSET;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Paragraph::isSeparator(pos_type pos) const
|
|
|
|
{
|
|
|
|
//FIXME: Are we sure this can be the only separator?
|
|
|
|
return d->text_[pos] == ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-26 13:07:59 +00:00
|
|
|
void Paragraph::deregisterWords()
|
|
|
|
{
|
2010-06-09 21:02:47 +00:00
|
|
|
Private::LangWordsMap::const_iterator itl = d->words_.begin();
|
|
|
|
Private::LangWordsMap::const_iterator ite = d->words_.end();
|
2010-06-09 20:56:42 +00:00
|
|
|
for (; itl != ite; ++itl) {
|
2016-12-31 14:22:07 +00:00
|
|
|
WordList & wl = theWordList(itl->first);
|
2010-06-09 20:56:42 +00:00
|
|
|
Private::Words::const_iterator it = (itl->second).begin();
|
|
|
|
Private::Words::const_iterator et = (itl->second).end();
|
|
|
|
for (; it != et; ++it)
|
2016-12-31 14:22:07 +00:00
|
|
|
wl.remove(*it);
|
2009-12-18 14:48:56 +00:00
|
|
|
}
|
2008-02-26 13:07:59 +00:00
|
|
|
d->words_.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-01 07:26:12 +00:00
|
|
|
void Paragraph::locateWord(pos_type & from, pos_type & to,
|
2019-12-27 12:01:35 +00:00
|
|
|
word_location const loc, bool const ignore_deleted) const
|
2009-05-01 07:26:12 +00:00
|
|
|
{
|
|
|
|
switch (loc) {
|
|
|
|
case WHOLE_WORD_STRICT:
|
|
|
|
if (from == 0 || from == size()
|
2019-12-27 12:01:35 +00:00
|
|
|
|| isWordSeparator(from, ignore_deleted)
|
|
|
|
|| isWordSeparator(from - 1, ignore_deleted)) {
|
2009-05-01 07:26:12 +00:00
|
|
|
to = from;
|
|
|
|
return;
|
|
|
|
}
|
2017-08-12 07:06:29 +00:00
|
|
|
// fall through
|
2009-05-01 07:26:12 +00:00
|
|
|
|
|
|
|
case WHOLE_WORD:
|
|
|
|
// If we are already at the beginning of a word, do nothing
|
2019-12-27 12:01:35 +00:00
|
|
|
if (!from || isWordSeparator(from - 1, ignore_deleted))
|
2009-05-01 07:26:12 +00:00
|
|
|
break;
|
2017-08-12 07:06:29 +00:00
|
|
|
// fall through
|
2009-05-01 07:26:12 +00:00
|
|
|
|
|
|
|
case PREVIOUS_WORD:
|
|
|
|
// always move the cursor to the beginning of previous word
|
2019-12-27 12:01:35 +00:00
|
|
|
while (from && !isWordSeparator(from - 1, ignore_deleted))
|
2009-05-01 07:26:12 +00:00
|
|
|
--from;
|
|
|
|
break;
|
|
|
|
case NEXT_WORD:
|
|
|
|
LYXERR0("Paragraph::locateWord: NEXT_WORD not implemented yet");
|
|
|
|
break;
|
|
|
|
case PARTIAL_WORD:
|
|
|
|
// no need to move the 'from' cursor
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
to = from;
|
2019-12-27 12:01:35 +00:00
|
|
|
while (to < size() && !isWordSeparator(to, ignore_deleted))
|
2009-05-01 07:26:12 +00:00
|
|
|
++to;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-01 09:56:20 +00:00
|
|
|
void Paragraph::collectWords()
|
2008-02-26 13:07:59 +00:00
|
|
|
{
|
2014-05-16 13:17:10 +00:00
|
|
|
for (pos_type pos = 0; pos < size(); ++pos) {
|
2009-06-21 14:30:57 +00:00
|
|
|
if (isWordSeparator(pos))
|
2008-02-26 13:07:59 +00:00
|
|
|
continue;
|
2009-05-01 07:26:12 +00:00
|
|
|
pos_type from = pos;
|
|
|
|
locateWord(from, pos, WHOLE_WORD);
|
2014-06-26 19:05:40 +00:00
|
|
|
// Work around MSVC warning: The statement
|
|
|
|
// if (pos < from + lyxrc.completion_minlength)
|
|
|
|
// triggers a signed vs. unsigned warning.
|
|
|
|
// I don't know why this happens, it could be a MSVC bug, or
|
|
|
|
// related to LLP64 (windows) vs. LP64 (unix) programming
|
|
|
|
// model, or the C++ standard might be ambigous in the section
|
|
|
|
// defining the "usual arithmetic conversions". However, using
|
|
|
|
// a temporary variable is safe and works on all compilers.
|
|
|
|
pos_type const endpos = from + lyxrc.completion_minlength;
|
|
|
|
if (pos < endpos)
|
2014-05-16 13:17:10 +00:00
|
|
|
continue;
|
|
|
|
FontList::const_iterator cit = d->fontlist_.fontIterator(from);
|
|
|
|
if (cit == d->fontlist_.end())
|
|
|
|
return;
|
|
|
|
Language const * lang = cit->font().language();
|
|
|
|
docstring const word = asString(from, pos, AS_STR_NONE);
|
|
|
|
d->words_[lang->lang()].insert(word);
|
2008-02-26 13:07:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Paragraph::registerWords()
|
|
|
|
{
|
2010-06-09 21:02:47 +00:00
|
|
|
Private::LangWordsMap::const_iterator itl = d->words_.begin();
|
|
|
|
Private::LangWordsMap::const_iterator ite = d->words_.end();
|
|
|
|
for (; itl != ite; ++itl) {
|
2016-12-31 14:22:07 +00:00
|
|
|
WordList & wl = theWordList(itl->first);
|
2010-06-09 21:02:47 +00:00
|
|
|
Private::Words::const_iterator it = (itl->second).begin();
|
|
|
|
Private::Words::const_iterator et = (itl->second).end();
|
|
|
|
for (; it != et; ++it)
|
2016-12-31 14:22:07 +00:00
|
|
|
wl.insert(*it);
|
2009-12-18 14:48:56 +00:00
|
|
|
}
|
2008-02-26 13:07:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-01 09:56:20 +00:00
|
|
|
void Paragraph::updateWords()
|
2008-02-26 13:07:59 +00:00
|
|
|
{
|
|
|
|
deregisterWords();
|
2009-05-01 09:56:20 +00:00
|
|
|
collectWords();
|
2008-02-26 13:07:59 +00:00
|
|
|
registerWords();
|
|
|
|
}
|
|
|
|
|
2009-05-06 23:39:17 +00:00
|
|
|
|
2010-09-29 19:31:16 +00:00
|
|
|
void Paragraph::Private::appendSkipPosition(SkipPositions & skips, pos_type const pos) const
|
|
|
|
{
|
|
|
|
SkipPositionsIterator begin = skips.begin();
|
|
|
|
SkipPositions::iterator end = skips.end();
|
|
|
|
if (pos > 0 && begin < end) {
|
|
|
|
--end;
|
|
|
|
if (end->last == pos - 1) {
|
|
|
|
end->last = pos;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skips.insert(end, FontSpan(pos, pos));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
Language * Paragraph::Private::locateSpellRange(
|
|
|
|
pos_type & from, pos_type & to,
|
2010-09-29 19:31:16 +00:00
|
|
|
SkipPositions & skips) const
|
2009-05-06 23:39:17 +00:00
|
|
|
{
|
2010-09-14 05:24:04 +00:00
|
|
|
// skip leading white space
|
|
|
|
while (from < to && owner_->isWordSeparator(from))
|
|
|
|
++from;
|
|
|
|
// don't check empty range
|
|
|
|
if (from >= to)
|
2020-03-16 06:12:16 +00:00
|
|
|
return nullptr;
|
2010-09-14 05:24:04 +00:00
|
|
|
// get current language
|
|
|
|
Language * lang = getSpellLanguage(from);
|
|
|
|
pos_type last = from;
|
|
|
|
bool samelang = true;
|
|
|
|
bool sameinset = true;
|
|
|
|
while (last < to && samelang && sameinset) {
|
|
|
|
// hop to end of word
|
|
|
|
while (last < to && !owner_->isWordSeparator(last)) {
|
2020-08-14 19:28:24 +00:00
|
|
|
Inset const * inset = owner_->getInset(last);
|
2020-08-25 05:14:29 +00:00
|
|
|
if (inset && dynamic_cast<const InsetSpecialChar *>(inset)) {
|
2020-08-14 19:28:24 +00:00
|
|
|
// check for "invisible" letters such as ligature breaks
|
|
|
|
odocstringstream os;
|
|
|
|
inset->toString(os);
|
|
|
|
if (os.str().length() != 0) {
|
|
|
|
// avoid spell check of visible special char insets
|
|
|
|
// stop the loop in front of the special char inset
|
|
|
|
sameinset = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (inset) {
|
2010-09-29 19:31:16 +00:00
|
|
|
appendSkipPosition(skips, last);
|
|
|
|
} else if (owner_->isDeleted(last)) {
|
|
|
|
appendSkipPosition(skips, last);
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
++last;
|
|
|
|
}
|
|
|
|
// hop to next word while checking for insets
|
|
|
|
while (sameinset && last < to && owner_->isWordSeparator(last)) {
|
|
|
|
if (Inset const * inset = owner_->getInset(last))
|
|
|
|
sameinset = inset->isChar() && inset->isLetter();
|
2010-09-29 19:31:16 +00:00
|
|
|
if (sameinset && owner_->isDeleted(last)) {
|
|
|
|
appendSkipPosition(skips, last);
|
|
|
|
}
|
2010-09-14 05:24:04 +00:00
|
|
|
if (sameinset)
|
|
|
|
last++;
|
|
|
|
}
|
|
|
|
if (sameinset && last < to) {
|
|
|
|
// now check for language change
|
|
|
|
samelang = lang == getSpellLanguage(last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if language change detected backstep is needed
|
|
|
|
if (!samelang)
|
|
|
|
--last;
|
|
|
|
to = last;
|
|
|
|
return lang;
|
|
|
|
}
|
2009-06-22 16:38:11 +00:00
|
|
|
|
2010-02-13 15:44:17 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
Language * Paragraph::Private::getSpellLanguage(pos_type const from) const
|
|
|
|
{
|
|
|
|
Language * lang =
|
|
|
|
const_cast<Language *>(owner_->getFontSettings(
|
|
|
|
inset_owner_->buffer().params(), from).language());
|
|
|
|
if (lang == inset_owner_->buffer().params().language
|
|
|
|
&& !lyxrc.spellchecker_alt_lang.empty()) {
|
2010-02-09 11:26:49 +00:00
|
|
|
string lang_code;
|
|
|
|
string const lang_variety =
|
|
|
|
split(lyxrc.spellchecker_alt_lang, lang_code, '-');
|
|
|
|
lang->setCode(lang_code);
|
|
|
|
lang->setVariety(lang_variety);
|
|
|
|
}
|
2010-09-14 05:24:04 +00:00
|
|
|
return lang;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Paragraph::requestSpellCheck(pos_type pos)
|
|
|
|
{
|
2011-08-20 13:48:19 +00:00
|
|
|
d->requestSpellCheck(pos);
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
2009-05-06 23:39:17 +00:00
|
|
|
|
2009-06-22 16:38:11 +00:00
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
bool Paragraph::needsSpellCheck() const
|
|
|
|
{
|
|
|
|
SpellChecker::ChangeNumber speller_change_number = 0;
|
|
|
|
if (theSpellChecker())
|
|
|
|
speller_change_number = theSpellChecker()->changeNumber();
|
|
|
|
if (speller_change_number > d->speller_state_.currentChangeNumber()) {
|
|
|
|
d->speller_state_.needsCompleteRefresh(speller_change_number);
|
|
|
|
}
|
|
|
|
return d->needsSpellCheck();
|
|
|
|
}
|
|
|
|
|
2009-06-22 16:38:11 +00:00
|
|
|
|
2010-12-07 00:13:19 +00:00
|
|
|
bool Paragraph::Private::ignoreWord(docstring const & word) const
|
|
|
|
{
|
|
|
|
// Ignore words with digits
|
|
|
|
// FIXME: make this customizable
|
|
|
|
// (note that some checkers ignore words with digits by default)
|
|
|
|
docstring::const_iterator cit = word.begin();
|
|
|
|
docstring::const_iterator const end = word.end();
|
|
|
|
for (; cit != end; ++cit) {
|
|
|
|
if (isNumber((*cit)))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to,
|
|
|
|
WordLangTuple & wl, docstring_list & suggestions,
|
|
|
|
bool do_suggestion, bool check_learned) const
|
|
|
|
{
|
|
|
|
SpellChecker::Result result = SpellChecker::WORD_OK;
|
|
|
|
SpellChecker * speller = theSpellChecker();
|
|
|
|
if (!speller)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
if (!d->layout_->spellcheck || !inInset().allowSpellCheck())
|
|
|
|
return result;
|
|
|
|
|
2019-12-27 12:01:35 +00:00
|
|
|
locateWord(from, to, WHOLE_WORD, true);
|
2010-09-19 11:49:10 +00:00
|
|
|
if (from == to || from >= size())
|
2010-09-14 05:24:04 +00:00
|
|
|
return result;
|
|
|
|
|
2010-12-20 19:18:56 +00:00
|
|
|
docstring word = asString(from, to, AS_STR_INSETS | AS_STR_SKIPDELETE);
|
2010-09-14 05:24:04 +00:00
|
|
|
Language * lang = d->getSpellLanguage(from);
|
|
|
|
|
2018-05-06 17:48:21 +00:00
|
|
|
if (getFontSettings(d->inset_owner_->buffer().params(), from).fontInfo().nospellcheck() == FONT_ON)
|
|
|
|
return result;
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
wl = WordLangTuple(word, lang);
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2012-10-21 19:14:16 +00:00
|
|
|
if (word.empty())
|
2010-09-14 05:24:04 +00:00
|
|
|
return result;
|
|
|
|
|
|
|
|
if (needsSpellCheck() || check_learned) {
|
2011-03-29 10:37:21 +00:00
|
|
|
pos_type end = to;
|
2010-12-07 00:13:19 +00:00
|
|
|
if (!d->ignoreWord(word)) {
|
2010-09-17 17:39:18 +00:00
|
|
|
bool const trailing_dot = to < size() && d->text_[to] == '.';
|
2010-09-14 05:24:04 +00:00
|
|
|
result = speller->check(wl);
|
2010-09-17 17:39:18 +00:00
|
|
|
if (SpellChecker::misspelled(result) && trailing_dot) {
|
2010-09-19 16:00:32 +00:00
|
|
|
wl = WordLangTuple(word.append(from_ascii(".")), lang);
|
2010-09-17 17:39:18 +00:00
|
|
|
result = speller->check(wl);
|
2010-09-19 11:49:10 +00:00
|
|
|
if (!SpellChecker::misspelled(result)) {
|
2010-09-19 16:00:32 +00:00
|
|
|
LYXERR(Debug::GUI, "misspelled word is correct with dot: \"" <<
|
2010-09-19 11:49:10 +00:00
|
|
|
word << "\" [" <<
|
|
|
|
from << ".." << to << "]");
|
2011-01-02 11:31:28 +00:00
|
|
|
} else {
|
2011-03-29 10:37:21 +00:00
|
|
|
// spell check with dot appended failed too
|
2011-01-02 11:31:28 +00:00
|
|
|
// restore original word/lang value
|
|
|
|
word = asString(from, to, AS_STR_INSETS | AS_STR_SKIPDELETE);
|
|
|
|
wl = WordLangTuple(word, lang);
|
2010-09-19 11:49:10 +00:00
|
|
|
}
|
2010-09-17 17:39:18 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-29 10:37:21 +00:00
|
|
|
if (!SpellChecker::misspelled(result)) {
|
|
|
|
// area up to the begin of the next word is not misspelled
|
|
|
|
while (end < size() && isWordSeparator(end))
|
|
|
|
++end;
|
|
|
|
}
|
|
|
|
d->setMisspelled(from, end, result);
|
2010-09-14 05:24:04 +00:00
|
|
|
} else {
|
|
|
|
result = d->speller_state_.getState(from);
|
|
|
|
}
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2011-03-29 10:37:21 +00:00
|
|
|
if (do_suggestion)
|
|
|
|
suggestions.clear();
|
|
|
|
|
|
|
|
if (SpellChecker::misspelled(result)) {
|
2010-09-14 05:24:04 +00:00
|
|
|
LYXERR(Debug::GUI, "misspelled word: \"" <<
|
|
|
|
word << "\" [" <<
|
|
|
|
from << ".." << to << "]");
|
2011-03-29 10:37:21 +00:00
|
|
|
if (do_suggestion)
|
|
|
|
speller->suggest(wl, suggestions);
|
|
|
|
}
|
2010-09-14 05:24:04 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-07 14:35:46 +00:00
|
|
|
void Paragraph::anonymize()
|
|
|
|
{
|
|
|
|
// This is a very crude anonymization for now
|
|
|
|
for (char_type & c : d->text_)
|
|
|
|
if (isLetterChar(c) || isNumber(c))
|
|
|
|
c = 'a';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void Paragraph::Private::markMisspelledWords(
|
|
|
|
pos_type const & first, pos_type const & last,
|
|
|
|
SpellChecker::Result result,
|
|
|
|
docstring const & word,
|
2010-09-29 19:31:16 +00:00
|
|
|
SkipPositions const & skips)
|
2010-09-14 05:24:04 +00:00
|
|
|
{
|
2010-09-14 12:48:03 +00:00
|
|
|
if (!SpellChecker::misspelled(result)) {
|
|
|
|
setMisspelled(first, last, SpellChecker::WORD_OK);
|
|
|
|
return;
|
|
|
|
}
|
2010-09-14 14:01:44 +00:00
|
|
|
int snext = first;
|
2010-09-14 12:48:03 +00:00
|
|
|
SpellChecker * speller = theSpellChecker();
|
|
|
|
// locate and enumerate the error positions
|
|
|
|
int nerrors = speller->numMisspelledWords();
|
2010-09-29 19:31:16 +00:00
|
|
|
int numskipped = 0;
|
|
|
|
SkipPositionsIterator it = skips.begin();
|
|
|
|
SkipPositionsIterator et = skips.end();
|
2010-09-14 12:48:03 +00:00
|
|
|
for (int index = 0; index < nerrors; ++index) {
|
|
|
|
int wstart;
|
|
|
|
int wlen = 0;
|
|
|
|
speller->misspelledWord(index, wstart, wlen);
|
|
|
|
/// should not happen if speller supports range checks
|
|
|
|
if (!wlen) continue;
|
|
|
|
docstring const misspelled = word.substr(wstart, wlen);
|
2010-09-29 19:31:16 +00:00
|
|
|
wstart += first + numskipped;
|
2010-09-14 12:48:03 +00:00
|
|
|
if (snext < wstart) {
|
|
|
|
/// mark the range of correct spelling
|
2010-09-29 19:31:16 +00:00
|
|
|
numskipped += countSkips(it, et, wstart);
|
2010-09-14 12:48:03 +00:00
|
|
|
setMisspelled(snext,
|
|
|
|
wstart - 1, SpellChecker::WORD_OK);
|
|
|
|
}
|
|
|
|
snext = wstart + wlen;
|
2010-09-29 19:31:16 +00:00
|
|
|
numskipped += countSkips(it, et, snext);
|
2010-09-14 12:48:03 +00:00
|
|
|
/// mark the range of misspelling
|
|
|
|
setMisspelled(wstart, snext, result);
|
|
|
|
LYXERR(Debug::GUI, "misspelled word: \"" <<
|
|
|
|
misspelled << "\" [" <<
|
|
|
|
wstart << ".." << (snext-1) << "]");
|
|
|
|
++snext;
|
2010-09-14 05:24:04 +00:00
|
|
|
}
|
|
|
|
if (snext <= last) {
|
2010-09-14 12:48:03 +00:00
|
|
|
/// mark the range of correct spelling at end
|
2010-09-14 05:24:04 +00:00
|
|
|
setMisspelled(snext, last, SpellChecker::WORD_OK);
|
|
|
|
}
|
2009-05-06 23:39:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-14 05:24:04 +00:00
|
|
|
void Paragraph::spellCheck() const
|
|
|
|
{
|
|
|
|
SpellChecker * speller = theSpellChecker();
|
2012-10-21 19:14:16 +00:00
|
|
|
if (!speller || empty() ||!needsSpellCheck())
|
2010-09-14 05:24:04 +00:00
|
|
|
return;
|
|
|
|
pos_type start;
|
|
|
|
pos_type endpos;
|
|
|
|
d->rangeOfSpellCheck(start, endpos);
|
|
|
|
if (speller->canCheckParagraph()) {
|
2010-09-14 12:48:03 +00:00
|
|
|
// loop until we leave the range
|
2010-09-14 05:24:04 +00:00
|
|
|
for (pos_type first = start; first < endpos; ) {
|
|
|
|
pos_type last = endpos;
|
2010-09-29 19:31:16 +00:00
|
|
|
Private::SkipPositions skips;
|
|
|
|
Language * lang = d->locateSpellRange(first, last, skips);
|
2010-09-14 05:24:04 +00:00
|
|
|
if (first >= endpos)
|
|
|
|
break;
|
|
|
|
// start the spell checker on the unit of meaning
|
2010-09-29 19:31:16 +00:00
|
|
|
docstring word = asString(first, last, AS_STR_INSETS + AS_STR_SKIPDELETE);
|
2010-09-14 05:24:04 +00:00
|
|
|
WordLangTuple wl = WordLangTuple(word, lang);
|
2020-10-05 10:38:09 +00:00
|
|
|
SpellChecker::Result result = !word.empty() ?
|
2010-09-14 05:24:04 +00:00
|
|
|
speller->check(wl) : SpellChecker::WORD_OK;
|
2010-09-29 19:31:16 +00:00
|
|
|
d->markMisspelledWords(first, last, result, word, skips);
|
2010-09-14 05:24:04 +00:00
|
|
|
first = ++last;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
static docstring_list suggestions;
|
|
|
|
pos_type to = endpos;
|
|
|
|
while (start < endpos) {
|
|
|
|
WordLangTuple wl;
|
|
|
|
spellCheck(start, to, wl, suggestions, false);
|
|
|
|
start = to + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d->readySpellCheck();
|
|
|
|
}
|
|
|
|
|
2010-09-14 14:00:29 +00:00
|
|
|
|
2011-01-29 12:28:02 +00:00
|
|
|
bool Paragraph::isMisspelled(pos_type pos, bool check_boundary) const
|
2009-06-22 16:38:11 +00:00
|
|
|
{
|
2011-01-29 12:28:02 +00:00
|
|
|
bool result = SpellChecker::misspelled(d->speller_state_.getState(pos));
|
2011-04-02 14:03:35 +00:00
|
|
|
if (result || pos <= 0 || pos > size())
|
2011-01-30 07:17:48 +00:00
|
|
|
return result;
|
2011-04-02 14:03:35 +00:00
|
|
|
if (check_boundary && (pos == size() || isWordSeparator(pos)))
|
2011-01-29 12:28:02 +00:00
|
|
|
result = SpellChecker::misspelled(d->speller_state_.getState(pos - 1));
|
|
|
|
return result;
|
2009-06-22 16:38:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-10 20:03:35 +00:00
|
|
|
string Paragraph::magicLabel() const
|
|
|
|
{
|
|
|
|
stringstream ss;
|
|
|
|
ss << "magicparlabel-" << id();
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-21 00:16:43 +00:00
|
|
|
} // namespace lyx
|