#include "output_xhtml.h"
#include "output_docbook.h"
#include "ParagraphParameters.h"
+#include "Session.h"
#include "SpellChecker.h"
#include "texstream.h"
#include "TexRow.h"
using namespace std;
using namespace lyx::support;
-// 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)
+// OSX clang and msvc < 2015 do not support C++11 thread_local
+#if defined(__APPLE__)
#define THREAD_LOCAL_STATIC static __thread
#elif defined(_MSC_VER) && (_MSC_VER < 1900)
#define THREAD_LOCAL_STATIC static __declspec(thread)
/// \return the number of characters written.
int latexSurrogatePair(BufferParams const &, otexstream & os,
char_type c, char_type next,
- OutputParams const &);
+ OutputParams const &) const;
/// Output a space in appropriate formatting (or a surrogate pair
/// if the next character is a combining character).
pos_type i,
unsigned int & column,
Font const & font,
- Layout const & style);
+ Layout const & style) const;
/// This could go to ParagraphParameters if we want to.
int startTeXParParams(BufferParams const &, otexstream &,
unsigned int & column,
bool const fontswitch_inset,
bool const closeLanguage,
- bool const lang_switched_at_inset);
+ bool const lang_switched_at_inset) const;
///
void latexSpecialChar(
Layout const & style,
pos_type & i,
pos_type end_pos,
- unsigned int & column);
+ unsigned int & column) const;
///
bool latexSpecialT1(
return speller_change_number > speller_state_.currentChangeNumber();
}
- bool ignoreWord(docstring const & word) const ;
+ bool ignoreWord(docstring const & word) const;
void setMisspelled(pos_type from, pos_type to, SpellChecker::Result state)
{
// Update list of misspelled positions
speller_state_.increasePosAfterPos(pos);
+
+ // Update bookmarks
+ if (inset_owner_ && inset_owner_->isBufferValid())
+ theSession().bookmarks().adjustPosAfterPos(inset_owner_->buffer().fileName(),
+ id_, pos, 1);
}
d->speller_state_.decreasePosAfterPos(pos);
d->speller_state_.refreshLast(size());
+ // Update bookmarks
+ if (d->inset_owner_ && d->inset_owner_->isBufferValid())
+ theSession().bookmarks().adjustPosAfterPos(d->inset_owner_->buffer().fileName(),
+ d->id_, pos, -1);
+
return true;
}
// Handle combining characters
int Paragraph::Private::latexSurrogatePair(BufferParams const & bparams,
otexstream & os, char_type c, char_type next,
- OutputParams const & runparams)
+ OutputParams const & runparams) const
{
// Writing next here may circumvent a possible font change between
// c and next. Since next is only output if it forms a surrogate pair
pos_type i,
unsigned int & column,
Font const & font,
- Layout const & style)
+ Layout const & style) const
{
if (style.pass_thru || runparams.pass_thru)
return false;
unsigned int & column,
bool const fontswitch_inset,
bool const closeLanguage,
- bool const lang_switched_at_inset)
+ bool const lang_switched_at_inset) const
{
Inset * inset = owner_->getInset(i);
LBUFERR(inset);
bool const cprotect = textinset
? textinset->hasCProtectContent(runparams.moving_arg)
&& !textinset->text().isMainText()
+ && inset->lyxCode() != BRANCH_CODE
: false;
unsigned int count2 = basefont.latexWriteStartChanges(os, bparams,
rp, running_font,
Layout const & style,
pos_type & i,
pos_type end_pos,
- unsigned int & column)
+ unsigned int & column) const
{
char_type const c = owner_->getUChar(bparams, runparams, i);
// non-standard font encoding. If we are using such a language,
// we do not output special T1 chars.
if (!runparams.inIPA && !running_font.language()->internalFontEncoding()
- && !runparams.isFullUnicode() && bparams.main_font_encoding() == "T1"
+ && !runparams.isFullUnicode() && runparams.main_fontenc == "T1"
&& latexSpecialT1(c, os, i, column))
return;
// NOTE: "fontspec" (non-TeX fonts) sets the font encoding to "TU" (untill 2017 "EU1" or "EU2")
if (c == 0x0022) {
if (features.runparams().isFullUnicode() && bp.useNonTeXFonts)
features.require("textquotedblp");
- else if (bp.main_font_encoding() != "T1"
+ else if (features.runparams().main_fontenc != "T1"
|| ((&owner_->getFontSettings(bp, i))->language()->internalFontEncoding()))
features.require("textquotedbl");
- } else if (ci.textfeature() && contains(ci.textpreamble(), '=')) {
+ } else if (ci.textFeature() && contains(ci.textPreamble(), '=')) {
// features that depend on the font or input encoding
- string feats = ci.textpreamble();
+ string feats = ci.textPreamble();
string fontenc = (&owner_->getFontSettings(bp, i))->language()->fontenc(bp);
if (fontenc.empty())
fontenc = features.runparams().main_fontenc;
return inInset().isPassThru() || d->layout_->pass_thru;
}
+
+bool Paragraph::parbreakIsNewline() const
+{
+ return inInset().getLayout().parbreakIsNewline() || d->layout_->parbreak_is_newline;
+}
+
+
+bool Paragraph::isPartOfTextSequence() const
+{
+ for (pos_type i = 0; i < size(); ++i) {
+ if (!isInset(i) || getInset(i)->isPartOfTextSequence())
+ return true;
+ }
+ return false;
+}
+
namespace {
// paragraphs inside floats need different alignment tags to avoid
(layout_->toggle_indent != ITOGGLE_NEVER) :
(layout_->toggle_indent == ITOGGLE_ALWAYS);
- if (canindent && params_.noindent() && !layout_->pass_thru) {
- os << "\\noindent ";
- column += 10;
- }
-
LyXAlignment const curAlign = params_.align();
+ // Do not output \\noindent for paragraphs
+ // 1. that cannot have indentation or are indented always,
+ // 2. that are not part of the immediate text sequence (e.g., contain only floats),
+ // 3. that are PassThru,
+ // 4. or that are centered.
+ if (canindent && params_.noindent()
+ && owner_->isPartOfTextSequence()
+ && !layout_->pass_thru
+ && curAlign != LYX_ALIGN_CENTER) {
+ if (!owner_->empty()
+ && owner_->getInset(0)
+ && owner_->getInset(0)->lyxCode() == VSPACE_CODE)
+ // If the paragraph starts with a vspace, the \\noindent
+ // needs to come after that (as it leaves vmode).
+ // If the paragraph consists only of the vspace,
+ // \\noindent is not needed at all.
+ runparams.need_noindent = owner_->size() > 1;
+ else {
+ os << "\\noindent" << termcmd;
+ column += 10;
+ }
+ }
+
if (curAlign == layout_->align)
return column;
OutputParams const & runparams,
int start_pos, int end_pos, bool force) const
{
- LYXERR(Debug::LATEX, "Paragraph::latex... " << this);
+ LYXERR(Debug::OUTFILE, "Paragraph::latex... " << this);
// FIXME This check should not be needed. Perhaps issue an
// error if it triggers.
pos_type body_pos = beginOfBody();
unsigned int column = 0;
- // 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;
+ // If we are inside an non inheritFont() inset,
+ // the outerfont is the buffer's main font
+ Font const real_outerfont =
+ inInset().inheritFont() ? outerfont : Font(bparams.getFont());
if (body_pos > 0) {
// the optional argument is kept in curly brackets in
if (runparams.for_searchAdv == OutputParams::NoSearch)
output_changes = bparams.output_changes;
else
- output_changes = (runparams.for_searchAdv == OutputParams::SearchWithDeleted);
+ output_changes = ((runparams.for_searchAdv & OutputParams::SearchWithDeleted) != 0);
if (c == META_INSET
&& i >= start_pos && (end_pos == -1 || i < end_pos)) {
if (isDeleted(i))
&& getInset(i)
&& getInset(i)->allowMultiPar()
&& getInset(i)->lyxCode() != ERT_CODE
- && getInset(i)->producesOutput();
+ && (getInset(i)->producesOutput()
+ // FIXME Something more general?
+ // Comments do not "produce output" but are still
+ // part of the TeX source and require font switches
+ // to be closed (otherwise LaTeX fails).
+ || getInset(i)->layoutName() == "Note:Comment");
bool closeLanguage = false;
bool lang_switched_at_inset = false;
column += Changes::latexMarkChange(os, bparams,
Change(Change::UNCHANGED), Change(Change::DELETED), rp);
}
- open_font = false;
// 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;
+ open_font &= !langClosed;
}
// if necessary, close language environment before opening CJK
string end_tag = subst(lang_end_command, "$$lang", running_lang);
os << from_ascii(end_tag);
column += end_tag.length();
- popLanguageName();
+ if (!languageStackEmpty())
+ popLanguageName();
}
// Switch file encoding if necessary (and allowed)
bool const cprotect = textinset
? textinset->hasCProtectContent(runparams.moving_arg)
&& !textinset->text().isMainText()
+ && inInset().lyxCode() != BRANCH_CODE
: false;
column += current_font.latexWriteStartChanges(ots, bparams,
runparams, basefont, last_font, false,
}
} else {
running_font = current_font;
- open_font = !langClosed;
+ open_font &= !langClosed;
}
}
os << setEncoding(prev_encoding->iconvName());
}
- LYXERR(Debug::LATEX, "Paragraph::latex... done " << this);
+ LYXERR(Debug::OUTFILE, "Paragraph::latex... done " << this);
}
}
// now check whether we have insets that need cprotection
- pos_type size = pos_type(d->text_.size());
- for (pos_type i = 0; i < size; ++i) {
- if (!isInset(i))
+ for (auto const & icit : d->insetlist_) {
+ Inset const * ins = icit.inset;
+ if (!ins)
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
- return true;
- default:
- break;
- }
}
return false;
void Paragraph::requestSpellCheck(pos_type pos)
{
d->requestSpellCheck(pos);
+ if (pos == -1) {
+ // Also request spellcheck within (text) insets
+ for (auto const & insets : insetList()) {
+ if (!insets.inset->asInsetText())
+ continue;
+ ParagraphList & inset_pars =
+ insets.inset->asInsetText()->paragraphs();
+ ParagraphList::iterator pit = inset_pars.begin();
+ ParagraphList::iterator pend = inset_pars.end();
+ for (; pit != pend; ++pit)
+ pit->requestSpellCheck();
+ }
+ }
}
/// should not happen if speller supports range checks
if (!wlen)
continue;
+ WordLangTuple const candidate(word.substr(wstart, wlen), lang);
wstart += first + numskipped;
if (snext < wstart) {
/// mark the range of correct spelling
}
snext = wstart + wlen;
// Check whether the candidate is in the document's local dict
- WordLangTuple const candidate(word.substr(wstart, wlen), lang);
SpellChecker::Result actresult = result;
if (inset_owner_->buffer().params().spellignored(candidate))
actresult = SpellChecker::DOCUMENT_LEARNED_WORD;