]> git.lyx.org Git - lyx.git/blob - src/mathed/MathAutoCorrect.cpp
Revert "XHTML: remove DOCTYPE, as the document is then understood as HTML4/XHTML1...
[lyx.git] / src / mathed / MathAutoCorrect.cpp
1 /**
2  * \file MathAutoCorrect.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "Cursor.h"
14 #include "MathAutoCorrect.h"
15 #include "MathData.h"
16 #include "InsetMath.h"
17 #include "MathSupport.h"
18 #include "MathParser.h"
19
20 #include "support/debug.h"
21 #include "support/FileName.h"
22 #include "support/filetools.h" //  LibFileSearch
23 #include "support/docstream.h"
24
25 #include <fstream>
26 #include <sstream>
27
28 using namespace std;
29
30 namespace lyx {
31
32 using support::libFileSearch;
33
34 namespace {
35
36 class Correction {
37 public:
38         ///
39         /// \brief Correction
40         Correction() : from2_(0) {}
41         ///
42         bool correct(Cursor & cur, char_type c) const;
43         ///
44         bool read(idocstream & is);
45         ///
46         void write(odocstream & os) const;
47 private:
48         ///
49         MathData from1_;
50         ///
51         char_type from2_;
52         ///
53         MathData to_;
54 };
55
56
57 bool Correction::read(idocstream & is)
58 {
59         docstring s1, s2, s3;
60         is >> s1 >> s2 >> s3;
61         if (!is)
62                 return false;
63         if (s2.size() != 1)
64                 return false;
65         MathData ar1, ar3;
66         mathed_parse_cell(ar1, s1);
67         mathed_parse_cell(ar3, s3);
68         from1_ = ar1;
69         from2_ = s2[0];
70         to_    = ar3;
71         return true;
72 }
73
74
75 bool Correction::correct(Cursor & cur, char_type c) const
76 {
77         //LYXERR(Debug::MATHED,
78         //      "trying to correct ar: " << at << " from: '" << from1_ << '\'');
79         if (from2_ != c)
80                 return false;
81         pos_type n = from1_.size();
82         if (cur.pos() < pos_type(from1_.size())) // not enough to match
83                 return false;
84         pos_type start = cur.pos() - from1_.size();
85
86         for (pos_type i = 0; i < n; i++)
87                 if (asString(cur.cell()[start + i]) != asString(from1_[i]))
88                         return false;
89
90         LYXERR(Debug::MATHED, "match found! subst in " << cur.cell()
91                 << " from: '" << from1_ << "' to '" << to_ << '\'');
92
93         /* To allow undoing the completion, we proceed in 4 steps
94          * - inset the raw character
95          * - split undo group so that we have two separate undo actions
96          * - record undo, delete the character we just entered and the from1_ part
97          * - finally, do the insertion of the correction.
98          */
99         cur.insert(c);
100         cur.splitUndoGroup();
101         cur.recordUndoSelection();
102         cur.cell().erase(cur.pos() - n - 1, cur.pos());
103         cur.pos() -= n + 1;
104
105         cur.insert(to_);
106         return true;
107 }
108
109
110 #if 0
111 void Correction::write(odocstream & os) const
112 {
113         os << "from: '" << from1_ << "' and '" << from2_
114            << "' to '" << to_ << '\'' << endl;
115 }
116
117
118 idocstream & operator>>(idocstream & is, Correction & corr)
119 {
120         corr.read(is);
121         return is;
122 }
123
124
125 odocstream & operator<<(odocstream & os, Correction & corr)
126 {
127         corr.write(os);
128         return os;
129 }
130 #endif
131
132
133
134 class Corrections {
135 public:
136         ///
137         typedef vector<Correction>::const_iterator const_iterator;
138         ///
139         Corrections() {}
140         ///
141         void insert(const Correction & corr) { data_.push_back(corr); }
142         ///
143         bool correct(Cursor & cur, char_type c) const;
144 private:
145         ///
146         vector<Correction> data_;
147 };
148
149
150 bool Corrections::correct(Cursor & cur, char_type c) const
151 {
152         for (const_iterator it = data_.begin(); it != data_.end(); ++it)
153                 if (it->correct(cur, c))
154                         return true;
155         return false;
156 }
157
158
159 Corrections theCorrections;
160
161 void initAutoCorrect()
162 {
163         LYXERR(Debug::MATHED, "reading autocorrect file");
164         support::FileName const file = libFileSearch(string(), "autocorrect");
165         if (file.empty()) {
166                 lyxerr << "Could not find autocorrect file" << endl;
167                 return;
168         }
169
170         string line;
171         ifstream is(file.toFilesystemEncoding().c_str());
172         while (getline(is, line)) {
173                 if (line.empty() || line[0] == '#') {
174                         //LYXERR(Debug::MATHED, "ignoring line '" << line << '\'');
175                         continue;
176                 }
177                 idocstringstream il(from_utf8(line));
178
179                 //LYXERR(Debug::MATHED, "line '" << line << '\'');
180                 Correction corr;
181                 if (corr.read(il)) {
182                         //LYXERR(Debug::MATHED, "parsed: '" << corr << '\'');
183                         theCorrections.insert(corr);
184                 }
185         }
186
187         LYXERR(Debug::MATHED, "done reading autocorrections.");
188 }
189
190
191 } // namespace
192
193
194 bool math_autocorrect(Cursor & cur, char_type c)
195 {
196         static bool initialized = false;
197
198         if (!initialized) {
199                 initAutoCorrect();
200                 initialized = true;
201         }
202
203         return theCorrections.correct(cur, c);
204 }
205 } // namespace lyx