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