Add \nospellcheck font property

This revives a ten year old idea (and patch) by Dov.

You can now mark in the character dialog text and exclude it from spell
checking.

Fixes: #1042

File format change

Remaining issue: The instant spell checking marks are not immediately
removed, but only after some editing.
This commit is contained in:
Juergen Spitzmueller 2018-05-06 19:48:21 +02:00
parent 40a61357af
commit 57dc817581
14 changed files with 257 additions and 149 deletions

View File

@ -7,6 +7,10 @@ changes happened in particular if possible. A good example would be
-----------------------
2018-05-06 Jürgen Spitzmüller <spitz@lyx.org>
* format incremented to 551: add font info param \nospellcheck that prevents
text from being spellchecked.
2018-04-22 Jürgen Spitzmüller <spitz@lyx.org>
* format incremented to 550: rename \fontencoding global to \fontencoding auto.
Semantic change: this is now automatically set depending on the document fonts.

View File

@ -202,6 +202,17 @@ def revert_fontenc(document):
document.header[i] = document.header[i].replace("auto", "global")
def revert_nospellcheck(document):
" Remove nospellcheck font info param "
i = 0
while True:
i = find_token(document.body, '\\nospellcheck', i)
if i == -1:
return
del document.body[i]
##
# Conversion hub
#
@ -213,10 +224,12 @@ convert = [
[547, []],
[548, []],
[549, []],
[550, [convert_fontenc]]
[550, [convert_fontenc]],
[551, []]
]
revert = [
[549, [revert_nospellcheck]],
[549, [revert_fontenc]],
[548, []],# dummy format change
[547, [revert_lscape]],

View File

@ -225,6 +225,8 @@ void Font::lyxWriteChanges(Font const & orgfont,
os << "\\emph " << LyXMiscNames[bits_.emph()] << "\n";
if (orgfont.fontInfo().number() != bits_.number())
os << "\\numeric " << LyXMiscNames[bits_.number()] << "\n";
if (orgfont.fontInfo().nospellcheck() != bits_.nospellcheck())
os << "\\nospellcheck " << LyXMiscNames[bits_.nospellcheck()] << "\n";
if (orgfont.fontInfo().underbar() != bits_.underbar()) {
// This is only for backwards compatibility
switch (bits_.underbar()) {
@ -619,6 +621,7 @@ string Font::toString(bool const toggle) const
<< "uwave " << bits_.uwave() << '\n'
<< "noun " << bits_.noun() << '\n'
<< "number " << bits_.number() << '\n'
<< "nospellcheck " << bits_.nospellcheck() << '\n'
<< "color " << bits_.color() << '\n'
<< "language " << lang << '\n'
<< "toggleall " << convert<string>(toggle);
@ -660,7 +663,8 @@ bool Font::fromString(string const & data, bool & toggle)
} else if (token == "emph" || token == "underbar"
|| token == "noun" || token == "number"
|| token == "uuline" || token == "uwave"
|| token == "strikeout" || token == "xout") {
|| token == "strikeout" || token == "xout"
|| token == "nospellcheck") {
int const next = lex.getInteger();
FontState const misc = FontState(next);
@ -681,6 +685,8 @@ bool Font::fromString(string const & data, bool & toggle)
bits_.setNoun(misc);
else if (token == "number")
bits_.setNumber(misc);
else if (token == "nospellcheck")
bits_.setNoSpellcheck(misc);
} else if (token == "color") {
int const next = lex.getInteger();
@ -809,7 +815,8 @@ ostream & operator<<(ostream & os, FontInfo const & f)
<< " uuline " << f.uuline()
<< " uwave " << f.uwave()
<< " noun " << f.noun()
<< " number " << f.number();
<< " number " << f.number()
<< " nospellcheck " << f.nospellcheck();
}

View File

@ -71,6 +71,7 @@ FontInfo const sane_font(
FONT_OFF,
FONT_OFF,
FONT_OFF,
FONT_OFF,
FONT_OFF);
FontInfo const inherit_font(
@ -87,7 +88,8 @@ FontInfo const inherit_font(
FONT_INHERIT,
FONT_INHERIT,
FONT_INHERIT,
FONT_OFF);
FONT_OFF,
FONT_INHERIT);
FontInfo const ignore_font(
IGNORE_FAMILY,
@ -103,6 +105,7 @@ FontInfo const ignore_font(
FONT_IGNORE,
FONT_IGNORE,
FONT_IGNORE,
FONT_IGNORE,
FONT_IGNORE);
@ -226,6 +229,8 @@ void FontInfo::reduce(FontInfo const & tmplt)
color_ = Color_inherit;
if (background_ == tmplt.background_)
background_ = Color_inherit;
if (nospellcheck_ == tmplt.nospellcheck_)
noun_ = FONT_INHERIT;
}
@ -276,6 +281,9 @@ FontInfo & FontInfo::realize(FontInfo const & tmplt)
if (background_ == Color_inherit)
background_ = tmplt.background_;
if (nospellcheck_ == FONT_INHERIT)
nospellcheck_ = tmplt.nospellcheck_;
return *this;
}
@ -375,6 +383,7 @@ void FontInfo::update(FontInfo const & newfont, bool toggleall)
setUwave(setMisc(newfont.uwave_, uwave_));
setNoun(setMisc(newfont.noun_, noun_));
setNumber(setMisc(newfont.number_, number_));
setNoSpellcheck(setMisc(newfont.nospellcheck_, nospellcheck_));
if (newfont.color_ == color_ && toggleall)
setColor(Color_inherit); // toggle 'back'
@ -396,7 +405,7 @@ bool FontInfo::resolved() const
&& uuline_ != FONT_INHERIT && uwave_ != FONT_INHERIT
&& strikeout_ != FONT_INHERIT && xout_ != FONT_INHERIT
&& noun_ != FONT_INHERIT && color_ != Color_inherit
&& background_ != Color_inherit);
&& background_ != Color_inherit && nospellcheck_ != FONT_INHERIT);
}
@ -689,6 +698,10 @@ FontInfo lyxRead(Lexer & lex, FontInfo const & fi)
f.setUwave(FONT_ON);
} else if (ttok == "noun") {
f.setNoun(FONT_ON);
} else if (ttok == "nospellcheck") {
f.setNoSpellcheck(FONT_ON);
} else if (ttok == "no_nospellcheck") {
f.setNoSpellcheck(FONT_OFF);
} else {
lex.printError("Illegal misc type");
}
@ -751,6 +764,10 @@ void lyxWrite(ostream & os, FontInfo const & f, string const & start, int level)
oss << indent << "\tMisc Noun\n";
else if (f.noun() == FONT_OFF)
oss << indent << "\tMisc No_Noun\n";
if (f.nospellcheck() == FONT_ON)
oss << indent << "\tMisc NoSpellcheck\n";
else if (f.nospellcheck() == FONT_OFF)
oss << indent << "\tMisc No_NoSpellcheck\n";
if (f.color() != Color_inherit && f.color() != Color_none)
oss << indent << "\tColor " << lcolor.getLyXName(f.color())
<< '\n';

