First shot at "auto correction" feature in mathed

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4195 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
André Pönitz 2002-05-24 08:29:16 +00:00
parent 946518bdcd
commit 4dd8a4ed0a
11 changed files with 587 additions and 7 deletions

View File

@ -1,3 +1,8 @@
2002-05-23 André Pönitz <poenitz@gmx.net>
* lib/autocorrect: new file
2002-05-03 Claus Hindsgaul <claus_h@image.dk> 2002-05-03 Claus Hindsgaul <claus_h@image.dk>
* examples/da_splash.lyx: revised * examples/da_splash.lyx: revised

352
lib/autocorrect Normal file
View File

@ -0,0 +1,352 @@
#
# Idea of "autocorrection" and parts of this file are shamelessly stolen
# from TeXMacs (they give vdhoeven@texmacs.org as contact)
#
# We do it a bit differently and allow corrections only to combine a symbol
# and a char to a new symbol.
#
#
| , \lfloor
\lfloor * |,
| ' \lceil
\lceil * |'
, | \rfloor
\rfloor * ,|
' | \rceil
\rceil * '|
\llbracket * [[*
\rrbracket * ]]*
\cap * \sqcap
\cup * \sqcup
\vee * \curlyvee
\curlyvee * \curlyveeuparrow
\curlyveeuparrow * \curlyveedownarrow
< / \nless
> / \ngtr
< = \leqslant
> = \geqslant
\leqslant / \nleqslant
\geqslant / \ngeqslant
\leqslant * \leq
\geslant * \geq
\leq / \nleq
\geq / \ngeq
< < \ll
\ll < \lll
> > \gg
\gg > \ggg
\ll = \lleq
\lll = \llleq
\gg = \ggeq
\ggg = \gggeq
\ll / \nll
\lll / \nlll
\gg / \ngg
\ggg / \nggg
\lleq / \nlleq
\llleq / \nllleq
\ggeq / \nggeq
\gggeq / \ngggeq
< . \lessdot
. > \gtrdot
\leqslant . \lesseqdot
\gtrdot = \gtreqdot
< * \prec
> * \succ
\prec / \nprec
\succ / \nsucc
\prec = \preccurlyeq
\succ = \succcurlyeq
\preccurlyeq / \npreccurlyeq
\succcurlyeq / \nsucccurlyeq
\preccurlyeq * \preceq
\succcurlyeq * \succeq
\preceq / \npreceq
\succeq / \nsucceq
\npreceq * \precneqq
\nsucceq * \succneqq
\ll * \precprec
\precprec * \precprecprec
\gg * \succsucc
\succsucc * \succsuccsucc
\precprec = \precpreceq
\lll * \precprecprec
\precprecprec = \precprecpreceq
\succsucc = \succsucceq
\ggg = \succsuccsucc
\succsuccsucc = \succsuccsucceq
\precprec / \nprecprec
\precprecprec / \nprecprecprec
\succsucc / \nsuccsucc
\succsuccsucc / \nsuccsuccsucc
\precpreceq / \nprecpreceq
\precprecpreceq / \nprecprecpreceq
\succsucceq / \nsuccsucceq
\succsuccsucceq / \nsuccsuccsucceq
\prec . \precdot
\succ . \dotsucc
\precdot . \preceqdot
\dotsucc . \dotsucceq
\precprec * \llangle
\succsucc * \rrangle
< > \lessgtr
> < \gtrless
< ~ \lesssim
\lesssim ~ \lessapprox
\prec ~ \precsim
\precsim ~ \precapprox
> ~ \gtrsim
\gtrsim ~ \gtrapprox
\succ ~ \gtrsim
\gtrsim ~ \gtrapprox
\leq * \leqq
\geq * \geqq
\leq > \lesseqgtr
\geq < \gtrqless
- > \rightarrow
< - \leftarrow
\leftarrow > \leftrightarrow
\rightarrow - \longrightarrow
\leftarrow - \longleftarrow
\longleftarrow > \longleftrightarrow
= > \Rightarrow
@ * \circ
\circ / \varnothing
\circ + \oplus
\circ - \ominus
@ x \otimes
\circ : \oover
\circ . \odot
@ R \circledR
@ S \circledS
\varnothing * \oslash
@ \ \obslash
@ @ \infty
\circ < \olessthan
\circ > \ogreaterthan
\circ & \owedge
\circ | \obar
\obar * \ovee
\circ v \ovee
\circ @ \infty
@@ * \varocircle
-@ @ \infty
\circ * \box
\box + \boxplus
\box - \boxminus
\box x \boxtimes
\box . \boxdot
\box / \boxslash
\box \ \boxbslash
\box @ \boxcircle
\boxcircle * \boxbox
\box | \boxbar
\box * \bullet
\bullet * \blacksquare
= * \asymp
\asymp * \equiv
\equiv * \asympasymp
\asympasymp * \simsim
~ * \sim
\sim ~ \approx
\approx - \approxeq
\sim - \simeq
\sim = \cong
= / \neq
\asymp / \nasymp
\equiv / \nequiv
\asympasymp / \nasympasymp
\simsim / \nsimsim
\sim / \nsim
\approx / \napprox
\simeq / \nsimeq
\cong / \ncong
#| \|
| * \shortmid
\shortmid * \varshortmid
| | \||
\|| | \interleave
\|| * \shortparallel
| - \vdash
\vdash - \longvdash
\|| - \Vdash
\Vdash - \longVdash
\interleave - \Vvdash
\Vvdash - \longVvdash
- | \dashv
< | \vartriangleleft
\vartriangleleft * \blacktriangleleft
\vartriangleleft / \ntriangleleft
\vartriangleleft = \trianglelefteqslant
\trianglelefteqslant / \ntrianglelefteqslant
\trianglelefteqslant * \trianglelefteq
\trianglelefteq / \ntriangleqleft
| > \vartriangleright
\vartriangleright * \blacktriangleright
\vartriangleright / \ntriangleright
\vartriangleright = \trianglerighteq
\trianglerighteq / \ntriangleqright
\trianglerighteq * \trianglerighteqslant
\trianglerighteqslant / \ntrianglerighteqslant
- * \um
+ - \pm
\pm * \upm
- + \mp
\mp * \ump
@ = \circeq
= @ \eqcirc
- @ \multimap
. = \doteq
. . \ldots
\ldots * \cdots
\cdots * \hdots
\hdots * \vdots
\ddots * \ddots
\udots * \udots
: = \assign
+ = \plusassign
- = \minusassign
/ * \div
* * \ast
\ast * \times
\times * \cdot
< * \subset
\subset * \in
\ / \nsubset
\in * \sqsubset
\subset = \subseteq
\subseteq / \nsubseteq
\subseteq * \subseteqq
\sqsubset * \langle
\langle * \leftslice
\leftslice * \subset
\subseteq / \nsubseteq
\subseteqq / \nsubseteqq
\nsubseteqq * \subsetneq
\subsetneq * \varsubsetneq
\varsubsetneq * \subsetneqq
\subsetneqq * \varsubsetneqq
\subset + \subsetplus
\subsetplus = \subsetpluseq
\subseteq + \subsetpluseq
\in / \nin
> * \supset
\supset / \nsupset
\supset = \supseteq
\supseteq / \nsupseteq
\supseteq * \supseteqq
\supseteq / \nsupseteq
\supseteqq / \nsupseteqq
\supseteq / \supsetneq
\supset + \supsetplus
\supsetplus = \supsetpluseq
\supseteq + \supsetpluseq
\supset * \ni
\ni / \nni
#
# The following is available in TeXMacs, but not (yet) in LyX
#
#--| \longdashv
#| = \vDash
#\vDash = \longvDash
#||= \VDash
#||== \longVDash
#| / \nmid
#||/ \nparallel
#|*/ \nshortmid
#||*/ \nshortparallel
#|-/ \nvdash
#||-/ \nVdash
#-|/ \ndashv
#-||/ \ndashV
#|=/ \nvDash
#||=/ \nVDash
#=|/ \nDashv
#=||/ \nDashV
#
#<=**> \lesseqqgtr
#>=**< \gtreqqless
#<>/ \nlessgtr
#></ \ngtrless
#<~/ \nlesssim
#<~/* \lnsim
#<~~/ \nlessapprox
#<~~/* \lnapprox
#<*~/ \nprecsim
#<*~/* \precnsim
#<*~~/ \nprecapprox
#<*~~/* \precnapprox
#>~/ \ngtrsim
#>~/* \gnsim
#>~~/ \ngtrapprox
#>~~/* \gnapprox
#>*~/ \nsuccsim
#>*~/* \succnsim
#>*~~/ \nsuccapprox
#>*~~/* \succnapprox
#<=**/ \nleqq
#>=**/ \ngeqq
#<=*>/ \nlesseqgtr
#>=*</ \ngtreqless
#<=**>/ \nlesseqqgtr
#>=**</ \ngtreqqless
#<=*/* \lneq
#<=**/* \lneqq
#<=**/** \lvertneqq
#>=*/* \gneq
#>=**/* \gneqq
#>=**/** \gvertneqq
#[[ * \llbracket
#]] * \rrbracket
#EE a \amalg
#EE d \partial
#EE p \wp
#EE n \cap
#EE u \cup
#EE w \wedge
#\wedge * \curlywedge
#\curlywedge * \curlywedgeuparrow
#\curlywedgeuparrow * \curlywedgedownarrow
#\curlywedgedownarrow * \wedges
#EE v \vee
#EE x \times
# <***/ \nsqsubset
# <***= \sqsubseteq
# <***=/ \nsqsubseteq
# >*=/** \varsupsetneq
# >*=*/* \supsetneqq
# >*=*/** \varsupsetneqq
# >*** \sqsupset
# >***/ \nsqsupset
# >***= \sqsupseteq
# >***=/ \nsqsupseteq
# >**** \rangle
# \rangle * \rightslice
# EE l \bigl
# EE m \bigm
# EE r \bigr
# EE @ \bigop
# EE L \int

