]> git.lyx.org Git - lyx.git/blob - src/Session.cpp
Constify and un-constify
[lyx.git] / src / Session.cpp
1 /**
2  * \file Session.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Bo Peng
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "Session.h"
15
16 #include "support/debug.h"
17 #include "support/filetools.h"
18 #include "support/Package.h"
19
20 #include <fstream>
21 #include <sstream>
22 #include <algorithm>
23 #include <iterator>
24
25 using namespace std;
26 using namespace lyx::support;
27
28 namespace {
29
30 string const sec_lastfiles = "[recent files]";
31 string const sec_lastfilepos = "[cursor positions]";
32 string const sec_lastopened = "[last opened files]";
33 string const sec_bookmarks = "[bookmarks]";
34 string const sec_session = "[session info]";
35 string const sec_toolbars = "[toolbars]";
36 string const sec_lastcommands = "[last commands]";
37 string const sec_authfiles = "[auth files]";
38 string const sec_shellescape = "[shell escape files]";
39
40 } // namespace
41
42
43 namespace lyx {
44
45 LastFilesSection::LastFilesSection(unsigned int num) :
46         default_num_last_files(4),
47         absolute_max_last_files(100)
48 {
49         setNumberOfLastFiles(num);
50 }
51
52
53 void LastFilesSection::read(istream & is)
54 {
55         string tmp;
56         do {
57                 char c = is.peek();
58                 if (c == '[')
59                         break;
60                 getline(is, tmp);
61                 if (tmp.empty() || tmp[0] == '#' || tmp[0] == ' ' || !FileName::isAbsolute(tmp))
62                         continue;
63
64                 // read lastfiles
65                 FileName const file(tmp);
66                 if (file.exists() && !file.isDirectory()
67                     && lastfiles.size() < num_lastfiles)
68                         lastfiles.push_back(file);
69                 else
70                         LYXERR(Debug::INIT, "LyX: Warning: Ignore last file: " << tmp);
71         } while (is.good());
72 }
73
74
75 void LastFilesSection::write(ostream & os) const
76 {
77         os << '\n' << sec_lastfiles << '\n';
78         copy(lastfiles.begin(), lastfiles.end(),
79              ostream_iterator<FileName>(os, "\n"));
80 }
81
82
83 void LastFilesSection::add(FileName const & file)
84 {
85         // If file already exist, delete it and reinsert at front.
86         LastFiles::iterator it = find(lastfiles.begin(), lastfiles.end(), file);
87         if (it != lastfiles.end())
88                 lastfiles.erase(it);
89         lastfiles.insert(lastfiles.begin(), file);
90         if (lastfiles.size() > num_lastfiles)
91                 lastfiles.pop_back();
92 }
93
94
95 void LastFilesSection::setNumberOfLastFiles(unsigned int no)
96 {
97         if (0 < no && no <= absolute_max_last_files)
98                 num_lastfiles = no;
99         else {
100                 LYXERR(Debug::INIT, "LyX: session: too many last files\n"
101                         << "\tdefault (=" << default_num_last_files << ") used.");
102                 num_lastfiles = default_num_last_files;
103         }
104 }
105
106
107 void LastOpenedSection::read(istream & is)
108 {
109         string tmp;
110         do {
111                 char c = is.peek();
112                 if (c == '[')
113                         break;
114                 getline(is, tmp);
115                 if (tmp.empty() || tmp[0] == '#' || tmp[0] == ' ')
116                         continue;
117
118                 try {
119                         LastOpenedFile lof;
120                         istringstream itmp(tmp);
121                         itmp >> lof.active;
122                         itmp.ignore(2);  // ignore ", "
123                         string fname;
124                         getline(itmp, fname);
125                         if (!FileName::isAbsolute(fname))
126                                 continue;
127
128                         FileName const file(fname);
129                         if (file.exists() && !file.isDirectory()) {
130                                 lof.file_name = file;
131                                 lastopened.push_back(lof);
132                         } else {
133                                 LYXERR(Debug::INIT,
134                                         "LyX: Warning: Ignore last opened file: " << tmp);
135                         }
136                 } catch (...) {
137                         LYXERR(Debug::INIT,
138                                 "LyX: Warning: unknown state of last opened file: " << tmp);
139                 }
140         } while (is.good());
141 }
142
143
144 void LastOpenedSection::write(ostream & os) const
145 {
146         os << '\n' << sec_lastopened << '\n';
147         for (size_t i = 0; i < lastopened.size(); ++i)
148                 os << lastopened[i].active << ", " << lastopened[i].file_name << '\n';
149 }
150
151
152 void LastOpenedSection::add(FileName const & file, bool active)
153 {
154         LastOpenedFile lof(file, active);
155         // check if file is already recorded (this can happen
156         // with multiple buffer views). We do only record each
157         // file once, since we cannot restore multiple views
158         // currently, we even crash in some cases (see #9483).
159         // FIXME: Add session support for multiple views of
160         //        the same buffer (split-view etc.).
161         for (size_t i = 0; i < lastopened.size(); ++i) {
162                 if (lastopened[i].file_name == file)
163                         return;
164         }
165         lastopened.push_back(lof);
166 }
167
168
169 void LastOpenedSection::clear()
170 {
171         lastopened.clear();
172 }
173
174
175 void LastFilePosSection::read(istream & is)
176 {
177         string tmp;
178         do {
179                 char c = is.peek();
180                 if (c == '[')
181                         break;
182                 getline(is, tmp);
183                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
184                         continue;
185
186                 try {
187                         // read lastfilepos
188                         // pos, file\n
189                         FilePos filepos;
190                         string fname;
191                         istringstream itmp(tmp);
192                         itmp >> filepos.pit;
193                         itmp.ignore(2);  // ignore ", "
194                         itmp >> filepos.pos;
195                         itmp.ignore(2);  // ignore ", "
196                         getline(itmp, fname);
197                         if (!FileName::isAbsolute(fname))
198                                 continue;
199                         filepos.file = FileName(fname);
200                         if (filepos.file.exists() && !filepos.file.isDirectory()
201                             && lastfilepos.size() < num_lastfilepos)
202                                 lastfilepos.push_back(filepos);
203                         else
204                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore pos of last file: " << fname);
205                 } catch (...) {
206                         LYXERR(Debug::INIT, "LyX: Warning: unknown pos of last file: " << tmp);
207                 }
208         } while (is.good());
209 }
210
211
212 void LastFilePosSection::write(ostream & os) const
213 {
214         os << '\n' << sec_lastfilepos << '\n';
215         for (auto const & file_p : lastfilepos)
216                 os << file_p.pit << ", " << file_p.pos << ", " << file_p.file << '\n';
217 }
218
219
220 void LastFilePosSection::save(FilePos const & pos)
221 {
222         // Remove element if it was already present. Iterating should
223         // not be a problem since the list is small (<100 elements).
224         for (FilePosList::iterator it = lastfilepos.begin();
225              it != lastfilepos.end(); ++it)
226                 if (it->file == pos.file) {
227                         lastfilepos.erase(it);
228                         break;
229                 }
230
231         // insert new element at front.
232         lastfilepos.push_front(pos);
233 }
234
235
236 LastFilePosSection::FilePos LastFilePosSection::load(FileName const & fname) const
237 {
238         for (auto const & fp : lastfilepos)
239                 if (fp.file == fname)
240                         // Has position information, return it.
241                         return fp;
242
243         // Not found, return the first paragraph
244         return FilePos();
245 }
246
247
248 void BookmarksSection::clear()
249 {
250         // keep bookmark[0], the temporary one
251         bookmarks.resize(1);
252         bookmarks.resize(max_bookmarks + 1);
253 }
254
255
256 void BookmarksSection::read(istream & is)
257 {
258         string tmp;
259         do {
260                 char c = is.peek();
261                 if (c == '[')
262                         break;
263                 getline(is, tmp);
264                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
265                         continue;
266
267                 try {
268                         // read bookmarks
269                         // idx, pit, pos, file\n
270                         unsigned int idx;
271                         pit_type pit;
272                         pos_type pos;
273                         string fname;
274                         istringstream itmp(tmp);
275                         itmp >> idx;
276                         itmp.ignore(2);  // ignore ", "
277                         itmp >> pit;
278                         itmp.ignore(2);  // ignore ", "
279                         itmp >> pos;
280                         itmp.ignore(2);  // ignore ", "
281                         getline(itmp, fname);
282                         if (!FileName::isAbsolute(fname))
283                                 continue;
284                         FileName const file(fname);
285                         // only load valid bookmarks
286                         if (file.exists() && !file.isDirectory() && idx <= max_bookmarks)
287                                 bookmarks[idx] = Bookmark(file, pit, pos, 0, 0);
288                         else
289                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore bookmark of file: " << fname);
290                 } catch (...) {
291                         LYXERR(Debug::INIT, "LyX: Warning: unknown Bookmark info: " << tmp);
292                 }
293         } while (is.good());
294 }
295
296
297 void BookmarksSection::write(ostream & os) const
298 {
299         os << '\n' << sec_bookmarks << '\n';
300         for (size_t i = 0; i <= max_bookmarks; ++i) {
301                 if (isValid(i))
302                         os << i << ", "
303                            << bookmarks[i].bottom_pit << ", "
304                            << bookmarks[i].bottom_pos << ", "
305                            << bookmarks[i].filename << '\n';
306         }
307 }
308
309
310 void BookmarksSection::save(FileName const & fname,
311         pit_type bottom_pit, pos_type bottom_pos,
312         int top_id, pos_type top_pos, unsigned int idx)
313 {
314         // silently ignore bookmarks when idx is out of range
315         if (idx <= max_bookmarks)
316                 bookmarks[idx] = Bookmark(fname, bottom_pit, bottom_pos, top_id, top_pos);
317 }
318
319
320 bool BookmarksSection::isValid(unsigned int i) const
321 {
322         return i <= max_bookmarks && !bookmarks[i].filename.empty();
323 }
324
325
326 bool BookmarksSection::hasValid() const
327 {
328         for (size_t i = 1; i <= size(); ++i) {
329                 if (isValid(i))
330                         return true;
331         }
332         return false;
333 }
334
335
336 BookmarksSection::Bookmark const & BookmarksSection::bookmark(unsigned int i) const
337 {
338         return bookmarks[i];
339 }
340
341
342 LastCommandsSection::LastCommandsSection(unsigned int num) :
343         default_num_last_commands(30),
344         absolute_max_last_commands(100)
345 {
346         setNumberOfLastCommands(num);
347 }
348
349
350 void LastCommandsSection::read(istream & is)
351 {
352         string tmp;
353         do {
354                 char c = is.peek();
355                 if (c == '[')
356                         break;
357                 getline(is, tmp);
358                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
359                         continue;
360
361                 lastcommands.push_back(tmp);
362         } while (is.good());
363 }
364
365
366 void LastCommandsSection::write(ostream & os) const
367 {
368         os << '\n' << sec_lastcommands << '\n';
369         copy(lastcommands.begin(), lastcommands.end(),
370                 ostream_iterator<std::string>(os, "\n"));
371 }
372
373
374 void LastCommandsSection::setNumberOfLastCommands(unsigned int no)
375 {
376         if (0 < no && no <= absolute_max_last_commands)
377                 num_lastcommands = no;
378         else {
379                 LYXERR(Debug::INIT, "LyX: session: too many last commands\n"
380                         << "\tdefault (=" << default_num_last_commands << ") used.");
381                 num_lastcommands = default_num_last_commands;
382         }
383 }
384
385
386 void LastCommandsSection::add(std::string const & string)
387 {
388         lastcommands.push_back(string);
389 }
390
391
392 void LastCommandsSection::clear()
393 {
394         lastcommands.clear();
395 }
396
397
398 Session::Session(unsigned int num_last_files, unsigned int num_last_commands) :
399         last_files(num_last_files), last_commands(num_last_commands)
400 {
401         // locate the session file
402         // note that the session file name 'session' is hard-coded
403         session_file = FileName(addName(package().user_support().absFileName(), "session"));
404         //
405         readFile();
406 }
407
408
409 void Session::readFile()
410 {
411         // we will not complain if we can't find session_file nor will
412         // we issue a warning. (Lgb)
413         ifstream is(session_file.toFilesystemEncoding().c_str());
414         string tmp;
415
416         while (getline(is, tmp)) {
417                 // Ignore comments, empty line or line stats with ' '
418                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
419                         continue;
420
421                 // Determine section id
422                 if (tmp == sec_lastfiles)
423                         lastFiles().read(is);
424                 else if (tmp == sec_lastopened)
425                         lastOpened().read(is);
426                 else if (tmp == sec_lastfilepos)
427                         lastFilePos().read(is);
428                 else if (tmp == sec_bookmarks)
429                         bookmarks().read(is);
430                 else if (tmp == sec_lastcommands)
431                         lastCommands().read(is);
432                 else if (tmp == sec_authfiles)
433                         authFiles().read(is);
434                 else if (tmp == sec_shellescape)
435                         shellescapeFiles().read(is);
436
437                 else
438                         LYXERR(Debug::INIT, "LyX: Warning: unknown Session section: " << tmp);
439         }
440 }
441
442
443 void Session::writeFile() const
444 {
445         ofstream os(session_file.toFilesystemEncoding().c_str());
446         if (os) {
447                 os << "## Automatically generated lyx session file \n"
448                     << "## Editing this file manually may cause lyx to crash.\n";
449
450                 lastFiles().write(os);
451                 lastOpened().write(os);
452                 lastFilePos().write(os);
453                 lastCommands().write(os);
454                 bookmarks().write(os);
455                 authFiles().write(os);
456                 shellescapeFiles().write(os);
457         } else
458                 LYXERR(Debug::INIT, "LyX: Warning: unable to save Session: "
459                        << session_file);
460 }
461
462
463 AuthFilesSection::AuthFilesSection() {  }
464
465
466 void AuthFilesSection::read(istream & is)
467 {
468         string tmp;
469         do {
470                 char c = is.peek();
471                 if (c == '[')
472                         break;
473                 getline(is, tmp);
474                 if (tmp.empty() || tmp[0] == '#' || tmp[0] == ' ' || !FileName::isAbsolute(tmp))
475                         continue;
476
477                 // read lastfiles
478                 FileName const file(tmp);
479                 if (file.exists() && !file.isDirectory())
480                         auth_files_.insert(tmp);
481                 else
482                         LYXERR(Debug::INIT, "LyX: Warning: Ignore auth file: " << tmp);
483         } while (is.good());
484 }
485
486
487 void AuthFilesSection::write(ostream & os) const
488 {
489         os << '\n' << sec_authfiles << '\n';
490         copy(auth_files_.begin(), auth_files_.end(),
491              ostream_iterator<std::string>(os, "\n"));
492 }
493
494
495 bool AuthFilesSection::find(string const & name) const
496 {
497         if (auth_files_.find(name) != auth_files_.end())
498                 return true;
499
500         return false;
501 }
502
503
504 void AuthFilesSection::insert(string const & name)
505 {
506         auth_files_.insert(name);
507 }
508
509
510 void ShellEscapeSection::read(istream & is)
511 {
512         string s;
513         do {
514                 char c = is.peek();
515                 if (c == '[')
516                         break;
517                 getline(is, s);
518                 if (s.empty() || s[0] == '#' || s[0] == ' ' || !FileName::isAbsolute(s))
519                         continue;
520
521                 // read shellescape files
522                 FileName const file(s.substr(0, s.length() - 2));
523                 if (file.exists() && !file.isDirectory())
524                         shellescape_files_.insert(s);
525                 else
526                         LYXERR(Debug::INIT, "LyX: Warning: Ignore shellescape file: " << file);
527         } while (is.good());
528 }
529
530
531 void ShellEscapeSection::write(ostream & os) const
532 {
533         os << '\n' << sec_shellescape << '\n';
534         copy(shellescape_files_.begin(), shellescape_files_.end(),
535              ostream_iterator<std::string>(os, "\n"));
536 }
537
538
539 bool ShellEscapeSection::find(string const & name) const
540 {
541         if (shellescape_files_.find(name + ",0") != shellescape_files_.end())
542                 return true;
543
544         return findAuth(name);
545 }
546
547
548 bool ShellEscapeSection::findAuth(string const & name) const
549 {
550         if (shellescape_files_.find(name + ",1") != shellescape_files_.end())
551                 return true;
552
553         return false;
554 }
555
556
557 void ShellEscapeSection::insert(string const & name, bool auth)
558 {
559         set<string>::iterator it;
560         string const name0 = name + ",0";
561         string const name1 = name + ",1";
562
563         if (auth) {
564                 it = shellescape_files_.find(name0);
565                 if (it != shellescape_files_.end())
566                         shellescape_files_.erase(it);
567                 shellescape_files_.insert(name1);
568         } else {
569                 it = shellescape_files_.find(name1);
570                 if (it != shellescape_files_.end())
571                         shellescape_files_.erase(it);
572                 shellescape_files_.insert(name0);
573         }
574 }
575
576
577 void ShellEscapeSection::remove(string const & name)
578 {
579         set<string>::iterator it = shellescape_files_.find(name + ",0");
580         if (it == shellescape_files_.end())
581                 it = shellescape_files_.find(name + ",1");
582         if (it != shellescape_files_.end())
583                 shellescape_files_.erase(it);
584 }
585
586
587 } // namespace lyx