View File

@ -48,11 +48,12 @@ public:
FontState uuline,
FontState uwave,
FontState noun,
FontState number)
FontState number,
FontState nospellcheck)
: family_(family), series_(series), shape_(shape), size_(size),
style_(LM_ST_TEXT), color_(color), background_(background), emph_(emph),
underbar_(underbar), strikeout_(strikeout), xout_(xout), uuline_(uuline),
uwave_(uwave), noun_(noun), number_(number)
uwave_(uwave), noun_(noun), number_(number), nospellcheck_(nospellcheck)
{}
/// Decreases font size by one
@ -92,6 +93,8 @@ public:
void setColor(ColorCode c) { color_ = c; }
ColorCode background() const { return background_; }
void setBackground(ColorCode b) { background_ = b; }
FontState nospellcheck() const { return nospellcheck_; }
void setNoSpellcheck(FontState n) { nospellcheck_ = n; }
//@}
///
@ -192,6 +195,8 @@ private:
FontState noun_;
///
FontState number_;
///
FontState nospellcheck_;
};
@ -210,7 +215,8 @@ inline bool operator==(FontInfo const & lhs, FontInfo const & rhs)
&& lhs.uuline_ == rhs.uuline_
&& lhs.uwave_ == rhs.uwave_
&& lhs.noun_ == rhs.noun_
&& lhs.number_ == rhs.number_;
&& lhs.number_ == rhs.number_
&& lhs.nospellcheck_ == rhs.nospellcheck_;
}

View File

