X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FParagraph.cpp;h=545ab0baee24f6796670443b2e3108989c166cf7;hb=0dcf78a4ad21b62de6082fdf3feb7c564ebd1dc7;hp=73157e6b7d60f5605b698b419e157d93e4509564;hpb=75bfed55079cab6b73fbea6ce4ae3f10d1af3b91;p=lyx.git diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 73157e6b7d..545ab0baee 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -87,7 +87,7 @@ namespace { /// Inset identifier (above 0x10ffff, for ucs-4) char_type const META_INSET = 0x200001; -} +} // namespace ///////////////////////////////////////////////////////////////////// @@ -1090,13 +1090,15 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, odocstream::pos_type const len = os.os().tellp(); if (inset->forceLTR() - && !runparams.use_polyglossia && running_font.isRightToLeft() // ERT is an exception, it should be output with no // decorations at all && inset->lyxCode() != ERT_CODE) { - if (running_font.language()->lang() == "farsi") - os << "\\beginL" << termcmd; + if (runparams.use_polyglossia) { + os << "\\LRE{"; + } else if (running_font.language()->lang() == "farsi" + || running_font.language()->lang() == "arabic_arabi") + os << "\\textLR{" << termcmd; else os << "\\L{"; close = true; @@ -1152,12 +1154,8 @@ void Paragraph::Private::latexInset(BufferParams const & bparams, throw(e); } - if (close) { - if (running_font.language()->lang() == "farsi") - os << "\\endL" << termcmd; - else - os << '}'; - } + if (close) + os << '}'; if (os.texrow().rows() > previous_row_count) { os.texrow().start(owner_->id(), i + 1); @@ -1181,10 +1179,7 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, pos_type end_pos, unsigned int & column) { - // With polyglossia, brackets and stuff need not be reversed - // in RTL scripts (see bug #8251) - char_type const c = (runparams.use_polyglossia) ? - owner_->getUChar(bparams, i) : text_[i]; + char_type const c = owner_->getUChar(bparams, runparams, i); if (style.pass_thru || runparams.pass_thru || contains(style.pass_thru_chars, c) @@ -1247,8 +1242,8 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, } break; case '\"': - os << "\\char34" << termcmd; - column += 9; + os << "\\textquotedbl" << termcmd; + column += 14; break; case '$': case '&': @@ -1289,7 +1284,10 @@ void Paragraph::Private::latexSpecialChar(otexstream & os, case 0x2013: case 0x2014: - if (bparams.use_dash_ligatures && !bparams.useNonTeXFonts) { + // XeTeX's dash behaviour is determined via a global setting + if (bparams.use_dash_ligatures + && owner_->getFontSettings(bparams, i).fontInfo().family() != TYPEWRITER_FAMILY + && (!bparams.useNonTeXFonts || runparams.flavor != OutputParams::XETEX)) { if (c == 0x2013) { // en-dash os << "--"; @@ -1417,6 +1415,14 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, os << "\\textvertline" << termcmd; column += 14; return true; + case 0x2013: + os << "\\textendash" << termcmd; + column += 12; + return true; + case 0x2014: + os << "\\textemdash" << termcmd; + column += 12; + return true; default: return false; } @@ -1426,43 +1432,18 @@ bool Paragraph::Private::latexSpecialT3(char_type const c, otexstream & os, void Paragraph::Private::validate(LaTeXFeatures & features) const { if (layout_->inpreamble && inset_owner_) { - bool const is_command = layout_->latextype == LATEX_COMMAND; - Buffer const & buf = inset_owner_->buffer(); - BufferParams const & bp = features.runparams().is_child - ? buf.masterParams() : buf.params(); - Font f; - // Using a string stream here circumvents the encoding + // FIXME: Using a string stream here circumvents the encoding // switching machinery of odocstream. Therefore the // output is wrong if this paragraph contains content // that needs to switch encoding. + Buffer const & buf = inset_owner_->buffer(); otexstringstream os; os << layout_->preamble(); - if (is_command) { - os << '\\' << from_ascii(layout_->latexname()); - // we have to provide all the optional arguments here, even though - // the last one is the only one we care about. - // Separate handling of optional argument inset. - if (!layout_->latexargs().empty()) { - OutputParams rp = features.runparams(); - rp.local_font = &owner_->getFirstFontSettings(bp); - latexArgInsets(*owner_, os, rp, layout_->latexargs()); - } - os << from_ascii(layout_->latexparam()); - } size_t const length = os.length(); - // this will output "{" at the beginning, but not at the end - owner_->latex(bp, f, os, features.runparams(), 0, -1, true); - if (os.length() > length) { - if (is_command) { - os << '}'; - if (!layout_->postcommandargs().empty()) { - OutputParams rp = features.runparams(); - rp.local_font = &owner_->getFirstFontSettings(bp); - latexArgInsets(*owner_, os, rp, layout_->postcommandargs(), "post:"); - } - } + TeXOnePar(buf, buf.text(), buf.getParFromID(owner_->id()).pit(), os, + features.runparams(), string(), 0, -1, true); + if (os.length() > length) features.addPreambleSnippet(os.release(), true); - } } if (features.runparams().flavor == OutputParams::HTML @@ -1490,6 +1471,16 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const for (; icit != iend; ++icit) { if (icit->inset) { features.inDeletedInset(owner_->isDeleted(icit->pos)); + 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"); + } icit->inset->validate(features); features.inDeletedInset(false); if (layout_->needprotect && @@ -1499,8 +1490,24 @@ void Paragraph::Private::validate(LaTeXFeatures & features) const } // then the contents + BufferParams const bp = features.runparams().is_child + ? features.buffer().masterParams() : features.buffer().params(); for (pos_type i = 0; i < int(text_.size()) ; ++i) { - BufferEncodings::validate(text_[i], features); + char_type c = text_[i]; + if (c == 0x0022) { + if (features.runparams().isFullUnicode() && bp.useNonTeXFonts) + features.require("textquotedblp"); + else if (bp.main_font_encoding() != "T1" + || ((&owner_->getFontSettings(bp, i))->language()->internalFontEncoding())) + features.require("textquotedbl"); + } + if (!bp.use_dash_ligatures + && (c == 0x2013 || c == 0x2014) + && bp.useNonTeXFonts + && features.runparams().flavor == OutputParams::XETEX) + // XeTeX's dash behaviour is determined via a global setting + features.require("xetexdashbreakstate"); + BufferEncodings::validate(c, features); } } @@ -1569,7 +1576,7 @@ void flushString(ostream & os, docstring & s) s.erase(); } -} +} // namespace void Paragraph::write(ostream & os, BufferParams const & bparams, @@ -1891,32 +1898,60 @@ Font const Paragraph::getLayoutFont } -char_type Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const +char_type Paragraph::getUChar(BufferParams const & bparams, + OutputParams const & rp, + pos_type pos) const { char_type c = d->text_[pos]; + + // Return unchanged character in LTR languages. if (!getFontSettings(bparams, pos).isRightToLeft()) return c; - // FIXME: The arabic special casing is due to the difference of arabic - // round brackets input introduced in r18599. Check if this should be - // unified with Hebrew or at least if all bracket types should be - // handled the same (file format change in either case). + // FIXME This is a complete mess due to all the language-specific + // special cases. We need to unify this eventually, but this + // requires a file format change and some thought. + // We also need to unify the input of parentheses in different RTL + // languages. Currently, some have their own methods (Arabic: + // 18599/lyxsvn, Hebrew: e5f42f67d/lyxgit), some don't (Urdu, Syriac). + // Also note that the representation in the LyX file is probably wrong + // (see FIXME in TextMetrics::breakRow). + // Most likely, we should simply rely on Qt's unicode handling here. string const & lang = getFontSettings(bparams, pos).language()->lang(); - bool const arabic = lang == "arabic_arabtex" || lang == "arabic_arabi" - || lang == "farsi"; + + // With polyglossia, brackets and stuff need not be reversed in RTL scripts + // FIXME: The special casing for Hebrew parens is due to the special + // handling on input (for Hebrew in e5f42f67d/lyxgit); see #8251. char_type uc = c; + if (rp.use_polyglossia) { + switch (c) { + case '(': + if (lang == "hebrew") + uc = ')'; + break; + case ')': + if (lang == "hebrew") + uc = '('; + break; + } + return uc; + } + + // In the following languages, brackets don't need to be reversed. + // Furthermore, in arabic_arabi, they are transformed to Arabic + // Ornate Parentheses (dunno if this is really wanted) + bool const reversebrackets = lang != "arabic_arabtex" + && lang != "arabic_arabi" + && lang != "farsi"; + switch (c) { - case '(': - uc = arabic ? c : ')'; - break; - case ')': - uc = arabic ? c : '('; - break; case '[': - uc = ']'; + if (reversebrackets) + uc = ']'; break; case ']': - uc = '['; + if (reversebrackets) + uc = '['; break; case '{': uc = '}'; @@ -2200,7 +2235,7 @@ bool corrected_env(otexstream & os, string const & suffix, string const & env, return true; } -} // namespace anon +} // namespace int Paragraph::Private::startTeXParParams(BufferParams const & bparams, @@ -2252,13 +2287,13 @@ int Paragraph::Private::startTeXParParams(BufferParams const & bparams, case LYX_ALIGN_DECIMAL: break; case LYX_ALIGN_LEFT: { - if (owner_->getParLanguage(bparams)->babel() != "hebrew") + if (!owner_->getParLanguage(bparams)->rightToLeft()) corrected_env(os, begin_tag, "flushleft", code, lastpar, column); else corrected_env(os, begin_tag, "flushright", code, lastpar, column); break; } case LYX_ALIGN_RIGHT: { - if (owner_->getParLanguage(bparams)->babel() != "hebrew") + if (!owner_->getParLanguage(bparams)->rightToLeft()) corrected_env(os, begin_tag, "flushright", code, lastpar, column); else corrected_env(os, begin_tag, "flushleft", code, lastpar, column); @@ -2310,13 +2345,13 @@ bool Paragraph::Private::endTeXParParams(BufferParams const & bparams, case LYX_ALIGN_DECIMAL: break; case LYX_ALIGN_LEFT: { - if (owner_->getParLanguage(bparams)->babel() != "hebrew") + if (!owner_->getParLanguage(bparams)->rightToLeft()) output = corrected_env(os, end_tag, "flushleft", code, lastpar, col); else output = corrected_env(os, end_tag, "flushright", code, lastpar, col); break; } case LYX_ALIGN_RIGHT: { - if (owner_->getParLanguage(bparams)->babel() != "hebrew") + if (!owner_->getParLanguage(bparams)->rightToLeft()) output = corrected_env(os, end_tag, "flushright", code, lastpar, col); else output = corrected_env(os, end_tag, "flushleft", code, lastpar, col); @@ -2389,7 +2424,9 @@ void Paragraph::latex(BufferParams const & bparams, // if the paragraph is empty, the loop will not be entered at all if (empty()) { - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } @@ -2427,7 +2464,9 @@ void Paragraph::latex(BufferParams const & bparams, os << "}] "; column +=3; } - if (style.isCommand()) { + // For InTitle commands, we have already opened a group + // in output_latex::TeXOnePar. + if (style.isCommand() && !style.intitle) { os << '{'; ++column; } @@ -2445,6 +2484,8 @@ void Paragraph::latex(BufferParams const & bparams, runparams.wasDisplayMath = runparams.inDisplayMath; runparams.inDisplayMath = false; bool deleted_display_math = false; + Change const & change = runparams.inDeletedInset + ? runparams.changeOfDeletedInset : lookupChange(i); // Check whether a display math inset follows if (d->text_[i] == META_INSET @@ -2459,11 +2500,28 @@ void Paragraph::latex(BufferParams const & bparams, // cannot set it here because it is a counter. deleted_display_math = isDeleted(i); } + 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, + basefont, needPar); + open_font = false; + } + basefont = getLayoutFont(bparams, outerfont); + running_font = basefont; + column += Changes::latexMarkChange(os, bparams, + Change(Change::INSERTED), change, rp); + } } - Change const & change = runparams.inDeletedInset - ? runparams.changeOfDeletedInset : lookupChange(i); - if (bparams.output_changes && runningChange != change) { if (open_font) { bool needPar = false; @@ -2514,6 +2572,7 @@ void Paragraph::latex(BufferParams const & bparams, bool const using_begin_end = runparams.use_polyglossia || !lang_end_command.empty(); if (!running_lang.empty() && + (!using_begin_end || running_lang == openLanguageName()) && current_font.language()->encoding()->package() == Encoding::CJK) { string end_tag = subst(lang_end_command, "$$lang", @@ -2540,7 +2599,7 @@ void Paragraph::latex(BufferParams const & bparams, char_type const c = d->text_[i]; // A display math inset inside an ulem command will be output - // as a box of width \columnwidth, so we have to either disable + // as a box of width \linewidth, so we have to either disable // 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. @@ -2928,7 +2987,7 @@ void doFontSwitch(vector & tagsToOpen, flag = false; } } -} +} // namespace docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, @@ -3257,7 +3316,8 @@ docstring Paragraph::simpleLyXHTMLOnePar(Buffer const & buf, retval += inset->xhtml(xs, np); } } else { - char_type c = getUChar(buf.masterBuffer()->params(), i); + char_type c = getUChar(buf.masterBuffer()->params(), + runparams, i); xs << c; } font_old = font.fontInfo(); @@ -3474,6 +3534,8 @@ void Paragraph::forOutliner(docstring & os, size_t const maxlen, size_t tmplen = shorten ? maxlen + 1 : maxlen; if (label && !labelString().empty()) os += labelString() + ' '; + if (!layout().isTocCaption()) + return; for (pos_type i = 0; i < size() && os.length() < tmplen; ++i) { if (isDeleted(i)) continue; @@ -3862,13 +3924,13 @@ void Paragraph::locateWord(pos_type & from, pos_type & to, to = from; return; } - // no break here, we go to the next + // fall through case WHOLE_WORD: // If we are already at the beginning of a word, do nothing if (!from || isWordSeparator(from - 1)) break; - // no break here, we go to the next + // fall through case PREVIOUS_WORD: // always move the cursor to the beginning of previous word @@ -4119,6 +4181,15 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to, } +void Paragraph::anonymize() +{ + // This is a very crude anonymization for now + for (char_type & c : d->text_) + if (isLetterChar(c) || isNumber(c)) + c = 'a'; +} + + void Paragraph::Private::markMisspelledWords( pos_type const & first, pos_type const & last, SpellChecker::Result result,