View File

@ -1,3 +1,11 @@
2002-05-23 André Pönitz <poenitz@gmx.net>
* math_autocorrect.[Ch]: new "auto correction" feature
* math_cursor.[Ch]: subsequent changes
* math_parser.C: somewhat better error reporting
2002-05-23 John Levon <moz@compsoc.man.ac.uk> 2002-05-23 John Levon <moz@compsoc.man.ac.uk>
* formula.C: * formula.C:

View File

@ -19,6 +19,8 @@ libmathed_la_SOURCES = \
math_arrayinset.h \ math_arrayinset.h \
math_atom.C \ math_atom.C \
math_atom.h \ math_atom.h \
math_autocorrect.C \
math_autocorrect.h \
math_biginset.C \ math_biginset.C \
math_biginset.h \ math_biginset.h \
math_binominset.C \ math_binominset.C \

View File

@ -0,0 +1,168 @@
#include <config.h>
#include "LString.h"
#include "Lsstream.h"
#include "debug.h"
#include "support/filetools.h" // LibFileSearch
#include "math_data.h"
#include "math_inset.h"
#include "math_parser.h"
#include <iostream>
#include <fstream>
using std::ifstream;
using std::istream;
using std::ostream;
using std::endl;
namespace {
class Correction {
public:
///
Correction() {}
///
bool correct(MathAtom & at, char c) const;
///
bool read(istream & is);
///
void write(ostream & os) const;
private:
///
MathAtom from1_;
///
char from2_;
///
MathAtom to_;
};
bool Correction::read(istream & is)
{
string s1, s2, s3;
is >> s1 >> s2 >> s3;
if (!is)
return false;
MathArray ar1, ar3;
mathed_parse_cell(ar1, s1);
mathed_parse_cell(ar3, s3);
if (ar1.size() != 1 || s2.size() != 1 || ar3.size() !=1)
return false;
from1_ = ar1.front();
from2_ = s2[0];
to_ = ar3.front();
return true;
}
void Correction::write(ostream & os) const
{
os << "from: '" << from1_ << "' and '" << from2_
<< "' to '" << to_ << "'" << endl;
}
bool Correction::correct(MathAtom & at, char c) const
{
//lyxerr[Debug::MATHED]
// << "trying to correct ar: " << at << " from: '" << from1_ << "'" << endl;
if (from2_ != c)
return false;
if (!at->match(from1_.nucleus()))
return false;
lyxerr[Debug::MATHED]
<< "match found! subst in " << at
<< " from: '" << from1_ << "' to '" << to_ << "'" << endl;
at = to_;
return true;
}
istream & operator>>(istream & is, Correction & corr)
{
corr.read(is);
return is;
}
ostream & operator<<(ostream & os, Correction & corr)
{
corr.write(os);
return os;
}
class Corrections {
public:
///
typedef vector<Correction>::const_iterator const_iterator;
///
Corrections() {}
///
void insert(const Correction & corr) { data_.push_back(corr); }
///
bool correct(MathAtom & at, char c) const;
private:
///
vector<Correction> data_;
};
bool Corrections::correct(MathAtom & at, char c) const
{
for (const_iterator it = data_.begin(); it != data_.end(); ++it)
if (it->correct(at, c))
return true;
return false;
}
Corrections theCorrections;
void initAutoCorrect()
{
lyxerr[Debug::MATHED] << "reading autocorrect file" << endl;
string const file = LibFileSearch(string(), "autocorrect");
if (file.empty()) {
lyxerr << "Could not find autocorrect file" << endl;
return;
}
string line;
ifstream is(file.c_str());
while (getline(is, line)) {
if (line.size() == 0 || line[0] == '#') {
//lyxerr[Debug::MATHED] << "ignoring line '" << line << "'" << endl;
continue;
}
istringstream il(line);
//lyxerr[Debug::MATHED] << "line '" << line << "'" << endl;
Correction corr;
if (corr.read(il)) {
//lyxerr[Debug::MATHED] << "parsed: '" << corr << "'" << endl;
theCorrections.insert(corr);
}
}
lyxerr[Debug::MATHED] << "done reading autocorrections." << endl;
}
} // namespace anon
bool math_autocorrect(MathAtom & at, char c)
{
static bool initialized = false;
if (!initialized) {
initAutoCorrect();
initialized = true;
}
return theCorrections.correct(at, c);
}

