diff --git a/development/scons/scons_manifest.py b/development/scons/scons_manifest.py index 70ca9fe821..f5471d5774 100644 --- a/development/scons/scons_manifest.py +++ b/development/scons/scons_manifest.py @@ -462,6 +462,7 @@ src_mathed_header_files = Split(''' InsetMathScript.h InsetMathSize.h InsetMathSpace.h + InsetMathSpecialChar.h InsetMathSplit.h InsetMathSqrt.h InsetMathStackrel.h @@ -533,6 +534,7 @@ src_mathed_files = Split(''' InsetMathScript.cpp InsetMathSize.cpp InsetMathSpace.cpp + InsetMathSpecialChar.cpp InsetMathSplit.cpp InsetMathSqrt.cpp InsetMathStackrel.cpp diff --git a/lib/symbols b/lib/symbols index f28529c0d0..66b8be98be 100644 --- a/lib/symbols +++ b/lib/symbols @@ -865,14 +865,6 @@ gcd lyxblacktext 0 0 funclim x deg lyxblacktext 0 0 func x bmod lyxblacktext 0 0 func x -{ mathrm 0 0 special x -} mathrm 0 0 special x -$ mathrm 0 0 special x -% mathrm 0 0 special x -& mathrm 0 0 special x -## don't remove the space from the beginning of the next line - # mathrm 0 0 special x - # @@ -912,7 +904,6 @@ endif iffont msb \def\Join{\ltimes\kern-18.5mu\rtimes} endif -\def\mathcircumflex{\mbox{\^{}}}{\^} # Fixme: latin-1 chars in text file \def\AA{\AA}{Å} \def\O{\O}{Ø} diff --git a/src/Makefile.am b/src/Makefile.am index 2b00b6733f..a94f6c720c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -361,6 +361,7 @@ SOURCEFILESMATHED = \ mathed/InsetMathScript.cpp \ mathed/InsetMathSize.cpp \ mathed/InsetMathSpace.cpp \ + mathed/InsetMathSpecialChar.cpp \ mathed/InsetMathSplit.cpp \ mathed/InsetMathSqrt.cpp \ mathed/InsetMathStackrel.cpp \ @@ -425,6 +426,7 @@ HEADERFILESMATHED = \ mathed/InsetMathScript.h \ mathed/InsetMathSize.h \ mathed/InsetMathSpace.h \ + mathed/InsetMathSpecialChar.h \ mathed/InsetMathSplit.h \ mathed/InsetMathSqrt.h \ mathed/InsetMathStackrel.h \ diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h index 2f91e9ede5..589f7b27e3 100644 --- a/src/mathed/InsetMath.h +++ b/src/mathed/InsetMath.h @@ -66,6 +66,7 @@ class InsetMathNest; class InsetMathScript; class InsetMathString; class InsetMathSpace; +class InsetMathSpecialChar; class InsetMathSymbol; class InsetMathUnknown; @@ -142,6 +143,7 @@ public: virtual InsetMathUnknown * asUnknownInset() { return 0; } virtual InsetMathUnknown const * asUnknownInset() const { return 0; } virtual InsetMathRef * asRefInset() { return 0; } + virtual InsetMathSpecialChar const * asSpecialCharInset() const { return 0; } /// identifies things that can get scripts virtual bool isScriptable() const { return false; } diff --git a/src/mathed/InsetMathNest.cpp b/src/mathed/InsetMathNest.cpp index 591e3609e4..ffde2ad45f 100644 --- a/src/mathed/InsetMathNest.cpp +++ b/src/mathed/InsetMathNest.cpp @@ -1435,6 +1435,9 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) cur.niceInsert(createInsetMath("textbackslash")); else cur.niceInsert(createInsetMath("backslash")); + } else if (c == '^' && currentMode() == InsetMath::MATH_MODE) { + cur.backspace(); + cur.niceInsert(createInsetMath("mathcircumflex")); } else if (c == '{') { cur.backspace(); cur.niceInsert(MathAtom(new InsetMathBrace)); @@ -1564,7 +1567,7 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) return cur.pos() != cur.lastpos(); } - // These shouldn't work in text mode: + // These should be treated differently when not in text mode: if (currentMode() != InsetMath::TEXT_MODE) { if (c == '_') { script(cur, false, save_selection); @@ -1578,10 +1581,19 @@ bool InsetMathNest::interpretChar(Cursor & cur, char_type c) cur.niceInsert(createInsetMath("sim")); return true; } + } else { + if (c == '^') { + cur.niceInsert(createInsetMath("textasciicircum")); + return true; + } + if (c == '~') { + cur.niceInsert(createInsetMath("textasciitilde")); + return true; + } } if (c == '{' || c == '}' || c == '&' || c == '$' || c == '#' || - c == '%' || c == '_' || c == '^') { + c == '%' || c == '_') { cur.niceInsert(createInsetMath(docstring(1, c))); return true; } diff --git a/src/mathed/InsetMathSpecialChar.cpp b/src/mathed/InsetMathSpecialChar.cpp new file mode 100644 index 0000000000..6157c7977a --- /dev/null +++ b/src/mathed/InsetMathSpecialChar.cpp @@ -0,0 +1,148 @@ +/** + * \file InsetMathSpecialChar.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Enrico Forestieri + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "InsetMathSpecialChar.h" + +#include "MathSupport.h" +#include "MathStream.h" +#include "MetricsInfo.h" + +#include "Dimension.h" +#include "LaTeXFeatures.h" +#include "TextPainter.h" + +#include "frontends/FontMetrics.h" + +#include "support/lassert.h" + + +namespace lyx { + + +InsetMathSpecialChar::InsetMathSpecialChar(docstring name) + : name_(name), kerning_(0) +{ + if (name.size() != 1) { + if (name == from_ascii("textasciicircum") + || name == from_ascii("mathcircumflex")) + char_ = '^'; + else if (name == from_ascii("textasciitilde")) + char_ = '~'; + else if (name == from_ascii("textbackslash")) + char_ = '\\'; + else + LASSERT(false, /**/); + } else + char_ = name.at(0); +} + + + +Inset * InsetMathSpecialChar::clone() const +{ + return new InsetMathSpecialChar(*this); +} + + +void InsetMathSpecialChar::metrics(MetricsInfo & mi, Dimension & dim) const +{ + if (mi.base.fontname == "mathnormal") { + ShapeChanger dummy(mi.base.font, UP_SHAPE); + dim = theFontMetrics(mi.base.font).dimension(char_); + } else { + frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); + dim = fm.dimension(char_); + kerning_ = fm.rbearing(char_) - dim.wid; + } +} + + +void InsetMathSpecialChar::draw(PainterInfo & pi, int x, int y) const +{ + if (pi.base.fontname == "mathnormal") { + ShapeChanger dummy(pi.base.font, UP_SHAPE); + pi.draw(x, y, char_); + } else { + pi.draw(x, y, char_); + } +} + + +void InsetMathSpecialChar::metricsT(TextMetricsInfo const &, Dimension & dim) const +{ + dim.wid = 1; + dim.asc = 1; + dim.des = 0; +} + + +void InsetMathSpecialChar::drawT(TextPainter & pain, int x, int y) const +{ + pain.draw(x, y, char_); +} + + +void InsetMathSpecialChar::write(WriteStream & os) const +{ + os << '\\' << name_; + if (name_.size() != 1) + os.pendingSpace(true); +} + + +void InsetMathSpecialChar::validate(LaTeXFeatures & features) const +{ + if (name_ == "mathcircumflex") + features.require("mathcircumflex"); +} + + +void InsetMathSpecialChar::normalize(NormalStream & os) const +{ + os << "[char "; + os.os().put(char_); + os << " mathalpha]"; +} + + +void InsetMathSpecialChar::maple(MapleStream & os) const +{ + os.os().put(char_); +} + + +void InsetMathSpecialChar::mathematica(MathematicaStream & os) const +{ + os.os().put(char_); +} + + +void InsetMathSpecialChar::octave(OctaveStream & os) const +{ + os.os().put(char_); +} + + +void InsetMathSpecialChar::mathmlize(MathStream & ms) const +{ + switch (char_) { + case '&': + ms << "&"; + break; + default: + ms.os().put(char_); + break; + } +} + + +} // namespace lyx diff --git a/src/mathed/InsetMathSpecialChar.h b/src/mathed/InsetMathSpecialChar.h new file mode 100644 index 0000000000..7e2e8083f8 --- /dev/null +++ b/src/mathed/InsetMathSpecialChar.h @@ -0,0 +1,69 @@ +// -*- C++ -*- +/** + * \file InsetMathSpecialChar.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Enrico Forestieri + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef MATH_SPECIALCHARINSET_H +#define MATH_SPECIALCHARINSET_H + +#include "InsetMath.h" + +namespace lyx { + +/// The special character inset. +class InsetMathSpecialChar : public InsetMath { +public: + /// + explicit InsetMathSpecialChar(docstring name); + /// + void setBuffer(Buffer &) {} + /// + void metrics(MetricsInfo & mi, Dimension & dim) const; + /// + void draw(PainterInfo & pi, int x, int y) const; + /// + void metricsT(TextMetricsInfo const & mi, Dimension & dim) const; + /// + void drawT(TextPainter &, int x, int y) const; + /// + int kerning(BufferView const *) const { return kerning_; } + /// + void write(WriteStream & os) const; + /// + void validate(LaTeXFeatures & features) const; + /// + void normalize(NormalStream & ns) const; + /// + void octave(OctaveStream & os) const; + /// + void maple(MapleStream &) const; + /// + void mathematica(MathematicaStream &) const; + /// + void mathmlize(MathStream & ms) const; + /// identifies SpecialChar insets + InsetMathSpecialChar const * asSpecialCharInset() const { return this; } + /// + docstring name() const { return name_; } + /// + char_type getChar() const { return char_; } + +private: + virtual Inset * clone() const; + /// the latex name + docstring name_; + /// the displayed character + char_type char_; + /// cached kerning for superscript + mutable int kerning_; +}; + +} // namespace lyx + +#endif diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp index c8060086b9..8791b719a5 100644 --- a/src/mathed/MathFactory.cpp +++ b/src/mathed/MathFactory.cpp @@ -32,6 +32,7 @@ #include "InsetMathRoot.h" #include "InsetMathSize.h" #include "InsetMathSpace.h" +#include "InsetMathSpecialChar.h" #include "InsetMathSplit.h" #include "InsetMathSqrt.h" #include "InsetMathStackrel.h" @@ -218,6 +219,20 @@ void initSymbols() } +bool isSpecialChar(docstring name) +{ + if (name.size() != 1) { + string const s = to_ascii(name); + return s == "textasciicircum" || s == "mathcircumflex" || + s == "textasciitilde" || s == "textbackslash"; + } else { + char_type const c = name.at(0); + return c == '{' || c == '}' || c == '&' || c == '$' || + c == '#' || c == '%' || c == '_'; + } +} + + } // namespace anon MathWordList const & mathedWordList() @@ -446,6 +461,8 @@ MathAtom createInsetMath(docstring const & s) return MathAtom(new InsetMathPhantom(InsetMathPhantom::vphantom)); if (s == "ensuremath") return MathAtom(new InsetMathEnsureMath); + if (isSpecialChar(s)) + return MathAtom(new InsetMathSpecialChar(s)); return MathAtom(new MathMacro(s)); } diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index fb05c7182e..c90b7188f4 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -518,8 +518,8 @@ void MathMacro::validate(LaTeXFeatures & features) const if (!requires_.empty()) features.require(requires_); - if (name() == "binom" || name() == "mathcircumflex") - features.require(to_utf8(name())); + if (name() == "binom") + features.require("binom"); // validate the cells and the definition if (displayMode() == DISPLAY_NORMAL) { diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp index 56fdf23c81..7494a2906c 100644 --- a/src/mathed/MathParser.cpp +++ b/src/mathed/MathParser.cpp @@ -100,11 +100,16 @@ bool stared(docstring const & s) } -docstring escapeSpecialChars(docstring const & str) +docstring escapeSpecialChars(docstring const & str, bool textmode) { + docstring const backslash = textmode ? from_ascii("\\textbackslash ") + : from_ascii("\\backslash "); + docstring const caret = textmode ? from_ascii("\\textasciicircum ") + : from_ascii("\\mathcircumflex "); + return subst(subst(subst(subst(subst(subst(subst(subst(subst(str, - from_ascii("\\"), from_ascii("\\backslash ")), - from_ascii("^"), from_ascii("\\mathcircumflex ")), + from_ascii("\\"), backslash), + from_ascii("^"), caret), from_ascii("_"), from_ascii("\\_")), from_ascii("$"), from_ascii("\\$")), from_ascii("#"), from_ascii("\\#")), @@ -540,8 +545,9 @@ void Parser::tokenize(istream & is) void Parser::tokenize(docstring const & buffer) { - idocstringstream is(mode_ & Parse::VERBATIM ? - escapeSpecialChars(buffer) : buffer, ios::in | ios::binary); + idocstringstream is(mode_ & Parse::VERBATIM + ? escapeSpecialChars(buffer, mode_ & Parse::TEXTMODE) + : buffer, ios::in | ios::binary); char_type c; while (is.get(c)) {