]> git.lyx.org Git - lyx.git/blob - src/LyX.cpp
Fix InsetListings::getCaption() for std::regex
[lyx.git] / src / LyX.cpp
1 /**
2  * \file LyX.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16 #include <version.h>
17
18 #include "LyX.h"
19
20 #include "AppleSpellChecker.h"
21 #include "AspellChecker.h"
22 #include "Buffer.h"
23 #include "BufferList.h"
24 #include "CmdDef.h"
25 #include "ColorSet.h"
26 #include "ConverterCache.h"
27 #include "Converter.h"
28 #include "CutAndPaste.h"
29 #include "EnchantChecker.h"
30 #include "Encoding.h"
31 #include "ErrorList.h"
32 #include "Format.h"
33 #include "FuncStatus.h"
34 #include "HunspellChecker.h"
35 #include "KeyMap.h"
36 #include "Language.h"
37 #include "LaTeXFonts.h"
38 #include "LayoutFile.h"
39 #include "Lexer.h"
40 #include "LyX.h"
41 #include "LyXAction.h"
42 #include "LyXRC.h"
43 #include "ModuleList.h"
44 #include "Mover.h"
45 #include "Server.h"
46 #include "ServerSocket.h"
47 #include "Session.h"
48 #include "WordList.h"
49
50 #include "frontends/alert.h"
51 #include "frontends/Application.h"
52
53 #include "support/ConsoleApplication.h"
54 #include "support/lassert.h"
55 #include "support/debug.h"
56 #include "support/environment.h"
57 #include "support/ExceptionMessage.h"
58 #include "support/filetools.h"
59 #include "support/gettext.h"
60 #include "support/lstrings.h"
61 #include "support/Messages.h"
62 #include "support/os.h"
63 #include "support/Package.h"
64
65 #include "support/bind.h"
66 #include <boost/scoped_ptr.hpp>
67
68 #include <algorithm>
69 #include <iostream>
70 #include <csignal>
71 #include <map>
72 #include <stdlib.h>
73 #include <string>
74 #include <vector>
75
76 using namespace std;
77 using namespace lyx::support;
78
79 #if defined (USE_MACOSX_PACKAGING)
80 #include <crt_externs.h>
81 #endif
82
83 namespace lyx {
84
85 namespace Alert = frontend::Alert;
86 namespace os = support::os;
87
88
89
90 // Are we using the GUI at all?  We default to true and this is changed
91 // to false when the export feature is used.
92
93 bool use_gui = true;
94
95
96 // We default to open documents in an already running instance, provided that
97 // the lyxpipe has been setup. This can be overridden either on the command
98 // line or through preference settings.
99
100 RunMode run_mode = PREFERRED;
101
102
103 // Tell what files can be silently overwritten during batch export.
104 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
105 // Unless specified on command line (through the -f switch) or through the
106 // environment variable LYX_FORCE_OVERWRITE, the default will be MAIN_FILE.
107
108 OverwriteFiles force_overwrite = UNSPECIFIED;
109
110
111 namespace {
112
113 // Filled with the command line arguments "foo" of "-sysdir foo" or
114 // "-userdir foo".
115 string cl_system_support;
116 string cl_user_support;
117
118 string geometryArg;
119
120 LyX * singleton_ = 0;
121
122 void showFileError(string const & error)
123 {
124         Alert::warning(_("Could not read configuration file"),
125                        bformat(_("Error while reading the configuration file\n%1$s.\n"
126                            "Please check your installation."), from_utf8(error)));
127 }
128
129 } // namespace anon
130
131 /// The main application class private implementation.
132 struct LyX::Impl {
133         Impl()
134                 : latexfonts_(0), spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
135         {}
136
137         ~Impl()
138         {
139                 delete latexfonts_;
140                 delete apple_spell_checker_;
141                 delete aspell_checker_;
142                 delete enchant_checker_;
143                 delete hunspell_checker_;
144         }
145
146         ///
147         BufferList buffer_list_;
148         ///
149         KeyMap toplevel_keymap_;
150         ///
151         CmdDef toplevel_cmddef_;
152         ///
153         boost::scoped_ptr<Server> lyx_server_;
154         ///
155         boost::scoped_ptr<ServerSocket> lyx_socket_;
156         ///
157         boost::scoped_ptr<frontend::Application> application_;
158         /// lyx session, containing lastfiles, lastfilepos, and lastopened
159         boost::scoped_ptr<Session> session_;
160
161         /// Files to load at start.
162         vector<string> files_to_load_;
163
164         /// The messages translators.
165         map<string, Messages> messages_;
166
167         /// The file converters.
168         Converters converters_;
169
170         // The system converters copy after reading lyxrc.defaults.
171         Converters system_converters_;
172
173         ///
174         Movers movers_;
175         ///
176         Movers system_movers_;
177
178         /// the parsed command line batch command if any
179         vector<string> batch_commands;
180
181         ///
182         LaTeXFonts * latexfonts_;
183
184         ///
185         SpellChecker * spell_checker_;
186         ///
187         SpellChecker * apple_spell_checker_;
188         ///
189         SpellChecker * aspell_checker_;
190         ///
191         SpellChecker * enchant_checker_;
192         ///
193         SpellChecker * hunspell_checker_;
194 };
195
196
197 /// The main application class for console mode
198 class LyXConsoleApp : public ConsoleApplication
199 {
200 public:
201         LyXConsoleApp(LyX * lyx, int & argc, char * argv[])
202                 : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx),
203                   argc_(argc), argv_(argv)
204         {
205         }
206         void doExec()
207         {
208                 int const exit_status = lyx_->execWithoutGui(argc_, argv_);
209                 exit(exit_status);
210         }
211 private:
212         LyX * lyx_;
213         int & argc_;
214         char ** argv_;
215 };
216
217
218 ///
219 frontend::Application * theApp()
220 {
221         if (singleton_)
222                 return singleton_->pimpl_->application_.get();
223         else
224                 return 0;
225 }
226
227
228 LyX::~LyX()
229 {
230         delete pimpl_;
231         singleton_ = 0;
232         WordList::cleanupWordLists();
233 }
234
235
236 void lyx_exit(int exit_code)
237 {
238         if (exit_code)
239                 // Something wrong happened so better save everything, just in
240                 // case.
241                 emergencyCleanup();
242
243 #ifndef NDEBUG
244         // Properly crash in debug mode in order to get a useful backtrace.
245         abort();
246 #endif
247
248         // In release mode, try to exit gracefully.
249         if (theApp())
250                 theApp()->exit(exit_code);
251         else
252                 exit(exit_code);
253 }
254
255
256 LyX::LyX()
257         : first_start(false)
258 {
259         singleton_ = this;
260         pimpl_ = new Impl;
261 }
262
263
264 Messages & LyX::messages(string const & language)
265 {
266         map<string, Messages>::iterator it = pimpl_->messages_.find(language);
267
268         if (it != pimpl_->messages_.end())
269                 return it->second;
270
271         pair<map<string, Messages>::iterator, bool> result =
272                         pimpl_->messages_.insert(make_pair(language, Messages(language)));
273
274         LATTEST(result.second);
275         return result.first->second;
276 }
277
278
279 int LyX::exec(int & argc, char * argv[])
280 {
281         // Minimal setting of locale before parsing command line
282         try {
283                 init_package(os::utf8_argv(0), string(), string());
284                 // we do not get to this point when init_package throws an exception
285                 setLocale();
286         } catch (ExceptionMessage const & message) {
287                 LYXERR(Debug::LOCALE, message.title_ + ", " + message.details_);
288         }
289
290         // Here we need to parse the command line. At least
291         // we need to parse for "-dbg" and "-help"
292         easyParse(argc, argv);
293
294         try {
295                 init_package(os::utf8_argv(0), cl_system_support, cl_user_support);
296         } catch (ExceptionMessage const & message) {
297                 if (message.type_ == ErrorException) {
298                         Alert::error(message.title_, message.details_);
299                         lyx_exit(1);
300                 } else if (message.type_ == WarningException) {
301                         Alert::warning(message.title_, message.details_);
302                 }
303         }
304
305         // Reinit the messages machinery in case package() knows
306         // something interesting about the locale directory.
307         setLocale();
308
309         if (!use_gui) {
310                 LyXConsoleApp app(this, argc, argv);
311
312                 // Reestablish our defaults, as Qt overwrites them
313                 // after creating app
314                 setLocale();//???
315
316                 return app.exec();
317         }
318
319         // Let the frontend parse and remove all arguments that it knows
320         pimpl_->application_.reset(createApplication(argc, argv));
321
322         // Reestablish our defaults, as Qt overwrites them
323         // after createApplication()
324         setLocale();//???
325
326         // Parse and remove all known arguments in the LyX singleton
327         // Give an error for all remaining ones.
328         int exit_status = init(argc, argv);
329         if (exit_status) {
330                 // Kill the application object before exiting.
331                 pimpl_->application_.reset();
332                 use_gui = false;
333                 prepareExit();
334                 return exit_status;
335         }
336
337         // If not otherwise specified by a command line option or
338         // by preferences, we default to reuse a running instance.
339         if (run_mode == PREFERRED)
340                 run_mode = USE_REMOTE;
341
342         // FIXME
343         /* Create a CoreApplication class that will provide the main event loop
344         * and the socket callback registering. With Qt, only QtCore
345         * library would be needed.
346         * When this is done, a server_mode could be created and the following two
347         * line would be moved out from here.
348         * However, note that the first of the two lines below triggers the
349         * "single instance" behavior, which should occur right at this point.
350         */
351         // Note: socket callback must be registered after init(argc, argv)
352         // such that package().temp_dir() is properly initialized.
353         pimpl_->lyx_server_.reset(new Server(lyxrc.lyxpipes));
354         pimpl_->lyx_socket_.reset(new ServerSocket(
355                         FileName(package().temp_dir().absFileName() + "/lyxsocket")));
356
357         // Start the real execution loop.
358         if (!theServer().deferredLoadingToOtherInstance())
359                 exit_status = pimpl_->application_->exec();
360         else if (!pimpl_->files_to_load_.empty()) {
361                 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
362                 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
363                 lyxerr << _("The following files could not be loaded:") << endl;
364                 for (; it != end; ++it)
365                         lyxerr << *it << endl;
366         }
367
368         prepareExit();
369
370         return exit_status;
371 }
372
373
374 void LyX::prepareExit()
375 {
376         // Clear the clipboard and selection stack:
377         cap::clearCutStack();
378         cap::clearSelection();
379
380         // Write the index file of the converter cache
381         ConverterCache::get().writeIndex();
382
383         // close buffers first
384         pimpl_->buffer_list_.closeAll();
385
386         // register session changes and shutdown server and socket
387         if (use_gui) {
388                 if (pimpl_->session_)
389                         pimpl_->session_->writeFile();
390                 pimpl_->session_.reset();
391                 pimpl_->lyx_server_.reset();
392                 pimpl_->lyx_socket_.reset();
393         }
394
395         // do any other cleanup procedures now
396         if (package().temp_dir() != package().system_temp_dir()) {
397                 string const abs_tmpdir = package().temp_dir().absFileName();
398                 if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) {
399                         docstring const msg =
400                                 bformat(_("%1$s does not appear like a LyX created temporary directory."),
401                                 from_utf8(abs_tmpdir));
402                         Alert::warning(_("Cannot remove temporary directory"), msg);
403                 } else {
404                         LYXERR(Debug::INFO, "Deleting tmp dir "
405                                 << package().temp_dir().absFileName());
406                         if (!package().temp_dir().destroyDirectory()) {
407                                 LYXERR0(bformat(_("Unable to remove the temporary directory %1$s"),
408                                         from_utf8(package().temp_dir().absFileName())));
409                         }
410                 }
411         }
412
413         // Kill the application object before exiting. This avoids crashes
414         // when exiting on Linux.
415         pimpl_->application_.reset();
416 }
417
418
419 void LyX::earlyExit(int status)
420 {
421         LATTEST(pimpl_->application_.get());
422         // LyX::pimpl_::application_ is not initialised at this
423         // point so it's safe to just exit after some cleanup.
424         prepareExit();
425         exit(status);
426 }
427
428
429 int LyX::init(int & argc, char * argv[])
430 {
431         // check for any spurious extra arguments
432         // other than documents
433         for (int argi = 1; argi < argc ; ++argi) {
434                 if (argv[argi][0] == '-') {
435                         lyxerr << to_utf8(
436                                 bformat(_("Wrong command line option `%1$s'. Exiting."),
437                                 from_utf8(os::utf8_argv(argi)))) << endl;
438                         return EXIT_FAILURE;
439                 }
440         }
441
442         // Initialization of LyX (reads lyxrc and more)
443         LYXERR(Debug::INIT, "Initializing LyX::init...");
444         bool success = init();
445         LYXERR(Debug::INIT, "Initializing LyX::init...done");
446         if (!success)
447                 return EXIT_FAILURE;
448
449         // Remaining arguments are assumed to be files to load.
450         for (int argi = 1; argi < argc; ++argi)
451                 pimpl_->files_to_load_.push_back(os::utf8_argv(argi));
452
453         if (!use_gui && pimpl_->files_to_load_.empty()) {
454                 lyxerr << to_utf8(_("Missing filename for this operation.")) << endl;
455                 return EXIT_FAILURE;
456         }
457
458         if (first_start) {
459                 pimpl_->files_to_load_.push_back(
460                         i18nLibFileSearch("examples", "splash.lyx").absFileName());
461         }
462
463         return EXIT_SUCCESS;
464 }
465
466
467 int LyX::execWithoutGui(int & argc, char * argv[])
468 {
469         int exit_status = init(argc, argv);
470         if (exit_status) {
471                 prepareExit();
472                 return exit_status;
473         }
474
475         // this is correct, since return values are inverted.
476         exit_status = !loadFiles();
477
478         if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
479                 prepareExit();
480                 return exit_status;
481         }
482
483         BufferList::iterator begin = pimpl_->buffer_list_.begin();
484
485         bool final_success = false;
486         for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
487                 Buffer * buf = *I;
488                 if (buf != buf->masterBuffer())
489                         continue;
490                 vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
491                 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
492                 DispatchResult dr;
493                 for (; bcit != bcend; ++bcit) {
494                         LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
495                         buf->dispatch(*bcit, dr);
496                         final_success |= !dr.error();
497                 }
498         }
499         prepareExit();
500         return !final_success;
501 }
502
503
504 bool LyX::loadFiles()
505 {
506         LATTEST(!use_gui);
507         bool success = true;
508         vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
509         vector<string>::const_iterator end = pimpl_->files_to_load_.end();
510
511         for (; it != end; ++it) {
512                 // get absolute path of file and add ".lyx" to
513                 // the filename if necessary
514                 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
515                         may_not_exist);
516
517                 if (fname.empty())
518                         continue;
519
520                 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName());
521                 if (buf->loadLyXFile() == Buffer::ReadSuccess) {
522                         ErrorList const & el = buf->errorList("Parse");
523                         if (!el.empty())
524                                 for_each(el.begin(), el.end(),
525                                 bind(&LyX::printError, this, _1));
526                 }
527                 else {
528                         pimpl_->buffer_list_.release(buf);
529                         docstring const error_message =
530                                 bformat(_("LyX failed to load the following file: %1$s"),
531                                 from_utf8(fname.absFileName()));
532                         lyxerr << to_utf8(error_message) << endl;
533                         success = false;
534                 }
535         }
536         return success;
537 }
538
539
540 void execBatchCommands()
541 {
542         LAPPERR(singleton_);
543         singleton_->execCommands();
544 }
545
546
547 void LyX::execCommands()
548 {
549         // The advantage of doing this here is that the event loop
550         // is already started. So any need for interaction will be
551         // aknowledged.
552
553         // if reconfiguration is needed.
554         if (LayoutFileList::get().empty()) {
555                 switch (Alert::prompt(
556                         _("No textclass is found"),
557                         _("LyX will only have minimal functionality because no textclasses "
558                                 "have been found. You can either try to reconfigure LyX normally, "
559                                 "try to reconfigure without checking your LaTeX installation, or continue."),
560                         0, 2,
561                         _("&Reconfigure"),
562                         _("&Without LaTeX"),
563                         _("&Continue")))
564                 {
565                 case 0:
566                         // regular reconfigure
567                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
568                         break;
569                 case 1:
570                         // reconfigure --without-latex-config
571                         lyx::dispatch(FuncRequest(LFUN_RECONFIGURE,
572                                 " --without-latex-config"));
573                         break;
574                 default:
575                         break;
576                 }
577         }
578
579         // create the first main window
580         lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
581
582         if (!pimpl_->files_to_load_.empty()) {
583                 // if some files were specified at command-line we assume that the
584                 // user wants to edit *these* files and not to restore the session.
585                 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
586                         lyx::dispatch(
587                                 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
588                 }
589                 // clear this list to save a few bytes of RAM
590                 pimpl_->files_to_load_.clear();
591         } else
592                 pimpl_->application_->restoreGuiSession();
593
594         // Execute batch commands if available
595         if (pimpl_->batch_commands.empty())
596                 return;
597
598         vector<string>::const_iterator bcit  = pimpl_->batch_commands.begin();
599         vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
600         for (; bcit != bcend; ++bcit) {
601                 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
602                 lyx::dispatch(lyxaction.lookupFunc(*bcit));
603         }
604 }
605
606
607 /*
608 Signals and Windows
609 ===================
610 The SIGHUP signal does not exist on Windows and does not need to be handled.
611
612 Windows handles SIGFPE and SIGSEGV signals as expected.
613
614 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
615 cause a new thread to be spawned. This may well result in unexpected
616 behaviour by the single-threaded LyX.
617
618 SIGTERM signals will come only from another process actually sending
619 that signal using 'raise' in Windows' POSIX compatability layer. It will
620 not come from the general "terminate process" methods that everyone
621 actually uses (and which can't be trapped). Killing an app 'politely' on
622 Windows involves first sending a WM_CLOSE message, something that is
623 caught already by the Qt frontend.
624
625 For more information see:
626
627 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
628 ...signals are mostly useless on Windows for a variety of reasons that are
629 Windows specific...
630
631 'UNIX Application Migration Guide, Chapter 9'
632 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
633
634 'How To Terminate an Application "Cleanly" in Win32'
635 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
636 */
637 extern "C" {
638
639 static void error_handler(int err_sig)
640 {
641         // Throw away any signals other than the first one received.
642         static sig_atomic_t handling_error = false;
643         if (handling_error)
644                 return;
645         handling_error = true;
646
647         // We have received a signal indicating a fatal error, so
648         // try and save the data ASAP.
649         emergencyCleanup();
650
651         // These lyxerr calls may or may not work:
652
653         // Signals are asynchronous, so the main program may be in a very
654         // fragile state when a signal is processed and thus while a signal
655         // handler function executes.
656         // In general, therefore, we should avoid performing any
657         // I/O operations or calling most library and system functions from
658         // signal handlers.
659
660         // This shouldn't matter here, however, as we've already invoked
661         // emergencyCleanup.
662         docstring msg;
663         switch (err_sig) {
664 #ifdef SIGHUP
665         case SIGHUP:
666                 msg = _("SIGHUP signal caught!\nBye.");
667                 break;
668 #endif
669         case SIGFPE:
670                 msg = _("SIGFPE signal caught!\nBye.");
671                 break;
672         case SIGSEGV:
673                 msg = _("SIGSEGV signal caught!\n"
674                           "Sorry, you have found a bug in LyX, "
675                           "hope you have not lost any data.\n"
676                           "Please read the bug-reporting instructions "
677                           "in 'Help->Introduction' and send us a bug report, "
678                           "if necessary. Thanks!\nBye.");
679                 break;
680         case SIGINT:
681         case SIGTERM:
682                 // no comments
683                 break;
684         }
685
686         if (!msg.empty()) {
687                 lyxerr << "\nlyx: " << msg << endl;
688                 // try to make a GUI message
689                 Alert::error(_("LyX crashed!"), msg, true);
690         }
691
692         // Deinstall the signal handlers
693 #ifdef SIGHUP
694         signal(SIGHUP, SIG_DFL);
695 #endif
696         signal(SIGINT, SIG_DFL);
697         signal(SIGFPE, SIG_DFL);
698         signal(SIGSEGV, SIG_DFL);
699         signal(SIGTERM, SIG_DFL);
700
701 #ifdef SIGHUP
702         if (err_sig == SIGSEGV ||
703                 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty())) {
704 #else
705         if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty()) {
706 #endif
707 #ifdef _MSC_VER
708                 // with abort() it crashes again.
709                 exit(err_sig);
710 #else
711                 abort();
712 #endif
713         }
714
715         exit(0);
716 }
717
718 }
719
720
721 void LyX::printError(ErrorItem const & ei)
722 {
723         docstring tmp = _("LyX: ") + ei.error + char_type(':')
724                 + ei.description;
725         cerr << to_utf8(tmp) << endl;
726 }
727
728 #if defined (USE_MACOSX_PACKAGING)
729 namespace {
730         // Unexposed--extract an environment variable name from its NAME=VALUE
731         // representation
732         std::string varname(const char* line)
733         {
734                 size_t nameLen = strcspn(line, "=");
735                 if (nameLen == strlen(line)) {
736                         return std::string();
737                 } else {
738                         return std::string(line, nameLen);
739                 }
740         }
741 }
742
743 void cleanDuplicateEnvVars()
744 {
745         std::set<std::string> seen;
746         std::set<std::string> dupes;
747
748         // Create a list of the environment variables that appear more than once
749         for (char **read = *_NSGetEnviron(); *read; read++) {
750                 std::string name = varname(*read);
751                 if (name.size() == 0) {
752                         continue;
753                 }
754                 if (seen.find(name) != seen.end()) {
755                         dupes.insert(name);
756                 } else {
757                         seen.insert(name);
758                 }
759         }
760
761         // Loop over the list of duplicated variables
762         std::set<std::string>::iterator dupe = dupes.begin();
763         std::set<std::string>::iterator const dend = dupes.end();
764         for (; dupe != dend; ++dupe) {
765                 const char *name = (*dupe).c_str();
766                 char *val = getenv(name);
767                 if (val != NULL) {
768                         LYXERR(Debug::INIT, "Duplicate environment variable: " << name);
769                         // unsetenv removes *all* instances of the variable from the environment
770                         unsetenv(name);
771
772                         // replace with the value from getenv (in practice appears to be the
773                         // first value in the list)
774                         setenv(name, val, 0);
775                 }
776         }
777 }
778 #endif
779
780
781 static void initTemplatePath()
782 {
783         FileName const package_template_path =
784                 FileName(addName(package().system_support().absFileName(), "templates"));
785
786         if (lyxrc.template_path.empty()) {
787                 lyxrc.template_path = package_template_path.absFileName();
788         }
789 #if defined (USE_MACOSX_PACKAGING)
790         FileName const user_template_path =
791                 FileName(addName(package().user_support().absFileName(), "templates"));
792
793         if (package_template_path != FileName(lyxrc.template_path) &&
794                 user_template_path != FileName(lyxrc.template_path))
795         {
796                 return;
797         }
798         FileName const user_template_link =
799                 FileName(addName(user_template_path.absFileName(),"SystemTemplates"));
800         if (user_template_link.isSymLink() && !equivalent(user_template_link, package_template_path)) {
801                 user_template_link.removeFile();
802         }
803         if (!user_template_link.exists()) {
804                 if (!package_template_path.link(user_template_link)) {
805                         FileName const user_support = package().user_support();
806                         if (user_support.exists() && user_support.isDirectory()) {
807                                 LYXERR(Debug::INIT, "Cannot create symlink " + user_template_link.absFileName());
808                                 lyxrc.template_path = package_template_path.absFileName();
809                         }
810                         return;
811                 }
812                 LYXERR(Debug::INIT, "Symlink \"" << user_template_link.absFileName() << "\" created.");
813         }
814         lyxrc.template_path = user_template_path.absFileName();
815 #endif
816 }
817
818
819 bool LyX::init()
820 {
821 #ifdef SIGHUP
822         signal(SIGHUP, error_handler);
823 #endif
824         signal(SIGFPE, error_handler);
825         signal(SIGSEGV, error_handler);
826         signal(SIGINT, error_handler);
827         signal(SIGTERM, error_handler);
828         // SIGPIPE can be safely ignored.
829
830 #if defined (USE_MACOSX_PACKAGING)
831         cleanDuplicateEnvVars();
832 #endif
833
834         lyxrc.tempdir_path = package().temp_dir().absFileName();
835         lyxrc.document_path = package().document_dir().absFileName();
836
837         if (lyxrc.example_path.empty()) {
838                 lyxrc.example_path = addPath(package().system_support().absFileName(),
839                                               "examples");
840         }
841         initTemplatePath();
842
843         // init LyXDir environment variable
844         string const lyx_dir = package().lyx_dir().absFileName();
845         LYXERR(Debug::INIT, "Setting LyXDir... to \"" << lyx_dir << "\"");
846         if (!setEnv("LyXDir", lyx_dir))
847                 LYXERR(Debug::INIT, "\t... failed!");
848
849         if (package().explicit_user_support() && getEnv(LYX_USERDIR_VER).empty()) {
850                 // -userdir was given on the command line.
851                 // Make it available to child processes, otherwise tex2lyx
852                 // would not find all layout files, and other converters might
853                 // use it as well.
854                 string const user_dir = package().user_support().absFileName();
855                 LYXERR(Debug::INIT, "Setting " LYX_USERDIR_VER "... to \""
856                                     << user_dir << '"');
857                 if (!setEnv(LYX_USERDIR_VER, user_dir))
858                         LYXERR(Debug::INIT, "\t... failed!");
859         }
860
861         //
862         // Read configuration files
863         //
864
865         // This one may have been distributed along with LyX.
866         if (!readRcFile("lyxrc.dist"))
867                 return false;
868
869         // Set the PATH correctly.
870 #if !defined (USE_POSIX_PACKAGING) && !defined (USE_HAIKU_PACKAGING)
871         // Add the directory containing the LyX executable to the path
872         // so that LyX can find things like tex2lyx.
873         if (package().build_support().empty())
874                 prependEnvPath("PATH", package().binary_dir().absFileName());
875 #endif
876         if (!lyxrc.path_prefix.empty())
877                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
878
879         // Check that user LyX directory is ok.
880         {
881                 string const lock_file = package().getConfigureLockName();
882                 int fd = fileLock(lock_file.c_str());
883
884                 if (queryUserLyXDir(package().explicit_user_support())) {
885                         package().reconfigureUserLyXDir("");
886                         // Now the user directory is present on first start.
887                         initTemplatePath();
888                 }
889                 fileUnlock(fd, lock_file.c_str());
890         }
891
892         if (!use_gui) {
893                 // No need for a splash when there is no GUI
894                 first_start = false;
895                 // Default is to overwrite the main file during export, unless
896                 // the -f switch was specified or LYX_FORCE_OVERWRITE was set
897                 if (force_overwrite == UNSPECIFIED) {
898                         string const what = getEnv("LYX_FORCE_OVERWRITE");
899                         if (what == "all")
900                                 force_overwrite = ALL_FILES;
901                         else if (what == "none")
902                                 force_overwrite = NO_FILES;
903                         else
904                                 force_overwrite = MAIN_FILE;
905                 }
906         }
907
908         // This one is generated in user_support directory by lib/configure.py.
909         if (!readRcFile("lyxrc.defaults"))
910                 return false;
911
912         // Query the OS to know what formats are viewed natively
913         formats.setAutoOpen();
914
915         // Read lyxrc.dist again to be able to override viewer auto-detection.
916         readRcFile("lyxrc.dist");
917
918         system_lyxrc = lyxrc;
919         system_formats = formats;
920         pimpl_->system_converters_ = pimpl_->converters_;
921         pimpl_->system_movers_ = pimpl_->movers_;
922         system_lcolor = lcolor;
923
924         // This one is edited through the preferences dialog.
925         if (!readRcFile("preferences", true))
926                 return false;
927
928         // The language may have been set to someting useful through prefs
929         setLocale();
930
931         if (!readEncodingsFile("encodings", "unicodesymbols"))
932                 return false;
933         if (!readLanguagesFile("languages"))
934                 return false;
935
936         LYXERR(Debug::INIT, "Reading layouts...");
937         // Load the layouts
938         LayoutFileList::get().read();
939         //...and the modules
940         theModuleList.read();
941
942         // read keymap and ui files in batch mode as well
943         // because InsetInfo needs to know these to produce
944         // the correct output
945
946         // Set up command definitions
947         pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
948
949         // FIXME
950         // Set up bindings
951         pimpl_->toplevel_keymap_.read("site");
952         pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
953         // load user bind file user.bind
954         pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
955
956         if (lyxerr.debugging(Debug::LYXRC))
957                 lyxrc.print();
958
959         os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
960         // Prepend path prefix a second time to take the user preferences into a account
961         if (!lyxrc.path_prefix.empty())
962                 prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix));
963
964         FileName const document_path(lyxrc.document_path);
965         if (document_path.exists() && document_path.isDirectory())
966                 package().document_dir() = document_path;
967
968         package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
969         if (package().temp_dir().empty()) {
970                 Alert::error(_("Could not create temporary directory"),
971                              bformat(_("Could not create a temporary directory in\n"
972                                                        "\"%1$s\"\n"
973                                                            "Make sure that this path exists and is writable and try again."),
974                                      from_utf8(lyxrc.tempdir_path)));
975                 // createLyXTmpDir() tries sufficiently hard to create a
976                 // usable temp dir, so the probability to come here is
977                 // close to zero. We therefore don't try to overcome this
978                 // problem with e.g. asking the user for a new path and
979                 // trying again but simply exit.
980                 return false;
981         }
982
983         LYXERR(Debug::INIT, "LyX tmp dir: `"
984                             << package().temp_dir().absFileName() << '\'');
985
986         LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
987         pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
988
989         // This must happen after package initialization and after lyxrc is
990         // read, therefore it can't be done by a static object.
991         ConverterCache::init();
992
993         return true;
994 }
995
996
997 void emergencyCleanup()
998 {
999         // what to do about tmpfiles is non-obvious. we would
1000         // like to delete any we find, but our lyxdir might
1001         // contain documents etc. which might be helpful on
1002         // a crash
1003
1004         singleton_->pimpl_->buffer_list_.emergencyWriteAll();
1005         if (use_gui) {
1006                 if (singleton_->pimpl_->lyx_server_)
1007                         singleton_->pimpl_->lyx_server_->emergencyCleanup();
1008                 singleton_->pimpl_->lyx_server_.reset();
1009                 singleton_->pimpl_->lyx_socket_.reset();
1010         }
1011 }
1012
1013
1014 bool LyX::queryUserLyXDir(bool explicit_userdir)
1015 {
1016         // Does user directory exist?
1017         FileName const sup = package().user_support();
1018         if (sup.exists() && sup.isDirectory()) {
1019                 first_start = false;
1020
1021                 return configFileNeedsUpdate("lyxrc.defaults")
1022                         || configFileNeedsUpdate("lyxmodules.lst")
1023                         || configFileNeedsUpdate("textclass.lst")
1024                         || configFileNeedsUpdate("packages.lst");
1025         }
1026
1027         first_start = !explicit_userdir;
1028
1029         // If the user specified explicitly a directory, ask whether
1030         // to create it. If the user says "no", then exit.
1031         if (explicit_userdir &&
1032             Alert::prompt(
1033                     _("Missing user LyX directory"),
1034                     bformat(_("You have specified a non-existent user "
1035                                            "LyX directory, %1$s.\n"
1036                                            "It is needed to keep your own configuration."),
1037                             from_utf8(package().user_support().absFileName())),
1038                     1, 0,
1039                     _("&Create directory"),
1040                     _("&Exit LyX"))) {
1041                 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
1042                 earlyExit(EXIT_FAILURE);
1043         }
1044
1045         lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
1046                           from_utf8(sup.absFileName()))) << endl;
1047
1048         if (!sup.createDirectory(0755)) {
1049                 // Failed, so let's exit.
1050                 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
1051                        << endl;
1052                 earlyExit(EXIT_FAILURE);
1053         }
1054
1055         return true;
1056 }
1057
1058
1059 bool LyX::readRcFile(string const & name, bool check_format)
1060 {
1061         LYXERR(Debug::INIT, "About to read " << name << "... ");
1062
1063         FileName const lyxrc_path = libFileSearch(string(), name);
1064         if (lyxrc_path.empty()) {
1065                 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
1066                 // FIXME
1067                 // This was the previous logic, but can it be right??
1068                 return true;
1069         }
1070         LYXERR(Debug::INIT, "Found in " << lyxrc_path);
1071         bool const success = lyxrc.read(lyxrc_path, check_format);
1072         if (!success)
1073                 showFileError(name);
1074         return success;
1075 }
1076
1077 // Read the languages file `name'
1078 bool LyX::readLanguagesFile(string const & name)
1079 {
1080         LYXERR(Debug::INIT, "About to read " << name << "...");
1081
1082         FileName const lang_path = libFileSearch(string(), name);
1083         if (lang_path.empty()) {
1084                 showFileError(name);
1085                 return false;
1086         }
1087         languages.read(lang_path);
1088         return true;
1089 }
1090
1091
1092 // Read the encodings file `name'
1093 bool LyX::readEncodingsFile(string const & enc_name,
1094                             string const & symbols_name)
1095 {
1096         LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1097                             << symbols_name << "...");
1098
1099         FileName const symbols_path = libFileSearch(string(), symbols_name);
1100         if (symbols_path.empty()) {
1101                 showFileError(symbols_name);
1102                 return false;
1103         }
1104
1105         FileName const enc_path = libFileSearch(string(), enc_name);
1106         if (enc_path.empty()) {
1107                 showFileError(enc_name);
1108                 return false;
1109         }
1110         encodings.read(enc_path, symbols_path);
1111         return true;
1112 }
1113
1114
1115 namespace {
1116
1117 /// return the the number of arguments consumed
1118 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
1119
1120 int parse_dbg(string const & arg, string const &, string &)
1121 {
1122         if (arg.empty()) {
1123                 cout << to_utf8(_("List of supported debug flags:")) << endl;
1124                 Debug::showTags(cout);
1125                 exit(0);
1126         }
1127         lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1128
1129         lyxerr.setLevel(Debug::value(arg));
1130         Debug::showLevel(lyxerr, lyxerr.level());
1131         return 1;
1132 }
1133
1134
1135 int parse_help(string const &, string const &, string &)
1136 {
1137         cout <<
1138                 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1139                   "Command line switches (case sensitive):\n"
1140                   "\t-help              summarize LyX usage\n"
1141                   "\t-userdir dir       set user directory to dir\n"
1142                   "\t-sysdir dir        set system directory to dir\n"
1143                   "\t-geometry WxH+X+Y  set geometry of the main window\n"
1144                   "\t-dbg feature[,feature]...\n"
1145                   "                  select the features to debug.\n"
1146                   "                  Type `lyx -dbg' to see the list of features\n"
1147                   "\t-x [--execute] command\n"
1148                   "                  where command is a lyx command.\n"
1149                   "\t-e [--export] fmt\n"
1150                   "                  where fmt is the export format of choice. Look in\n"
1151                   "                  Tools->Preferences->File Handling->File Formats->Short Name\n"
1152                   "                  to see which parameter (which differs from the format name\n"
1153                   "                  in the File->Export menu) should be passed.\n"
1154                   "                  Note that the order of -e and -x switches matters.\n"
1155                   "\t-E [--export-to] fmt filename\n"
1156                   "                  where fmt is the export format of choice (see --export),\n"
1157                   "                  and filename is the destination filename.\n"
1158                   "\t-i [--import] fmt file.xxx\n"
1159                   "                  where fmt is the import format of choice\n"
1160                   "                  and file.xxx is the file to be imported.\n"
1161                   "\t-f [--force-overwrite] what\n"
1162                   "                  where what is either `all', `main' or `none',\n"
1163                   "                  specifying whether all files, main file only, or no files,\n"
1164                   "                  respectively, are to be overwritten during a batch export.\n"
1165                   "                  Anything else is equivalent to `all', but is not consumed.\n"
1166                   "\t-n [--no-remote]\n"
1167                   "                  open documents in a new instance\n"
1168                   "\t-r [--remote]\n"
1169                   "                  open documents in an already running instance\n"
1170                   "                  (a working lyxpipe is needed)\n"
1171                   "\t-batch    execute commands without launching GUI and exit.\n"
1172                   "\t-version  summarize version and build info\n"
1173                                "Check the LyX man page for more details.")) << endl;
1174         exit(0);
1175         return 0;
1176 }
1177
1178
1179 int parse_version(string const &, string const &, string &)
1180 {
1181         cout << "LyX " << lyx_version
1182                << " (" << lyx_release_date << ")" << endl;
1183         if (string(lyx_git_commit_hash) != "none")
1184                 cout << to_utf8(_("  Git commit hash "))
1185                      << string(lyx_git_commit_hash).substr(0,8) << endl;
1186         cout << lyx_version_info << endl;
1187         exit(0);
1188         return 0;
1189 }
1190
1191
1192 int parse_sysdir(string const & arg, string const &, string &)
1193 {
1194         if (arg.empty()) {
1195                 Alert::error(_("No system directory"),
1196                         _("Missing directory for -sysdir switch"));
1197                 exit(1);
1198         }
1199         cl_system_support = arg;
1200         return 1;
1201 }
1202
1203
1204 int parse_userdir(string const & arg, string const &, string &)
1205 {
1206         if (arg.empty()) {
1207                 Alert::error(_("No user directory"),
1208                         _("Missing directory for -userdir switch"));
1209                 exit(1);
1210         }
1211         cl_user_support = arg;
1212         return 1;
1213 }
1214
1215
1216 int parse_execute(string const & arg, string const &, string & batch)
1217 {
1218         if (arg.empty()) {
1219                 Alert::error(_("Incomplete command"),
1220                         _("Missing command string after --execute switch"));
1221                 exit(1);
1222         }
1223         batch = arg;
1224         return 1;
1225 }
1226
1227
1228 int parse_export_to(string const & type, string const & output_file, string & batch)
1229 {
1230         if (type.empty()) {
1231                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1232                                          "--export-to switch")) << endl;
1233                 exit(1);
1234         }
1235         if (output_file.empty()) {
1236                 lyxerr << to_utf8(_("Missing destination filename after "
1237                                          "--export-to switch")) << endl;
1238                 exit(1);
1239         }
1240         batch = "buffer-export " + type + " " + output_file;
1241         use_gui = false;
1242         return 2;
1243 }
1244
1245
1246 int parse_export(string const & type, string const &, string & batch)
1247 {
1248         if (type.empty()) {
1249                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1250                                          "--export switch")) << endl;
1251                 exit(1);
1252         }
1253         batch = "buffer-export " + type;
1254         use_gui = false;
1255         return 1;
1256 }
1257
1258
1259 int parse_import(string const & type, string const & file, string & batch)
1260 {
1261         if (type.empty()) {
1262                 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1263                                          "--import switch")) << endl;
1264                 exit(1);
1265         }
1266         if (file.empty()) {
1267                 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1268                 exit(1);
1269         }
1270         batch = "buffer-import " + type + ' ' + file;
1271         return 2;
1272 }
1273
1274
1275 int parse_geometry(string const & arg1, string const &, string &)
1276 {
1277         geometryArg = arg1;
1278         // don't remove "-geometry", it will be pruned out later in the
1279         // frontend if need be.
1280         return -1;
1281 }
1282
1283
1284 int parse_batch(string const &, string const &, string &)
1285 {
1286         use_gui = false;
1287         return 0;
1288 }
1289
1290
1291 int parse_noremote(string const &, string const &, string &)
1292 {
1293         run_mode = NEW_INSTANCE;
1294         return 0;
1295 }
1296
1297
1298 int parse_remote(string const &, string const &, string &)
1299 {
1300         run_mode = USE_REMOTE;
1301         return 0;
1302 }
1303
1304
1305 int parse_force(string const & arg, string const &, string &)
1306 {
1307         if (arg == "all") {
1308                 force_overwrite = ALL_FILES;
1309                 return 1;
1310         } else if (arg == "main") {
1311                 force_overwrite = MAIN_FILE;
1312                 return 1;
1313         } else if (arg == "none") {
1314                 force_overwrite = NO_FILES;
1315                 return 1;
1316         }
1317         force_overwrite = ALL_FILES;
1318         return 0;
1319 }
1320
1321
1322 } // namespace anon
1323
1324
1325 void LyX::easyParse(int & argc, char * argv[])
1326 {
1327         map<string, cmd_helper> cmdmap;
1328
1329         cmdmap["-dbg"] = parse_dbg;
1330         cmdmap["-help"] = parse_help;
1331         cmdmap["--help"] = parse_help;
1332         cmdmap["-version"] = parse_version;
1333         cmdmap["--version"] = parse_version;
1334         cmdmap["-sysdir"] = parse_sysdir;
1335         cmdmap["-userdir"] = parse_userdir;
1336         cmdmap["-x"] = parse_execute;
1337         cmdmap["--execute"] = parse_execute;
1338         cmdmap["-e"] = parse_export;
1339         cmdmap["--export"] = parse_export;
1340         cmdmap["-E"] = parse_export_to;
1341         cmdmap["--export-to"] = parse_export_to;
1342         cmdmap["-i"] = parse_import;
1343         cmdmap["--import"] = parse_import;
1344         cmdmap["-geometry"] = parse_geometry;
1345         cmdmap["-batch"] = parse_batch;
1346         cmdmap["-f"] = parse_force;
1347         cmdmap["--force-overwrite"] = parse_force;
1348         cmdmap["-n"] = parse_noremote;
1349         cmdmap["--no-remote"] = parse_noremote;
1350         cmdmap["-r"] = parse_remote;
1351         cmdmap["--remote"] = parse_remote;
1352
1353         for (int i = 1; i < argc; ++i) {
1354                 map<string, cmd_helper>::const_iterator it
1355                         = cmdmap.find(argv[i]);
1356
1357                 // don't complain if not found - may be parsed later
1358                 if (it == cmdmap.end())
1359                         continue;
1360
1361                 string const arg =
1362                         (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1363                 string const arg2 =
1364                         (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1365
1366                 string batch;
1367                 int const remove = 1 + it->second(arg, arg2, batch);
1368                 if (!batch.empty())
1369                         pimpl_->batch_commands.push_back(batch);
1370
1371                 // Now, remove used arguments by shifting
1372                 // the following ones remove places down.
1373                 if (remove > 0) {
1374                         os::remove_internal_args(i, remove);
1375                         argc -= remove;
1376                         for (int j = i; j < argc; ++j)
1377                                 argv[j] = argv[j + remove];
1378                         --i;
1379                 }
1380         }
1381 }
1382
1383
1384 FuncStatus getStatus(FuncRequest const & action)
1385 {
1386         LAPPERR(theApp());
1387         return theApp()->getStatus(action);
1388 }
1389
1390
1391 DispatchResult const & dispatch(FuncRequest const & action)
1392 {
1393         LAPPERR(theApp());
1394         return theApp()->dispatch(action);
1395 }
1396
1397
1398 void dispatch(FuncRequest const & action, DispatchResult & dr)
1399 {
1400         LAPPERR(theApp());
1401         theApp()->dispatch(action, dr);
1402 }
1403
1404
1405 vector<string> & theFilesToLoad()
1406 {
1407         LAPPERR(singleton_);
1408         return singleton_->pimpl_->files_to_load_;
1409 }
1410
1411
1412 BufferList & theBufferList()
1413 {
1414         LAPPERR(singleton_);
1415         return singleton_->pimpl_->buffer_list_;
1416 }
1417
1418
1419 Server & theServer()
1420 {
1421         // FIXME: this should not be use_gui dependent
1422         LWARNIF(use_gui);
1423         LAPPERR(singleton_);
1424         return *singleton_->pimpl_->lyx_server_.get();
1425 }
1426
1427
1428 ServerSocket & theServerSocket()
1429 {
1430         // FIXME: this should not be use_gui dependent
1431         LWARNIF(use_gui);
1432         LAPPERR(singleton_);
1433         return *singleton_->pimpl_->lyx_socket_.get();
1434 }
1435
1436
1437 KeyMap & theTopLevelKeymap()
1438 {
1439         LAPPERR(singleton_);
1440         return singleton_->pimpl_->toplevel_keymap_;
1441 }
1442
1443
1444 Converters & theConverters()
1445 {
1446         LAPPERR(singleton_);
1447         return  singleton_->pimpl_->converters_;
1448 }
1449
1450
1451 Converters & theSystemConverters()
1452 {
1453         LAPPERR(singleton_);
1454         return  singleton_->pimpl_->system_converters_;
1455 }
1456
1457
1458 Movers & theMovers()
1459 {
1460         LAPPERR(singleton_);
1461         return singleton_->pimpl_->movers_;
1462 }
1463
1464
1465 Mover const & getMover(string  const & fmt)
1466 {
1467         LAPPERR(singleton_);
1468         return singleton_->pimpl_->movers_(fmt);
1469 }
1470
1471
1472 void setMover(string const & fmt, string const & command)
1473 {
1474         LAPPERR(singleton_);
1475         singleton_->pimpl_->movers_.set(fmt, command);
1476 }
1477
1478
1479 Movers & theSystemMovers()
1480 {
1481         LAPPERR(singleton_);
1482         return singleton_->pimpl_->system_movers_;
1483 }
1484
1485
1486 Messages const & getMessages(string const & language)
1487 {
1488         LAPPERR(singleton_);
1489         return singleton_->messages(language);
1490 }
1491
1492
1493 Messages const & getGuiMessages()
1494 {
1495         LAPPERR(singleton_);
1496         return singleton_->messages(Messages::guiLanguage());
1497 }
1498
1499
1500 Session & theSession()
1501 {
1502         LAPPERR(singleton_);
1503         return *singleton_->pimpl_->session_.get();
1504 }
1505
1506
1507 LaTeXFonts & theLaTeXFonts()
1508 {
1509         LAPPERR(singleton_);
1510         if (!singleton_->pimpl_->latexfonts_)
1511                 singleton_->pimpl_->latexfonts_ = new LaTeXFonts;
1512         return *singleton_->pimpl_->latexfonts_;
1513 }
1514
1515
1516 CmdDef & theTopLevelCmdDef()
1517 {
1518         LAPPERR(singleton_);
1519         return singleton_->pimpl_->toplevel_cmddef_;
1520 }
1521
1522
1523 SpellChecker * theSpellChecker()
1524 {
1525         if (!singleton_->pimpl_->spell_checker_)
1526                 setSpellChecker();
1527         return singleton_->pimpl_->spell_checker_;
1528 }
1529
1530
1531 void setSpellChecker()
1532 {
1533         SpellChecker::ChangeNumber speller_change_number =singleton_->pimpl_->spell_checker_ ?
1534                 singleton_->pimpl_->spell_checker_->changeNumber() : 0;
1535
1536         if (lyxrc.spellchecker == "native") {
1537 #if defined(USE_MACOSX_PACKAGING)
1538                 if (!singleton_->pimpl_->apple_spell_checker_)
1539                         singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker;
1540                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1541 #else
1542                 singleton_->pimpl_->spell_checker_ = 0;
1543 #endif
1544         } else if (lyxrc.spellchecker == "aspell") {
1545 #if defined(USE_ASPELL)
1546                 if (!singleton_->pimpl_->aspell_checker_)
1547                         singleton_->pimpl_->aspell_checker_ = new AspellChecker;
1548                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1549 #else
1550                 singleton_->pimpl_->spell_checker_ = 0;
1551 #endif
1552         } else if (lyxrc.spellchecker == "enchant") {
1553 #if defined(USE_ENCHANT)
1554                 if (!singleton_->pimpl_->enchant_checker_)
1555                         singleton_->pimpl_->enchant_checker_ = new EnchantChecker;
1556                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1557 #else
1558                 singleton_->pimpl_->spell_checker_ = 0;
1559 #endif
1560         } else if (lyxrc.spellchecker == "hunspell") {
1561 #if defined(USE_HUNSPELL)
1562                 if (!singleton_->pimpl_->hunspell_checker_)
1563                         singleton_->pimpl_->hunspell_checker_ = new HunspellChecker;
1564                 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1565 #else
1566                 singleton_->pimpl_->spell_checker_ = 0;
1567 #endif
1568         } else {
1569                 singleton_->pimpl_->spell_checker_ = 0;
1570         }
1571         if (singleton_->pimpl_->spell_checker_) {
1572                 singleton_->pimpl_->spell_checker_->changeNumber(speller_change_number);
1573                 singleton_->pimpl_->spell_checker_->advanceChangeNumber();
1574         }
1575 }
1576
1577 } // namespace lyx