View File

@ -0,0 +1,9 @@
#ifndef MATHAUTOCORRECT_H
#define MATHAUTOCORRECT_H
class MathAtom;
// make "corrections" according to file lib/autocorrect
bool math_autocorrect(MathAtom & at, char c);
#endif

View File

@ -29,6 +29,7 @@
#include "frontends/Painter.h" #include "frontends/Painter.h"
#include "math_cursor.h" #include "math_cursor.h"
#include "formulabase.h" #include "formulabase.h"
#include "math_autocorrect.h"
#include "math_arrayinset.h" #include "math_arrayinset.h"
#include "math_braceinset.h" #include "math_braceinset.h"
#include "math_boxinset.h" #include "math_boxinset.h"
@ -182,7 +183,8 @@ Selection theSelection;
MathCursor::MathCursor(InsetFormulaBase * formula, bool left) MathCursor::MathCursor(InsetFormulaBase * formula, bool left)
: formula_(formula), lastcode_(LM_TC_MIN), selection_(false) : formula_(formula), lastcode_(LM_TC_MIN),
autocorrect_(false), selection_(false)
{ {
left ? first() : last(); left ? first() : last();
} }
@ -299,6 +301,7 @@ bool MathCursor::posRight()
bool MathCursor::left(bool sel) bool MathCursor::left(bool sel)
{ {
dump("Left 1"); dump("Left 1");
autocorrect_ = false;
if (inMacroMode()) { if (inMacroMode()) {
macroModeClose(); macroModeClose();
lastcode_ = LM_TC_MIN; lastcode_ = LM_TC_MIN;
@ -319,6 +322,7 @@ bool MathCursor::left(bool sel)
bool MathCursor::right(bool sel) bool MathCursor::right(bool sel)
{ {
dump("Right 1"); dump("Right 1");
autocorrect_ = false;
if (inMacroMode()) { if (inMacroMode()) {
macroModeClose(); macroModeClose();
lastcode_ = LM_TC_MIN; lastcode_ = LM_TC_MIN;
@ -351,7 +355,7 @@ void MathCursor::last()
bool positionable(MathCursor::cursor_type const & cursor, bool positionable(MathCursor::cursor_type const & cursor,
MathCursor::cursor_type const & anchor) MathCursor::cursor_type const & anchor)
{ {
// avoid deeper nested insets when selecting // avoid deeper nested insets when selecting
if (cursor.size() > anchor.size()) if (cursor.size() > anchor.size())
@ -386,6 +390,7 @@ void MathCursor::setPos(int x, int y)
void MathCursor::home(bool sel) void MathCursor::home(bool sel)
{ {
dump("home 1"); dump("home 1");
autocorrect_ = false;
selHandle(sel); selHandle(sel);
macroModeClose(); macroModeClose();
lastcode_ = LM_TC_MIN; lastcode_ = LM_TC_MIN;
@ -398,6 +403,7 @@ void MathCursor::home(bool sel)
void MathCursor::end(bool sel) void MathCursor::end(bool sel)
{ {
dump("end 1"); dump("end 1");
autocorrect_ = false;
selHandle(sel); selHandle(sel);
macroModeClose(); macroModeClose();
lastcode_ = LM_TC_MIN; lastcode_ = LM_TC_MIN;
@ -498,6 +504,7 @@ void MathCursor::paste(MathArray const & ar)
void MathCursor::backspace() void MathCursor::backspace()
{ {
autocorrect_ = false;
if (pos() == 0) { if (pos() == 0) {
pullArg(false); pullArg(false);
return; return;
@ -523,6 +530,7 @@ void MathCursor::backspace()
void MathCursor::erase() void MathCursor::erase()
{ {
autocorrect_ = false;
if (inMacroMode()) if (inMacroMode())
return; return;
@ -556,6 +564,7 @@ void MathCursor::erase()
void MathCursor::delLine() void MathCursor::delLine()
{ {
autocorrect_ = false;
macroModeClose(); macroModeClose();
if (selection_) { if (selection_) {
@ -586,6 +595,7 @@ bool MathCursor::up(bool sel)
if (goUpDown(true)) if (goUpDown(true))
return true; return true;
Cursor_ = save; Cursor_ = save;
autocorrect_ = false;
return selection_; return selection_;
} }
@ -599,6 +609,7 @@ bool MathCursor::down(bool sel)
if (goUpDown(false)) if (goUpDown(false))
return true; return true;
Cursor_ = save; Cursor_ = save;
autocorrect_ = false;
return selection_; return selection_;
} }
@ -1490,6 +1501,12 @@ bool MathCursor::interpret(char c)
return true; return true;
} }
// leave autocorrect mode if necessary
if (autocorrect_ && c == ' ') {
autocorrect_ = false;
return true;
}
// just clear selection on pressing the space par // just clear selection on pressing the space par
if (selection_ && c == ' ') { if (selection_ && c == ' ') {
selClear(); selClear();
@ -1563,9 +1580,14 @@ bool MathCursor::interpret(char c)
return true; return true;
} }
// try auto-correction
if (autocorrect_ && hasPrevAtom() && math_autocorrect(prevAtom(), c))
return true;
// no special circumstances, so insert the character without any fuss // no special circumstances, so insert the character without any fuss
insert(c, lastcode_ == LM_TC_MIN ? MathCharInset::nativeCode(c) : lastcode_); insert(c, lastcode_ == LM_TC_MIN ? MathCharInset::nativeCode(c) : lastcode_);
lastcode_ = LM_TC_MIN; lastcode_ = LM_TC_MIN;
autocorrect_ = true;
return true; return true;
} }

View File

@ -287,7 +287,8 @@ private:
InsetFormulaBase * formula_; InsetFormulaBase * formula_;
/// text code of last char entered /// text code of last char entered
MathTextCodes lastcode_; MathTextCodes lastcode_;
// Selection stuff /// do we allow autocorrection
bool autocorrect_;
/// do we currently select /// do we currently select
bool selection_; bool selection_;
}; };

View File

@ -38,6 +38,16 @@ int MathInset::height() const
} }
ostream & operator<<(ostream & os, MathAtom const & at)
{
if (at.nucleus())
os << *(at.nucleus());
else
os << "(nil)";
return os;
}
ostream & operator<<(ostream & os, MathInset const & inset) ostream & operator<<(ostream & os, MathInset const & inset)
{ {
WriteStream wi(os, false, false); WriteStream wi(os, false, false);
@ -45,7 +55,6 @@ ostream & operator<<(ostream & os, MathInset const & inset)
return os; return os;
} }
MathInset::size_type MathInset::nargs() const MathInset::size_type MathInset::nargs() const
{ {
return 0; return 0;

View File

@ -255,5 +255,6 @@ public:
}; };
std::ostream & operator<<(std::ostream &, MathInset const &); std::ostream & operator<<(std::ostream &, MathInset const &);
std::ostream & operator<<(std::ostream &, MathAtom const &);
#endif #endif

View File

@ -420,8 +420,10 @@ bool Parser::good() const
char Parser::getChar() char Parser::getChar()
{ {
if (!good()) if (!good()) {
lyxerr << "The input stream is not well..." << endl; lyxerr << "The input stream is not well..." << endl;
dump();
}
return tokens_[pos_++].character(); return tokens_[pos_++].character();
} }
@ -486,7 +488,7 @@ void Parser::tokenize(string const & buffer)
char c; char c;
while (is.get(c)) { while (is.get(c)) {
//lyxerr << "reading c: " << c << "\n"; lyxerr << "reading c: " << c << "\n";
switch (catcode(c)) { switch (catcode(c)) {
case catNewline: { case catNewline: {
@ -1030,8 +1032,8 @@ void Parser::parse_into1(MathArray & array, unsigned flags, MathTextCodes code)
else if (t.cat() == catEnd) { else if (t.cat() == catEnd) {
if (flags & FLAG_BRACE_LAST) if (flags & FLAG_BRACE_LAST)
return; return;
dump();
lyxerr << "found '}' unexpectedly, array: '" << array << "'\n"; lyxerr << "found '}' unexpectedly, array: '" << array << "'\n";
dump();
//lyxerr << "found '}' unexpectedly\n"; //lyxerr << "found '}' unexpectedly\n";
//lyx::Assert(0); //lyx::Assert(0);
//add(array, '}', LM_TC_TEX); //add(array, '}', LM_TC_TEX);
@ -1039,6 +1041,7 @@ void Parser::parse_into1(MathArray & array, unsigned flags, MathTextCodes code)
else if (t.cat() == catAlign) { else if (t.cat() == catAlign) {
lyxerr << "found tab unexpectedly, array: '" << array << "'\n"; lyxerr << "found tab unexpectedly, array: '" << array << "'\n";
dump();
//lyxerr << "found tab unexpectedly\n"; //lyxerr << "found tab unexpectedly\n";
add(array, '&', LM_TC_TEX); add(array, '&', LM_TC_TEX);
} }