3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
20 #include "AppleSpellChecker.h"
21 #include "AspellChecker.h"
23 #include "BufferList.h"
26 #include "ConverterCache.h"
27 #include "Converter.h"
28 #include "CutAndPaste.h"
29 #include "EnchantChecker.h"
31 #include "ErrorList.h"
33 #include "FuncStatus.h"
34 #include "HunspellChecker.h"
37 #include "LayoutFile.h"
40 #include "LyXAction.h"
42 #include "ModuleList.h"
45 #include "ServerSocket.h"
48 #include "frontends/alert.h"
49 #include "frontends/Application.h"
51 #include "graphics/Previews.h"
53 #include "support/lassert.h"
54 #include "support/debug.h"
55 #include "support/environment.h"
56 #include "support/ExceptionMessage.h"
57 #include "support/filetools.h"
58 #include "support/gettext.h"
59 #include "support/lstrings.h"
60 #include "support/Messages.h"
61 #include "support/os.h"
62 #include "support/Package.h"
63 #include "support/Path.h"
64 #include "support/Systemcall.h"
66 #include "support/bind.h"
67 #include <boost/scoped_ptr.hpp>
78 using namespace lyx::support;
82 namespace Alert = frontend::Alert;
83 namespace os = support::os;
87 // Are we using the GUI at all? We default to true and this is changed
88 // to false when the export feature is used.
93 // Tell what files can be silently overwritten during batch export.
94 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
95 // Unless specified on command line (through the -f switch) or through the
96 // environment variable LYX_FORCE_OVERWRITE, the default will be MAIN_FILE.
98 OverwriteFiles force_overwrite = UNSPECIFIED;
103 // Filled with the command line arguments "foo" of "-sysdir foo" or
105 string cl_system_support;
106 string cl_user_support;
110 LyX * singleton_ = 0;
112 void showFileError(string const & error)
114 Alert::warning(_("Could not read configuration file"),
115 bformat(_("Error while reading the configuration file\n%1$s.\n"
116 "Please check your installation."), from_utf8(error)));
120 void reconfigureUserLyXDir()
122 string const configure_command = package().configure_command();
124 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
125 PathChanger p(package().user_support());
127 one.startscript(Systemcall::Wait, configure_command);
128 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
133 /// The main application class private implementation.
136 Impl() : spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
138 // Set the default User Interface language as soon as possible.
139 // The language used will be derived from the environment
141 messages_["GUI"] = Messages();
146 delete apple_spell_checker_;
147 delete aspell_checker_;
148 delete enchant_checker_;
149 delete hunspell_checker_;
153 BufferList buffer_list_;
155 KeyMap toplevel_keymap_;
157 CmdDef toplevel_cmddef_;
159 boost::scoped_ptr<Server> lyx_server_;
161 boost::scoped_ptr<ServerSocket> lyx_socket_;
163 boost::scoped_ptr<frontend::Application> application_;
164 /// lyx session, containing lastfiles, lastfilepos, and lastopened
165 boost::scoped_ptr<Session> session_;
167 /// Files to load at start.
168 vector<string> files_to_load_;
170 /// The messages translators.
171 map<string, Messages> messages_;
173 /// The file converters.
174 Converters converters_;
176 // The system converters copy after reading lyxrc.defaults.
177 Converters system_converters_;
182 Movers system_movers_;
184 /// has this user started lyx for the first time?
186 /// the parsed command line batch command if any
187 vector<string> batch_commands;
190 graphics::Previews preview_;
192 SpellChecker * spell_checker_;
194 SpellChecker * apple_spell_checker_;
196 SpellChecker * aspell_checker_;
198 SpellChecker * enchant_checker_;
200 SpellChecker * hunspell_checker_;
204 frontend::Application * theApp()
207 return singleton_->pimpl_->application_.get();
220 void lyx_exit(int exit_code)
223 // Something wrong happened so better save everything, just in
228 // Properly crash in debug mode in order to get a useful backtrace.
232 // In release mode, try to exit gracefully.
234 theApp()->exit(exit_code);
248 Messages & LyX::messages(string const & language)
250 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
252 if (it != pimpl_->messages_.end())
255 pair<map<string, Messages>::iterator, bool> result =
256 pimpl_->messages_.insert(make_pair(language, Messages(language)));
258 LASSERT(result.second, /**/);
259 return result.first->second;
263 void setRcGuiLanguage()
265 LASSERT(singleton_, /**/);
266 if (lyxrc.gui_language == "auto")
268 Language const * language = languages.getLanguage(lyxrc.gui_language);
270 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
271 if (!setEnv("LANGUAGE", language->code()))
272 LYXERR(Debug::LOCALE, "\t... failed!");
274 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
275 if (!setEnv("LC_ALL", "en_US"))
276 LYXERR(Debug::LOCALE, "\t... failed!");
278 singleton_->pimpl_->messages_["GUI"] = Messages();
282 int LyX::exec(int & argc, char * argv[])
284 // Here we need to parse the command line. At least
285 // we need to parse for "-dbg" and "-help"
286 easyParse(argc, argv);
289 init_package(os::utf8_argv(0),
290 cl_system_support, cl_user_support,
291 top_build_dir_is_one_level_up);
292 } catch (ExceptionMessage const & message) {
293 if (message.type_ == ErrorException) {
294 Alert::error(message.title_, message.details_);
296 } else if (message.type_ == WarningException) {
297 Alert::warning(message.title_, message.details_);
301 // Reinit the messages machinery in case package() knows
302 // something interesting about the locale directory.
306 // FIXME: create a ConsoleApplication
307 int exit_status = init(argc, argv);
313 // this is correct, since return values are inverted.
314 exit_status = !loadFiles();
316 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
321 BufferList::iterator begin = pimpl_->buffer_list_.begin();
323 bool final_success = false;
324 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
326 if (buf != buf->masterBuffer())
328 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
329 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
331 for (; bcit != bcend; bcit++) {
332 LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
333 buf->dispatch(*bcit, dr);
334 final_success |= !dr.error();
338 return !final_success;
341 // Let the frontend parse and remove all arguments that it knows
342 pimpl_->application_.reset(createApplication(argc, argv));
344 // Reestablish our defaults, as Qt overwrites them
345 // after createApplication()
348 // Parse and remove all known arguments in the LyX singleton
349 // Give an error for all remaining ones.
350 int exit_status = init(argc, argv);
352 // Kill the application object before exiting.
353 pimpl_->application_.reset();
360 /* Create a CoreApplication class that will provide the main event loop
361 * and the socket callback registering. With Qt4, only QtCore
362 * library would be needed.
363 * When this is done, a server_mode could be created and the following two
364 * line would be moved out from here.
366 // Note: socket callback must be registered after init(argc, argv)
367 // such that package().temp_dir() is properly initialized.
368 pimpl_->lyx_server_.reset(new Server(lyxrc.lyxpipes));
369 pimpl_->lyx_socket_.reset(new ServerSocket(
370 FileName(package().temp_dir().absFileName() + "/lyxsocket")));
372 // Start the real execution loop.
373 exit_status = pimpl_->application_->exec();
381 void LyX::prepareExit()
383 // Clear the clipboard and selection stack:
384 cap::clearCutStack();
385 cap::clearSelection();
387 // Write the index file of the converter cache
388 ConverterCache::get().writeIndex();
390 // close buffers first
391 pimpl_->buffer_list_.closeAll();
393 // register session changes and shutdown server and socket
395 if (pimpl_->session_)
396 pimpl_->session_->writeFile();
397 pimpl_->session_.reset();
398 pimpl_->lyx_server_.reset();
399 pimpl_->lyx_socket_.reset();
402 // do any other cleanup procedures now
403 if (package().temp_dir() != package().system_temp_dir()) {
404 string const abs_tmpdir = package().temp_dir().absFileName();
405 if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) {
406 docstring const msg =
407 bformat(_("%1$s does not appear like a LyX created temporary directory."),
408 from_utf8(abs_tmpdir));
409 Alert::warning(_("Cannot remove temporary directory"), msg);
411 LYXERR(Debug::INFO, "Deleting tmp dir "
412 << package().temp_dir().absFileName());
413 if (!package().temp_dir().destroyDirectory()) {
414 docstring const msg =
415 bformat(_("Unable to remove the temporary directory %1$s"),
416 from_utf8(package().temp_dir().absFileName()));
417 Alert::warning(_("Unable to remove temporary directory"), msg);
422 // Kill the application object before exiting. This avoids crashes
423 // when exiting on Linux.
424 if (pimpl_->application_)
425 pimpl_->application_.reset();
429 void LyX::earlyExit(int status)
431 LASSERT(pimpl_->application_.get(), /**/);
432 // LyX::pimpl_::application_ is not initialised at this
433 // point so it's safe to just exit after some cleanup.
439 int LyX::init(int & argc, char * argv[])
441 // check for any spurious extra arguments
442 // other than documents
443 for (int argi = 1; argi < argc ; ++argi) {
444 if (argv[argi][0] == '-') {
446 bformat(_("Wrong command line option `%1$s'. Exiting."),
447 from_utf8(os::utf8_argv(argi)))) << endl;
452 // Initialization of LyX (reads lyxrc and more)
453 LYXERR(Debug::INIT, "Initializing LyX::init...");
454 bool success = init();
455 LYXERR(Debug::INIT, "Initializing LyX::init...done");
459 // Remaining arguments are assumed to be files to load.
460 for (int argi = argc - 1; argi >= 1; --argi)
461 pimpl_->files_to_load_.push_back(os::utf8_argv(argi));
464 pimpl_->files_to_load_.push_back(
465 i18nLibFileSearch("examples", "splash.lyx").absFileName());
472 bool LyX::loadFiles()
474 LASSERT(!use_gui, /**/);
476 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
477 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
479 for (; it != end; ++it) {
480 // get absolute path of file and add ".lyx" to
481 // the filename if necessary
482 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
488 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName(), false);
489 if (buf->loadLyXFile(fname)) {
490 ErrorList const & el = buf->errorList("Parse");
492 for_each(el.begin(), el.end(),
493 bind(&LyX::printError, this, _1));
496 pimpl_->buffer_list_.release(buf);
504 void execBatchCommands()
506 LASSERT(singleton_, /**/);
507 singleton_->execCommands();
511 void LyX::execCommands()
513 // The advantage of doing this here is that the event loop
514 // is already started. So any need for interaction will be
517 // if reconfiguration is needed.
518 if (LayoutFileList::get().empty()) {
519 switch (Alert::prompt(
520 _("No textclass is found"),
521 _("LyX will only have minimal functionality because no textclasses "
522 "have been found. You can either try to reconfigure LyX normally, "
523 "try to reconfigure using only the defaults, or continue."),
530 // regular reconfigure
531 lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
534 // reconfigure --without-latex-config
535 lyx::dispatch(FuncRequest(LFUN_RECONFIGURE,
536 " --without-latex-config"));
543 // create the first main window
544 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
546 if (!pimpl_->files_to_load_.empty()) {
547 // if some files were specified at command-line we assume that the
548 // user wants to edit *these* files and not to restore the session.
549 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
551 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
553 // clear this list to save a few bytes of RAM
554 pimpl_->files_to_load_.clear();
556 pimpl_->application_->restoreGuiSession();
558 // Execute batch commands if available
559 if (pimpl_->batch_commands.empty())
562 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
563 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
564 for (; bcit != bcend; bcit++) {
565 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
566 lyx::dispatch(lyxaction.lookupFunc(*bcit));
574 The SIGHUP signal does not exist on Windows and does not need to be handled.
576 Windows handles SIGFPE and SIGSEGV signals as expected.
578 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
579 cause a new thread to be spawned. This may well result in unexpected
580 behaviour by the single-threaded LyX.
582 SIGTERM signals will come only from another process actually sending
583 that signal using 'raise' in Windows' POSIX compatability layer. It will
584 not come from the general "terminate process" methods that everyone
585 actually uses (and which can't be trapped). Killing an app 'politely' on
586 Windows involves first sending a WM_CLOSE message, something that is
587 caught already by the Qt frontend.
589 For more information see:
591 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
592 ...signals are mostly useless on Windows for a variety of reasons that are
595 'UNIX Application Migration Guide, Chapter 9'
596 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
598 'How To Terminate an Application "Cleanly" in Win32'
599 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
603 static void error_handler(int err_sig)
605 // Throw away any signals other than the first one received.
606 static sig_atomic_t handling_error = false;
609 handling_error = true;
611 // We have received a signal indicating a fatal error, so
612 // try and save the data ASAP.
615 // These lyxerr calls may or may not work:
617 // Signals are asynchronous, so the main program may be in a very
618 // fragile state when a signal is processed and thus while a signal
619 // handler function executes.
620 // In general, therefore, we should avoid performing any
621 // I/O operations or calling most library and system functions from
624 // This shouldn't matter here, however, as we've already invoked
630 msg = _("SIGHUP signal caught!\nBye.");
634 msg = _("SIGFPE signal caught!\nBye.");
637 msg = _("SIGSEGV signal caught!\n"
638 "Sorry, you have found a bug in LyX, "
639 "hope you have not lost any data.\n"
640 "Please read the bug-reporting instructions "
641 "in 'Help->Introduction' and send us a bug report, "
642 "if necessary. Thanks !\nBye.");
651 lyxerr << "\nlyx: " << msg << endl;
652 // try to make a GUI message
653 Alert::error(_("LyX crashed!"), msg);
656 // Deinstall the signal handlers
658 signal(SIGHUP, SIG_DFL);
660 signal(SIGINT, SIG_DFL);
661 signal(SIGFPE, SIG_DFL);
662 signal(SIGSEGV, SIG_DFL);
663 signal(SIGTERM, SIG_DFL);
666 if (err_sig == SIGSEGV ||
667 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty())) {
669 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty()) {
672 // with abort() it crashes again.
685 void LyX::printError(ErrorItem const & ei)
687 docstring tmp = _("LyX: ") + ei.error + char_type(':')
689 cerr << to_utf8(tmp) << endl;
696 signal(SIGHUP, error_handler);
698 signal(SIGFPE, error_handler);
699 signal(SIGSEGV, error_handler);
700 signal(SIGINT, error_handler);
701 signal(SIGTERM, error_handler);
702 // SIGPIPE can be safely ignored.
704 lyxrc.tempdir_path = package().temp_dir().absFileName();
705 lyxrc.document_path = package().document_dir().absFileName();
707 if (lyxrc.example_path.empty()) {
708 lyxrc.example_path = addPath(package().system_support().absFileName(),
711 if (lyxrc.template_path.empty()) {
712 lyxrc.template_path = addPath(package().system_support().absFileName(),
717 // Read configuration files
720 // This one may have been distributed along with LyX.
721 if (!readRcFile("lyxrc.dist"))
724 // Set the language defined by the distributor.
727 // Set the PATH correctly.
728 #if !defined (USE_POSIX_PACKAGING)
729 // Add the directory containing the LyX executable to the path
730 // so that LyX can find things like tex2lyx.
731 if (package().build_support().empty())
732 prependEnvPath("PATH", package().binary_dir().absFileName());
734 if (!lyxrc.path_prefix.empty())
735 prependEnvPath("PATH", lyxrc.path_prefix);
737 // Check that user LyX directory is ok.
738 if (queryUserLyXDir(package().explicit_user_support()))
739 reconfigureUserLyXDir();
742 // No need for a splash when there is no GUI
744 // Default is to overwrite the main file during export, unless
745 // the -f switch was specified or LYX_FORCE_OVERWRITE was set
746 if (force_overwrite == UNSPECIFIED) {
747 string const what = getEnv("LYX_FORCE_OVERWRITE");
749 force_overwrite = ALL_FILES;
750 else if (what == "none")
751 force_overwrite = NO_FILES;
753 force_overwrite = MAIN_FILE;
757 // This one is generated in user_support directory by lib/configure.py.
758 if (!readRcFile("lyxrc.defaults"))
761 // Query the OS to know what formats are viewed natively
762 formats.setAutoOpen();
764 // Read lyxrc.dist again to be able to override viewer auto-detection.
765 readRcFile("lyxrc.dist");
767 // Set again the language defined by the distributor.
770 system_lyxrc = lyxrc;
771 system_formats = formats;
772 pimpl_->system_converters_ = pimpl_->converters_;
773 pimpl_->system_movers_ = pimpl_->movers_;
774 system_lcolor = lcolor;
776 // This one is edited through the preferences dialog.
777 if (!readRcFile("preferences"))
780 if (!readEncodingsFile("encodings", "unicodesymbols"))
782 if (!readLanguagesFile("languages"))
785 // Set the language defined by the user.
788 LYXERR(Debug::INIT, "Reading layouts...");
790 LayoutFileList::get().read();
792 theModuleList.read();
794 // read keymap and ui files in batch mode as well
795 // because InsetInfo needs to know these to produce
796 // the correct output
798 // Set up command definitions
799 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
802 pimpl_->toplevel_keymap_.read("site");
803 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
804 // load user bind file user.bind
805 pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
807 if (lyxerr.debugging(Debug::LYXRC))
810 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
811 if (!lyxrc.path_prefix.empty())
812 prependEnvPath("PATH", lyxrc.path_prefix);
814 FileName const document_path(lyxrc.document_path);
815 if (document_path.exists() && document_path.isDirectory())
816 package().document_dir() = document_path;
818 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
819 if (package().temp_dir().empty()) {
820 Alert::error(_("Could not create temporary directory"),
821 bformat(_("Could not create a temporary directory in\n"
823 "Make sure that this path exists and is writable and try again."),
824 from_utf8(lyxrc.tempdir_path)));
825 // createLyXTmpDir() tries sufficiently hard to create a
826 // usable temp dir, so the probability to come here is
827 // close to zero. We therefore don't try to overcome this
828 // problem with e.g. asking the user for a new path and
829 // trying again but simply exit.
833 LYXERR(Debug::INIT, "LyX tmp dir: `"
834 << package().temp_dir().absFileName() << '\'');
836 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
837 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
839 // This must happen after package initialization and after lyxrc is
840 // read, therefore it can't be done by a static object.
841 ConverterCache::init();
847 void emergencyCleanup()
849 // what to do about tmpfiles is non-obvious. we would
850 // like to delete any we find, but our lyxdir might
851 // contain documents etc. which might be helpful on
854 singleton_->pimpl_->buffer_list_.emergencyWriteAll();
856 if (singleton_->pimpl_->lyx_server_)
857 singleton_->pimpl_->lyx_server_->emergencyCleanup();
858 singleton_->pimpl_->lyx_server_.reset();
859 singleton_->pimpl_->lyx_socket_.reset();
864 // return true if file does not exist or is older than configure.py.
865 static bool needsUpdate(string const & file)
867 // We cannot initialize configure_script directly because the package
868 // is not initialized yet when static objects are constructed.
869 static FileName configure_script;
870 static bool firstrun = true;
873 FileName(addName(package().system_support().absFileName(),
879 FileName(addName(package().user_support().absFileName(), file));
880 return !absfile.exists()
881 || configure_script.lastModified() > absfile.lastModified();
885 bool LyX::queryUserLyXDir(bool explicit_userdir)
887 // Does user directory exist?
888 FileName const sup = package().user_support();
889 if (sup.exists() && sup.isDirectory()) {
892 return needsUpdate("lyxrc.defaults")
893 || needsUpdate("lyxmodules.lst")
894 || needsUpdate("textclass.lst")
895 || needsUpdate("packages.lst");
898 first_start = !explicit_userdir;
900 // If the user specified explicitly a directory, ask whether
901 // to create it. If the user says "no", then exit.
902 if (explicit_userdir &&
904 _("Missing user LyX directory"),
905 bformat(_("You have specified a non-existent user "
906 "LyX directory, %1$s.\n"
907 "It is needed to keep your own configuration."),
908 from_utf8(package().user_support().absFileName())),
910 _("&Create directory"),
912 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
913 earlyExit(EXIT_FAILURE);
916 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
917 from_utf8(sup.absFileName()))) << endl;
919 if (!sup.createDirectory(0755)) {
920 // Failed, so let's exit.
921 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
923 earlyExit(EXIT_FAILURE);
930 bool LyX::readRcFile(string const & name)
932 LYXERR(Debug::INIT, "About to read " << name << "... ");
934 FileName const lyxrc_path = libFileSearch(string(), name);
935 if (!lyxrc_path.empty()) {
936 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
937 if (lyxrc.read(lyxrc_path) < 0) {
942 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
947 // Read the languages file `name'
948 bool LyX::readLanguagesFile(string const & name)
950 LYXERR(Debug::INIT, "About to read " << name << "...");
952 FileName const lang_path = libFileSearch(string(), name);
953 if (lang_path.empty()) {
957 languages.read(lang_path);
962 // Read the encodings file `name'
963 bool LyX::readEncodingsFile(string const & enc_name,
964 string const & symbols_name)
966 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
967 << symbols_name << "...");
969 FileName const symbols_path = libFileSearch(string(), symbols_name);
970 if (symbols_path.empty()) {
971 showFileError(symbols_name);
975 FileName const enc_path = libFileSearch(string(), enc_name);
976 if (enc_path.empty()) {
977 showFileError(enc_name);
980 encodings.read(enc_path, symbols_path);
987 /// return the the number of arguments consumed
988 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
990 int parse_dbg(string const & arg, string const &, string &)
993 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
994 Debug::showTags(lyxerr);
997 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
999 lyxerr.setLevel(Debug::value(arg));
1000 Debug::showLevel(lyxerr, lyxerr.level());
1005 int parse_help(string const &, string const &, string &)
1008 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1009 "Command line switches (case sensitive):\n"
1010 "\t-help summarize LyX usage\n"
1011 "\t-userdir dir set user directory to dir\n"
1012 "\t-sysdir dir set system directory to dir\n"
1013 "\t-geometry WxH+X+Y set geometry of the main window\n"
1014 "\t-dbg feature[,feature]...\n"
1015 " select the features to debug.\n"
1016 " Type `lyx -dbg' to see the list of features\n"
1017 "\t-x [--execute] command\n"
1018 " where command is a lyx command.\n"
1019 "\t-e [--export] fmt\n"
1020 " where fmt is the export format of choice.\n"
1021 " Look on Tools->Preferences->File formats->Format\n"
1022 " to get an idea which parameters should be passed.\n"
1023 " Note that the order of -e and -x switches matters.\n"
1024 "\t-i [--import] fmt file.xxx\n"
1025 " where fmt is the import format of choice\n"
1026 " and file.xxx is the file to be imported.\n"
1027 "\t-f [--force-overwrite] what\n"
1028 " where what is either `all', `main' or `none',\n"
1029 " specifying whether all files, main file only, or no files,\n"
1030 " respectively, are to be overwritten during a batch export.\n"
1031 " Anything else is equivalent to `all', but is not consumed.\n"
1032 "\t-batch execute commands without launching GUI and exit.\n"
1033 "\t-version summarize version and build info\n"
1034 "Check the LyX man page for more details.")) << endl;
1040 int parse_version(string const &, string const &, string &)
1042 lyxerr << "LyX " << lyx_version
1043 << " (" << lyx_release_date << ")" << endl;
1044 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1046 lyxerr << lyx_version_info << endl;
1052 int parse_sysdir(string const & arg, string const &, string &)
1055 Alert::error(_("No system directory"),
1056 _("Missing directory for -sysdir switch"));
1059 cl_system_support = arg;
1064 int parse_userdir(string const & arg, string const &, string &)
1067 Alert::error(_("No user directory"),
1068 _("Missing directory for -userdir switch"));
1071 cl_user_support = arg;
1076 int parse_execute(string const & arg, string const &, string & batch)
1079 Alert::error(_("Incomplete command"),
1080 _("Missing command string after --execute switch"));
1088 int parse_export(string const & type, string const &, string & batch)
1091 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1092 "--export switch")) << endl;
1095 batch = "buffer-export " + type;
1101 int parse_import(string const & type, string const & file, string & batch)
1104 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1105 "--import switch")) << endl;
1109 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1113 batch = "buffer-import " + type + ' ' + file;
1118 int parse_geometry(string const & arg1, string const &, string &)
1121 // don't remove "-geometry", it will be pruned out later in the
1122 // frontend if need be.
1127 int parse_batch(string const &, string const &, string &)
1134 int parse_force(string const & arg, string const &, string &)
1137 force_overwrite = ALL_FILES;
1139 } else if (arg == "main") {
1140 force_overwrite = MAIN_FILE;
1142 } else if (arg == "none") {
1143 force_overwrite = NO_FILES;
1146 force_overwrite = ALL_FILES;
1154 void LyX::easyParse(int & argc, char * argv[])
1156 map<string, cmd_helper> cmdmap;
1158 cmdmap["-dbg"] = parse_dbg;
1159 cmdmap["-help"] = parse_help;
1160 cmdmap["--help"] = parse_help;
1161 cmdmap["-version"] = parse_version;
1162 cmdmap["--version"] = parse_version;
1163 cmdmap["-sysdir"] = parse_sysdir;
1164 cmdmap["-userdir"] = parse_userdir;
1165 cmdmap["-x"] = parse_execute;
1166 cmdmap["--execute"] = parse_execute;
1167 cmdmap["-e"] = parse_export;
1168 cmdmap["--export"] = parse_export;
1169 cmdmap["-i"] = parse_import;
1170 cmdmap["--import"] = parse_import;
1171 cmdmap["-geometry"] = parse_geometry;
1172 cmdmap["-batch"] = parse_batch;
1173 cmdmap["-f"] = parse_force;
1174 cmdmap["--force-overwrite"] = parse_force;
1176 for (int i = 1; i < argc; ++i) {
1177 map<string, cmd_helper>::const_iterator it
1178 = cmdmap.find(argv[i]);
1180 // don't complain if not found - may be parsed later
1181 if (it == cmdmap.end())
1185 (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1187 (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1190 int const remove = 1 + it->second(arg, arg2, batch);
1192 pimpl_->batch_commands.push_back(batch);
1194 // Now, remove used arguments by shifting
1195 // the following ones remove places down.
1197 os::remove_internal_args(i, remove);
1199 for (int j = i; j < argc; ++j)
1200 argv[j] = argv[j + remove];
1207 FuncStatus getStatus(FuncRequest const & action)
1209 LASSERT(theApp(), /**/);
1210 return theApp()->getStatus(action);
1214 void dispatch(FuncRequest const & action)
1216 LASSERT(theApp(), /**/);
1217 return theApp()->dispatch(action);
1221 void dispatch(FuncRequest const & action, DispatchResult & dr)
1223 LASSERT(theApp(), /**/);
1224 return theApp()->dispatch(action, dr);
1228 BufferList & theBufferList()
1230 LASSERT(singleton_, /**/);
1231 return singleton_->pimpl_->buffer_list_;
1235 Server & theServer()
1237 // FIXME: this should not be use_gui dependent
1238 LASSERT(use_gui, /**/);
1239 LASSERT(singleton_, /**/);
1240 return *singleton_->pimpl_->lyx_server_.get();
1244 ServerSocket & theServerSocket()
1246 // FIXME: this should not be use_gui dependent
1247 LASSERT(use_gui, /**/);
1248 LASSERT(singleton_, /**/);
1249 return *singleton_->pimpl_->lyx_socket_.get();
1253 KeyMap & theTopLevelKeymap()
1255 LASSERT(singleton_, /**/);
1256 return singleton_->pimpl_->toplevel_keymap_;
1260 Converters & theConverters()
1262 LASSERT(singleton_, /**/);
1263 return singleton_->pimpl_->converters_;
1267 Converters & theSystemConverters()
1269 LASSERT(singleton_, /**/);
1270 return singleton_->pimpl_->system_converters_;
1274 Movers & theMovers()
1276 LASSERT(singleton_, /**/);
1277 return singleton_->pimpl_->movers_;
1281 Mover const & getMover(string const & fmt)
1283 LASSERT(singleton_, /**/);
1284 return singleton_->pimpl_->movers_(fmt);
1288 void setMover(string const & fmt, string const & command)
1290 LASSERT(singleton_, /**/);
1291 singleton_->pimpl_->movers_.set(fmt, command);
1295 Movers & theSystemMovers()
1297 LASSERT(singleton_, /**/);
1298 return singleton_->pimpl_->system_movers_;
1302 Messages const & getMessages(string const & language)
1304 LASSERT(singleton_, /**/);
1305 return singleton_->messages(language);
1309 Messages const & getGuiMessages()
1311 LASSERT(singleton_, /**/);
1312 return singleton_->pimpl_->messages_["GUI"];
1316 graphics::Previews & thePreviews()
1318 LASSERT(singleton_, /**/);
1319 return singleton_->pimpl_->preview_;
1323 Session & theSession()
1325 LASSERT(singleton_, /**/);
1326 return *singleton_->pimpl_->session_.get();
1330 CmdDef & theTopLevelCmdDef()
1332 LASSERT(singleton_, /**/);
1333 return singleton_->pimpl_->toplevel_cmddef_;
1337 SpellChecker * theSpellChecker()
1339 if (!singleton_->pimpl_->spell_checker_)
1341 return singleton_->pimpl_->spell_checker_;
1345 void setSpellChecker()
1347 #if defined(USE_MACOSX_PACKAGING)
1348 if (lyxrc.spellchecker == "native") {
1349 if (!singleton_->pimpl_->apple_spell_checker_)
1350 singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker();
1351 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1355 #if defined(USE_ASPELL)
1356 if (lyxrc.spellchecker == "aspell") {
1357 if (!singleton_->pimpl_->aspell_checker_)
1358 singleton_->pimpl_->aspell_checker_ = new AspellChecker();
1359 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1363 #if defined(USE_ENCHANT)
1364 if (lyxrc.spellchecker == "enchant") {
1365 if (!singleton_->pimpl_->enchant_checker_)
1366 singleton_->pimpl_->enchant_checker_ = new EnchantChecker();
1367 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1371 #if defined(USE_HUNSPELL)
1372 if (lyxrc.spellchecker == "hunspell") {
1373 if (!singleton_->pimpl_->hunspell_checker_)
1374 singleton_->pimpl_->hunspell_checker_ = new HunspellChecker();
1375 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1379 singleton_->pimpl_->spell_checker_ = 0;