@ -4231,6 +4231,9 @@ SpellChecker::Result Paragraph::spellCheck(pos_type & from, pos_type & to,
docstring word = asString(from, to, AS_STR_INSETS | AS_STR_SKIPDELETE);
Language * lang = d->getSpellLanguage(from);
if (getFontSettings(d->inset_owner_->buffer().params(), from).fontInfo().nospellcheck() == FONT_ON)
return result;
wl = WordLangTuple(word, lang);
if (word.empty())

View File

@ -139,6 +139,13 @@ void RowPainter::paintInset(Row::Element const & e) const
}
void RowPainter::paintLanguageMarkings(Row::Element const & e) const
{
paintForeignMark(e);
paintNoSpellingMark(e);
}
void RowPainter::paintForeignMark(Row::Element const & e) const
{
Language const * lang = e.font.language();
@ -157,6 +164,23 @@ void RowPainter::paintForeignMark(Row::Element const & e) const
}
void RowPainter::paintNoSpellingMark(Row::Element const & e) const
{
//if (!lyxrc.mark_no_spelling)
// return;
if (e.font.language() == latex_language)
return;
if (!e.font.fontInfo().nospellcheck())
return;
int const desc = e.inset ? e.dim.descent() : 0;
int const y = yo_ + pi_.base.solidLineOffset()
+ desc + pi_.base.solidLineThickness() / 2;
pi_.pain.line(int(x_), y, int(x_ + e.full_width()), y, Color_language,
Painter::line_onoffdash, pi_.base.solidLineThickness());
}
void RowPainter::paintMisspelledMark(Row::Element const & e) const
{
// if changed the misspelled marker gets placed slightly lower than normal
@ -541,8 +565,9 @@ void RowPainter::paintOnlyInsets()
Row::Element const & e = *cit;
if (e.type == Row::INSET) {
paintInset(e);
// The line that indicates word in a different language
paintForeignMark(e);
// The markings of foreign languages
// and of text ignored for spellchecking
paintLanguageMarkings(e);
// change tracking (not for insets that handle it themselves)
if (!e.inset->canPaintChange(*pi_.base.bv))
paintChange(e);
@ -578,8 +603,9 @@ void RowPainter::paintText()
pi_.pain.textDecoration(e.font.fontInfo(), int(x_), yo_, int(e.full_width()));
}
// The line that indicates word in a different language
paintForeignMark(e);
// The markings of foreign languages
// and of text ignored for spellchecking
paintLanguageMarkings(e);
// change tracking (not for insets that handle it themselves)
if (e.type != Row::INSET || ! e.inset->canPaintChange(*pi_.base.bv))

View File

@ -57,7 +57,9 @@ public:
void paintSelection() const;
private:
void paintLanguageMarkings(Row::Element const & e) const;
void paintForeignMark(Row::Element const & e) const;
void paintNoSpellingMark(Row::Element const & e) const;
void paintStringAndSel(Row::Element const & e) const;
void paintMisspelledMark(Row::Element const & e) const;
void paintChange(Row::Element const & e) const;

View File

@ -445,6 +445,9 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
} else if (token == "\\numeric") {
lex.next();
font.fontInfo().setNumber(setLyXMisc(lex.getString()));
} else if (token == "\\nospellcheck") {
lex.next();
font.fontInfo().setNoSpellcheck(setLyXMisc(lex.getString()));
} else if (token == "\\emph") {
lex.next();
font.fontInfo().setEmph(setLyXMisc(lex.getString()));

View File

@ -347,6 +347,8 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
newfi.setNoun(oldfi.noun() == FONT_OFF ? FONT_ON : FONT_OFF);
if (newfi.number() == FONT_TOGGLE)
newfi.setNumber(oldfi.number() == FONT_OFF ? FONT_ON : FONT_OFF);
if (newfi.nospellcheck() == FONT_TOGGLE)
newfi.setNoSpellcheck(oldfi.nospellcheck() == FONT_OFF ? FONT_ON : FONT_OFF);
}
setFont(cur.bv(), cur.selectionBegin().top(),

View File

@ -261,6 +261,7 @@ GuiCharacter::GuiCharacter(GuiView & lv)
bc().addReadOnly(strikeCO);
bc().addReadOnly(nounCB);
bc().addReadOnly(emphCB);
bc().addReadOnly(nospellcheckCB);
bc().addReadOnly(langCO);
bc().addReadOnly(colorCO);
bc().addReadOnly(autoapplyCB);
@ -296,6 +297,18 @@ void GuiCharacter::on_nounCB_clicked()
}
void GuiCharacter::on_nospellcheckCB_clicked()
{
// skip intermediate state at user click
if (!nospellcheck_) {
nospellcheckCB->setCheckState(Qt::Checked);
nospellcheck_ = true;
}
change_adaptor();
}
void GuiCharacter::change_adaptor()
{
changed();
@ -418,6 +431,8 @@ void GuiCharacter::updateContents()
font.fontInfo().setEmph(FONT_IGNORE);
if (fi.noun() != tmp.fontInfo().noun())
font.fontInfo().setNoun(FONT_IGNORE);
if (fi.nospellcheck() != tmp.fontInfo().nospellcheck())
font.fontInfo().setNoSpellcheck(FONT_IGNORE);
if (fi.color() != tmp.fontInfo().color())
font.fontInfo().setColor(Color_ignore);
if (fi.underbar() != tmp.fontInfo().underbar()
@ -519,8 +534,10 @@ void GuiCharacter::paramsToDialog(Font const & font)
colorCO->setCurrentIndex(colorCO->findData(toqstr(lcolor.getLyXName(fi.color()))));
emphCB->setCheckState(getMarkupState(fi.emph()));
nounCB->setCheckState(getMarkupState(fi.noun()));
nospellcheckCB->setCheckState(getMarkupState(fi.nospellcheck()));
emph_ = emphCB->checkState() == Qt::Checked;
noun_ = nounCB->checkState() == Qt::Checked;
nospellcheck_ = nospellcheckCB->checkState() == Qt::Checked;
// reset_language is a null pointer.
QString const lang = (font.language() == reset_language)
@ -538,6 +555,7 @@ void GuiCharacter::applyView()
fi.setSize(size[sizeCO->currentIndex()].second);
fi.setEmph(setMarkupState(emphCB->checkState()));
fi.setNoun(setMarkupState(nounCB->checkState()));
fi.setNoSpellcheck(setMarkupState(nospellcheckCB->checkState()));
setBar(fi, bar[ulineCO->currentIndex()].second);
setStrike(fi, strike[strikeCO->currentIndex()].second);
fi.setColor(lcolor.getFromLyXName(fromqstr(colorCO->itemData(colorCO->currentIndex()).toString())));

View File

@ -65,6 +65,7 @@ protected Q_SLOTS:
void change_adaptor();
void on_emphCB_clicked();
void on_nounCB_clicked();
void on_nospellcheckCB_clicked();
private:
/// \name Dialog inherited methods
@ -102,6 +103,8 @@ private:
bool emph_;
///
bool noun_;
///
bool nospellcheck_;
};
} // namespace frontend

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>523</width>
<height>365</height>
<height>412</height>
</rect>
</property>
<property name="windowTitle">
@ -16,8 +16,86 @@
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_7">
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="autoapplyCB">
<property name="toolTip">
<string>Apply each change automatically</string>
</property>
<property name="text">
<string>Apply changes &amp;immediately</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okPB">
<property name="text">
<string>&amp;OK</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyPB">
<property name="text">
<string>&amp;Apply</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closePB">
<property name="text">
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
@ -243,14 +321,24 @@
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>&amp;Language</string>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Language Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="LanguageLA">
<property name="text">
<string>&amp;Language:</string>
</property>
<property name="buddy">
<cstring>langCO</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="langCO">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@ -264,132 +352,48 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Semantic Markup</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="emphCB">
<property name="toolTip">
<string>Semantic emphasizing (italic by default, but can be adapted)</string>
</property>
<property name="text">
<string>&amp;Emphasized</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="nounCB">
<property name="toolTip">
<string>Semantic markup of nouns (small caps by default, but can be adapted)</string>
</property>
<property name="text">
<string>&amp;Noun</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="nospellcheckCB">
<property name="toolTip">
<string>If this is selected, the marked text will not be spellchecked</string>
</property>
<property name="text">
<string>E&amp;xclude from Spellchecking</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Semantic Markup</string>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="autoapplyCB">
<property name="toolTip">
<string>Apply each change automatically</string>
</property>
<property name="text">
<string>Apply changes &amp;immediately</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="okPB">
<property name="text">
<string>&amp;OK</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="applyPB">
<property name="text">
<string>&amp;Apply</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closePB">
<property name="text">
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QCheckBox" name="emphCB">
<property name="toolTip">
<string>Semantic emphasizing (italic by default, but can be adapted)</string>
</property>
<property name="text">
<string>&amp;Emphasized</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="nounCB">
<property name="toolTip">
<string>Semantic markup of nouns (small caps by default, but can be adapted)</string>
</property>
<property name="text">
<string>&amp;Noun</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>

View File

@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
#define LYX_FORMAT_LYX 550 // spitz: \fontenc auto
#define LYX_FORMAT_TEX2LYX 550
#define LYX_FORMAT_LYX 551 // spitz: \nospellcheck font param
#define LYX_FORMAT_TEX2LYX 551
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER