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.
96 OverwriteFiles force_overwrite = NO_FILES;
101 // Filled with the command line arguments "foo" of "-sysdir foo" or
103 string cl_system_support;
104 string cl_user_support;
108 LyX * singleton_ = 0;
110 void showFileError(string const & error)
112 Alert::warning(_("Could not read configuration file"),
113 bformat(_("Error while reading the configuration file\n%1$s.\n"
114 "Please check your installation."), from_utf8(error)));
118 void reconfigureUserLyXDir()
120 string const configure_command = package().configure_command();
122 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
123 PathChanger p(package().user_support());
125 one.startscript(Systemcall::Wait, configure_command);
126 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
131 /// The main application class private implementation.
134 Impl() : spell_checker_(0), apple_spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
136 // Set the default User Interface language as soon as possible.
137 // The language used will be derived from the environment
139 messages_["GUI"] = Messages();
144 delete apple_spell_checker_;
145 delete aspell_checker_;
146 delete enchant_checker_;
147 delete hunspell_checker_;
151 BufferList buffer_list_;
153 KeyMap toplevel_keymap_;
155 CmdDef toplevel_cmddef_;
157 boost::scoped_ptr<Server> lyx_server_;
159 boost::scoped_ptr<ServerSocket> lyx_socket_;
161 boost::scoped_ptr<frontend::Application> application_;
162 /// lyx session, containing lastfiles, lastfilepos, and lastopened
163 boost::scoped_ptr<Session> session_;
165 /// Files to load at start.
166 vector<string> files_to_load_;
168 /// The messages translators.
169 map<string, Messages> messages_;
171 /// The file converters.
172 Converters converters_;
174 // The system converters copy after reading lyxrc.defaults.
175 Converters system_converters_;
180 Movers system_movers_;
182 /// has this user started lyx for the first time?
184 /// the parsed command line batch command if any
185 vector<string> batch_commands;
188 graphics::Previews preview_;
190 SpellChecker * spell_checker_;
192 SpellChecker * apple_spell_checker_;
194 SpellChecker * aspell_checker_;
196 SpellChecker * enchant_checker_;
198 SpellChecker * hunspell_checker_;
202 frontend::Application * theApp()
205 return singleton_->pimpl_->application_.get();
218 void lyx_exit(int exit_code)
221 // Something wrong happened so better save everything, just in
226 // Properly crash in debug mode in order to get a useful backtrace.
230 // In release mode, try to exit gracefully.
232 theApp()->exit(exit_code);
246 Messages & LyX::messages(string const & language)
248 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
250 if (it != pimpl_->messages_.end())
253 pair<map<string, Messages>::iterator, bool> result =
254 pimpl_->messages_.insert(make_pair(language, Messages(language)));
256 LASSERT(result.second, /**/);
257 return result.first->second;
261 void setRcGuiLanguage()
263 LASSERT(singleton_, /**/);
264 if (lyxrc.gui_language == "auto")
266 Language const * language = languages.getLanguage(lyxrc.gui_language);
268 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
269 if (!setEnv("LANGUAGE", language->code()))
270 LYXERR(Debug::LOCALE, "\t... failed!");
272 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
273 if (!setEnv("LC_ALL", "en_US"))
274 LYXERR(Debug::LOCALE, "\t... failed!");
276 singleton_->pimpl_->messages_["GUI"] = Messages();
280 int LyX::exec(int & argc, char * argv[])
282 // Here we need to parse the command line. At least
283 // we need to parse for "-dbg" and "-help"
284 easyParse(argc, argv);
287 init_package(os::utf8_argv(0),
288 cl_system_support, cl_user_support,
289 top_build_dir_is_one_level_up);
290 } catch (ExceptionMessage const & message) {
291 if (message.type_ == ErrorException) {
292 Alert::error(message.title_, message.details_);
294 } else if (message.type_ == WarningException) {
295 Alert::warning(message.title_, message.details_);
299 // Reinit the messages machinery in case package() knows
300 // something interesting about the locale directory.
304 // FIXME: create a ConsoleApplication
305 int exit_status = init(argc, argv);
311 // this is correct, since return values are inverted.
312 exit_status = !loadFiles();
314 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
319 BufferList::iterator begin = pimpl_->buffer_list_.begin();
321 bool final_success = false;
322 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
324 if (buf != buf->masterBuffer())
326 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
327 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
329 for (; bcit != bcend; bcit++) {
330 LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
331 buf->dispatch(*bcit, dr);
332 final_success |= !dr.error();
336 return !final_success;
339 // Let the frontend parse and remove all arguments that it knows
340 pimpl_->application_.reset(createApplication(argc, argv));
342 // Reestablish our defaults, as Qt overwrites them
343 // after createApplication()
346 // Parse and remove all known arguments in the LyX singleton
347 // Give an error for all remaining ones.
348 int exit_status = init(argc, argv);
350 // Kill the application object before exiting.
351 pimpl_->application_.reset();
358 /* Create a CoreApplication class that will provide the main event loop
359 * and the socket callback registering. With Qt4, only QtCore
360 * library would be needed.
361 * When this is done, a server_mode could be created and the following two
362 * line would be moved out from here.
364 // Note: socket callback must be registered after init(argc, argv)
365 // such that package().temp_dir() is properly initialized.
366 pimpl_->lyx_server_.reset(new Server(lyxrc.lyxpipes));
367 pimpl_->lyx_socket_.reset(new ServerSocket(
368 FileName(package().temp_dir().absFileName() + "/lyxsocket")));
370 // Start the real execution loop.
371 exit_status = pimpl_->application_->exec();
379 void LyX::prepareExit()
381 // Clear the clipboard and selection stack:
382 cap::clearCutStack();
383 cap::clearSelection();
385 // Write the index file of the converter cache
386 ConverterCache::get().writeIndex();
388 // close buffers first
389 pimpl_->buffer_list_.closeAll();
391 // register session changes and shutdown server and socket
393 if (pimpl_->session_)
394 pimpl_->session_->writeFile();
395 pimpl_->session_.reset();
396 pimpl_->lyx_server_.reset();
397 pimpl_->lyx_socket_.reset();
400 // do any other cleanup procedures now
401 if (package().temp_dir() != package().system_temp_dir()) {
402 string const abs_tmpdir = package().temp_dir().absFileName();
403 if (!contains(package().temp_dir().absFileName(), "lyx_tmpdir")) {
404 docstring const msg =
405 bformat(_("%1$s does not appear like a LyX created temporary directory."),
406 from_utf8(abs_tmpdir));
407 Alert::warning(_("Cannot remove temporary directory"), msg);
409 LYXERR(Debug::INFO, "Deleting tmp dir "
410 << package().temp_dir().absFileName());
411 if (!package().temp_dir().destroyDirectory()) {
412 docstring const msg =
413 bformat(_("Unable to remove the temporary directory %1$s"),
414 from_utf8(package().temp_dir().absFileName()));
415 Alert::warning(_("Unable to remove temporary directory"), msg);
420 // Kill the application object before exiting. This avoids crashes
421 // when exiting on Linux.
422 if (pimpl_->application_)
423 pimpl_->application_.reset();
427 void LyX::earlyExit(int status)
429 LASSERT(pimpl_->application_.get(), /**/);
430 // LyX::pimpl_::application_ is not initialised at this
431 // point so it's safe to just exit after some cleanup.
437 int LyX::init(int & argc, char * argv[])
439 // check for any spurious extra arguments
440 // other than documents
441 for (int argi = 1; argi < argc ; ++argi) {
442 if (argv[argi][0] == '-') {
444 bformat(_("Wrong command line option `%1$s'. Exiting."),
445 from_utf8(os::utf8_argv(argi)))) << endl;
450 // Initialization of LyX (reads lyxrc and more)
451 LYXERR(Debug::INIT, "Initializing LyX::init...");
452 bool success = init();
453 LYXERR(Debug::INIT, "Initializing LyX::init...done");
457 // Remaining arguments are assumed to be files to load.
458 for (int argi = argc - 1; argi >= 1; --argi)
459 pimpl_->files_to_load_.push_back(os::utf8_argv(argi));
462 pimpl_->files_to_load_.push_back(
463 i18nLibFileSearch("examples", "splash.lyx").absFileName());
470 bool LyX::loadFiles()
472 LASSERT(!use_gui, /**/);
474 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
475 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
477 for (; it != end; ++it) {
478 // get absolute path of file and add ".lyx" to
479 // the filename if necessary
480 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
486 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName(), false);
487 if (buf->loadLyXFile(fname)) {
488 ErrorList const & el = buf->errorList("Parse");
490 for_each(el.begin(), el.end(),
491 bind(&LyX::printError, this, _1));
494 pimpl_->buffer_list_.release(buf);
502 void execBatchCommands()
504 LASSERT(singleton_, /**/);
505 singleton_->execCommands();
509 void LyX::execCommands()
511 // The advantage of doing this here is that the event loop
512 // is already started. So any need for interaction will be
515 // if reconfiguration is needed.
516 if (LayoutFileList::get().empty()) {
517 switch (Alert::prompt(
518 _("No textclass is found"),
519 _("LyX will only have minimal functionality because no textclasses "
520 "have been found. You can either try to reconfigure LyX normally, "
521 "try to reconfigure using only the defaults, or continue."),
528 // regular reconfigure
529 lyx::dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
532 // reconfigure --without-latex-config
533 lyx::dispatch(FuncRequest(LFUN_RECONFIGURE,
534 " --without-latex-config"));
541 // create the first main window
542 lyx::dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
544 if (!pimpl_->files_to_load_.empty()) {
545 // if some files were specified at command-line we assume that the
546 // user wants to edit *these* files and not to restore the session.
547 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
549 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
551 // clear this list to save a few bytes of RAM
552 pimpl_->files_to_load_.clear();
554 pimpl_->application_->restoreGuiSession();
556 // Execute batch commands if available
557 if (pimpl_->batch_commands.empty())
560 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
561 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
562 for (; bcit != bcend; bcit++) {
563 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
564 lyx::dispatch(lyxaction.lookupFunc(*bcit));
572 The SIGHUP signal does not exist on Windows and does not need to be handled.
574 Windows handles SIGFPE and SIGSEGV signals as expected.
576 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
577 cause a new thread to be spawned. This may well result in unexpected
578 behaviour by the single-threaded LyX.
580 SIGTERM signals will come only from another process actually sending
581 that signal using 'raise' in Windows' POSIX compatability layer. It will
582 not come from the general "terminate process" methods that everyone
583 actually uses (and which can't be trapped). Killing an app 'politely' on
584 Windows involves first sending a WM_CLOSE message, something that is
585 caught already by the Qt frontend.
587 For more information see:
589 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
590 ...signals are mostly useless on Windows for a variety of reasons that are
593 'UNIX Application Migration Guide, Chapter 9'
594 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
596 'How To Terminate an Application "Cleanly" in Win32'
597 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
601 static void error_handler(int err_sig)
603 // Throw away any signals other than the first one received.
604 static sig_atomic_t handling_error = false;
607 handling_error = true;
609 // We have received a signal indicating a fatal error, so
610 // try and save the data ASAP.
613 // These lyxerr calls may or may not work:
615 // Signals are asynchronous, so the main program may be in a very
616 // fragile state when a signal is processed and thus while a signal
617 // handler function executes.
618 // In general, therefore, we should avoid performing any
619 // I/O operations or calling most library and system functions from
622 // This shouldn't matter here, however, as we've already invoked
628 msg = _("SIGHUP signal caught!\nBye.");
632 msg = _("SIGFPE signal caught!\nBye.");
635 msg = _("SIGSEGV signal caught!\n"
636 "Sorry, you have found a bug in LyX, "
637 "hope you have not lost any data.\n"
638 "Please read the bug-reporting instructions "
639 "in 'Help->Introduction' and send us a bug report, "
640 "if necessary. Thanks !\nBye.");
649 lyxerr << "\nlyx: " << msg << endl;
650 // try to make a GUI message
651 Alert::error(_("LyX crashed!"), msg);
654 // Deinstall the signal handlers
656 signal(SIGHUP, SIG_DFL);
658 signal(SIGINT, SIG_DFL);
659 signal(SIGFPE, SIG_DFL);
660 signal(SIGSEGV, SIG_DFL);
661 signal(SIGTERM, SIG_DFL);
664 if (err_sig == SIGSEGV ||
665 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty())) {
667 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty()) {
670 // with abort() it crashes again.
683 void LyX::printError(ErrorItem const & ei)
685 docstring tmp = _("LyX: ") + ei.error + char_type(':')
687 cerr << to_utf8(tmp) << endl;
694 signal(SIGHUP, error_handler);
696 signal(SIGFPE, error_handler);
697 signal(SIGSEGV, error_handler);
698 signal(SIGINT, error_handler);
699 signal(SIGTERM, error_handler);
700 // SIGPIPE can be safely ignored.
702 lyxrc.tempdir_path = package().temp_dir().absFileName();
703 lyxrc.document_path = package().document_dir().absFileName();
705 if (lyxrc.example_path.empty()) {
706 lyxrc.example_path = addPath(package().system_support().absFileName(),
709 if (lyxrc.template_path.empty()) {
710 lyxrc.template_path = addPath(package().system_support().absFileName(),
715 // Read configuration files
718 // This one may have been distributed along with LyX.
719 if (!readRcFile("lyxrc.dist"))
722 // Set the language defined by the distributor.
725 // Set the PATH correctly.
726 #if !defined (USE_POSIX_PACKAGING)
727 // Add the directory containing the LyX executable to the path
728 // so that LyX can find things like tex2lyx.
729 if (package().build_support().empty())
730 prependEnvPath("PATH", package().binary_dir().absFileName());
732 if (!lyxrc.path_prefix.empty())
733 prependEnvPath("PATH", lyxrc.path_prefix);
735 // Check that user LyX directory is ok.
736 if (queryUserLyXDir(package().explicit_user_support()))
737 reconfigureUserLyXDir();
739 // no need for a splash when there is no GUI
744 // This one is generated in user_support directory by lib/configure.py.
745 if (!readRcFile("lyxrc.defaults"))
748 // Query the OS to know what formats are viewed natively
749 formats.setAutoOpen();
751 // Read lyxrc.dist again to be able to override viewer auto-detection.
752 readRcFile("lyxrc.dist");
754 // Set again the language defined by the distributor.
757 system_lyxrc = lyxrc;
758 system_formats = formats;
759 pimpl_->system_converters_ = pimpl_->converters_;
760 pimpl_->system_movers_ = pimpl_->movers_;
761 system_lcolor = lcolor;
763 // This one is edited through the preferences dialog.
764 if (!readRcFile("preferences"))
767 if (!readEncodingsFile("encodings", "unicodesymbols"))
769 if (!readLanguagesFile("languages"))
772 // Set the language defined by the user.
775 LYXERR(Debug::INIT, "Reading layouts...");
777 LayoutFileList::get().read();
779 theModuleList.read();
781 // read keymap and ui files in batch mode as well
782 // because InsetInfo needs to know these to produce
783 // the correct output
785 // Set up command definitions
786 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
789 pimpl_->toplevel_keymap_.read("site");
790 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
791 // load user bind file user.bind
792 pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
794 if (lyxerr.debugging(Debug::LYXRC))
797 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
798 if (!lyxrc.path_prefix.empty())
799 prependEnvPath("PATH", lyxrc.path_prefix);
801 FileName const document_path(lyxrc.document_path);
802 if (document_path.exists() && document_path.isDirectory())
803 package().document_dir() = document_path;
805 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
806 if (package().temp_dir().empty()) {
807 Alert::error(_("Could not create temporary directory"),
808 bformat(_("Could not create a temporary directory in\n"
810 "Make sure that this path exists and is writable and try again."),
811 from_utf8(lyxrc.tempdir_path)));
812 // createLyXTmpDir() tries sufficiently hard to create a
813 // usable temp dir, so the probability to come here is
814 // close to zero. We therefore don't try to overcome this
815 // problem with e.g. asking the user for a new path and
816 // trying again but simply exit.
820 LYXERR(Debug::INIT, "LyX tmp dir: `"
821 << package().temp_dir().absFileName() << '\'');
823 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
824 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
826 // This must happen after package initialization and after lyxrc is
827 // read, therefore it can't be done by a static object.
828 ConverterCache::init();
834 void emergencyCleanup()
836 // what to do about tmpfiles is non-obvious. we would
837 // like to delete any we find, but our lyxdir might
838 // contain documents etc. which might be helpful on
841 singleton_->pimpl_->buffer_list_.emergencyWriteAll();
843 if (singleton_->pimpl_->lyx_server_)
844 singleton_->pimpl_->lyx_server_->emergencyCleanup();
845 singleton_->pimpl_->lyx_server_.reset();
846 singleton_->pimpl_->lyx_socket_.reset();
851 // return true if file does not exist or is older than configure.py.
852 static bool needsUpdate(string const & file)
854 // We cannot initialize configure_script directly because the package
855 // is not initialized yet when static objects are constructed.
856 static FileName configure_script;
857 static bool firstrun = true;
860 FileName(addName(package().system_support().absFileName(),
866 FileName(addName(package().user_support().absFileName(), file));
867 return !absfile.exists()
868 || configure_script.lastModified() > absfile.lastModified();
872 bool LyX::queryUserLyXDir(bool explicit_userdir)
874 // Does user directory exist?
875 FileName const sup = package().user_support();
876 if (sup.exists() && sup.isDirectory()) {
879 return needsUpdate("lyxrc.defaults")
880 || needsUpdate("lyxmodules.lst")
881 || needsUpdate("textclass.lst")
882 || needsUpdate("packages.lst");
885 first_start = !explicit_userdir;
887 // If the user specified explicitly a directory, ask whether
888 // to create it. If the user says "no", then exit.
889 if (explicit_userdir &&
891 _("Missing user LyX directory"),
892 bformat(_("You have specified a non-existent user "
893 "LyX directory, %1$s.\n"
894 "It is needed to keep your own configuration."),
895 from_utf8(package().user_support().absFileName())),
897 _("&Create directory"),
899 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
900 earlyExit(EXIT_FAILURE);
903 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
904 from_utf8(sup.absFileName()))) << endl;
906 if (!sup.createDirectory(0755)) {
907 // Failed, so let's exit.
908 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
910 earlyExit(EXIT_FAILURE);
917 bool LyX::readRcFile(string const & name)
919 LYXERR(Debug::INIT, "About to read " << name << "... ");
921 FileName const lyxrc_path = libFileSearch(string(), name);
922 if (!lyxrc_path.empty()) {
923 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
924 if (lyxrc.read(lyxrc_path) < 0) {
929 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
934 // Read the languages file `name'
935 bool LyX::readLanguagesFile(string const & name)
937 LYXERR(Debug::INIT, "About to read " << name << "...");
939 FileName const lang_path = libFileSearch(string(), name);
940 if (lang_path.empty()) {
944 languages.read(lang_path);
949 // Read the encodings file `name'
950 bool LyX::readEncodingsFile(string const & enc_name,
951 string const & symbols_name)
953 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
954 << symbols_name << "...");
956 FileName const symbols_path = libFileSearch(string(), symbols_name);
957 if (symbols_path.empty()) {
958 showFileError(symbols_name);
962 FileName const enc_path = libFileSearch(string(), enc_name);
963 if (enc_path.empty()) {
964 showFileError(enc_name);
967 encodings.read(enc_path, symbols_path);
974 /// return the the number of arguments consumed
975 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
977 int parse_dbg(string const & arg, string const &, string &)
980 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
981 Debug::showTags(lyxerr);
984 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
986 lyxerr.setLevel(Debug::value(arg));
987 Debug::showLevel(lyxerr, lyxerr.level());
992 int parse_help(string const &, string const &, string &)
995 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
996 "Command line switches (case sensitive):\n"
997 "\t-help summarize LyX usage\n"
998 "\t-userdir dir set user directory to dir\n"
999 "\t-sysdir dir set system directory to dir\n"
1000 "\t-geometry WxH+X+Y set geometry of the main window\n"
1001 "\t-dbg feature[,feature]...\n"
1002 " select the features to debug.\n"
1003 " Type `lyx -dbg' to see the list of features\n"
1004 "\t-x [--execute] command\n"
1005 " where command is a lyx command.\n"
1006 "\t-e [--export] fmt\n"
1007 " where fmt is the export format of choice.\n"
1008 " Look on Tools->Preferences->File formats->Format\n"
1009 " to get an idea which parameters should be passed.\n"
1010 " Note that the order of -e and -x switches matters.\n"
1011 "\t-i [--import] fmt file.xxx\n"
1012 " where fmt is the import format of choice\n"
1013 " and file.xxx is the file to be imported.\n"
1014 "\t-f [--force-overwrite] what\n"
1015 " where what is either `all' or `main'.\n"
1016 " Using `all', all files are overwritten during\n"
1017 " a batch export, otherwise only the main file will be.\n"
1018 " Anything else is equivalent to `all', but is not consumed.\n"
1019 "\t-batch execute commands without launching GUI and exit.\n"
1020 "\t-version summarize version and build info\n"
1021 "Check the LyX man page for more details.")) << endl;
1027 int parse_version(string const &, string const &, string &)
1029 lyxerr << "LyX " << lyx_version
1030 << " (" << lyx_release_date << ")" << endl;
1031 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1033 lyxerr << lyx_version_info << endl;
1039 int parse_sysdir(string const & arg, string const &, string &)
1042 Alert::error(_("No system directory"),
1043 _("Missing directory for -sysdir switch"));
1046 cl_system_support = arg;
1051 int parse_userdir(string const & arg, string const &, string &)
1054 Alert::error(_("No user directory"),
1055 _("Missing directory for -userdir switch"));
1058 cl_user_support = arg;
1063 int parse_execute(string const & arg, string const &, string & batch)
1066 Alert::error(_("Incomplete command"),
1067 _("Missing command string after --execute switch"));
1075 int parse_export(string const & type, string const &, string & batch)
1078 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1079 "--export switch")) << endl;
1082 batch = "buffer-export " + type;
1088 int parse_import(string const & type, string const & file, string & batch)
1091 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1092 "--import switch")) << endl;
1096 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1100 batch = "buffer-import " + type + ' ' + file;
1105 int parse_geometry(string const & arg1, string const &, string &)
1108 // don't remove "-geometry", it will be pruned out later in the
1109 // frontend if need be.
1114 int parse_batch(string const &, string const &, string &)
1121 int parse_force(string const & arg, string const &, string &)
1124 force_overwrite = ALL_FILES;
1126 } else if (arg == "main") {
1127 force_overwrite = MAIN_FILE;
1130 force_overwrite = ALL_FILES;
1138 void LyX::easyParse(int & argc, char * argv[])
1140 map<string, cmd_helper> cmdmap;
1142 cmdmap["-dbg"] = parse_dbg;
1143 cmdmap["-help"] = parse_help;
1144 cmdmap["--help"] = parse_help;
1145 cmdmap["-version"] = parse_version;
1146 cmdmap["--version"] = parse_version;
1147 cmdmap["-sysdir"] = parse_sysdir;
1148 cmdmap["-userdir"] = parse_userdir;
1149 cmdmap["-x"] = parse_execute;
1150 cmdmap["--execute"] = parse_execute;
1151 cmdmap["-e"] = parse_export;
1152 cmdmap["--export"] = parse_export;
1153 cmdmap["-i"] = parse_import;
1154 cmdmap["--import"] = parse_import;
1155 cmdmap["-geometry"] = parse_geometry;
1156 cmdmap["-batch"] = parse_batch;
1157 cmdmap["-f"] = parse_force;
1158 cmdmap["--force-overwrite"] = parse_force;
1160 for (int i = 1; i < argc; ++i) {
1161 map<string, cmd_helper>::const_iterator it
1162 = cmdmap.find(argv[i]);
1164 // don't complain if not found - may be parsed later
1165 if (it == cmdmap.end())
1169 (i + 1 < argc) ? os::utf8_argv(i + 1) : string();
1171 (i + 2 < argc) ? os::utf8_argv(i + 2) : string();
1174 int const remove = 1 + it->second(arg, arg2, batch);
1176 pimpl_->batch_commands.push_back(batch);
1178 // Now, remove used arguments by shifting
1179 // the following ones remove places down.
1181 os::remove_internal_args(i, remove);
1183 for (int j = i; j < argc; ++j)
1184 argv[j] = argv[j + remove];
1191 FuncStatus getStatus(FuncRequest const & action)
1193 LASSERT(theApp(), /**/);
1194 return theApp()->getStatus(action);
1198 void dispatch(FuncRequest const & action)
1200 LASSERT(theApp(), /**/);
1201 return theApp()->dispatch(action);
1205 void dispatch(FuncRequest const & action, DispatchResult & dr)
1207 LASSERT(theApp(), /**/);
1208 return theApp()->dispatch(action, dr);
1212 BufferList & theBufferList()
1214 LASSERT(singleton_, /**/);
1215 return singleton_->pimpl_->buffer_list_;
1219 Server & theServer()
1221 // FIXME: this should not be use_gui dependent
1222 LASSERT(use_gui, /**/);
1223 LASSERT(singleton_, /**/);
1224 return *singleton_->pimpl_->lyx_server_.get();
1228 ServerSocket & theServerSocket()
1230 // FIXME: this should not be use_gui dependent
1231 LASSERT(use_gui, /**/);
1232 LASSERT(singleton_, /**/);
1233 return *singleton_->pimpl_->lyx_socket_.get();
1237 KeyMap & theTopLevelKeymap()
1239 LASSERT(singleton_, /**/);
1240 return singleton_->pimpl_->toplevel_keymap_;
1244 Converters & theConverters()
1246 LASSERT(singleton_, /**/);
1247 return singleton_->pimpl_->converters_;
1251 Converters & theSystemConverters()
1253 LASSERT(singleton_, /**/);
1254 return singleton_->pimpl_->system_converters_;
1258 Movers & theMovers()
1260 LASSERT(singleton_, /**/);
1261 return singleton_->pimpl_->movers_;
1265 Mover const & getMover(string const & fmt)
1267 LASSERT(singleton_, /**/);
1268 return singleton_->pimpl_->movers_(fmt);
1272 void setMover(string const & fmt, string const & command)
1274 LASSERT(singleton_, /**/);
1275 singleton_->pimpl_->movers_.set(fmt, command);
1279 Movers & theSystemMovers()
1281 LASSERT(singleton_, /**/);
1282 return singleton_->pimpl_->system_movers_;
1286 Messages const & getMessages(string const & language)
1288 LASSERT(singleton_, /**/);
1289 return singleton_->messages(language);
1293 Messages const & getGuiMessages()
1295 LASSERT(singleton_, /**/);
1296 return singleton_->pimpl_->messages_["GUI"];
1300 graphics::Previews & thePreviews()
1302 LASSERT(singleton_, /**/);
1303 return singleton_->pimpl_->preview_;
1307 Session & theSession()
1309 LASSERT(singleton_, /**/);
1310 return *singleton_->pimpl_->session_.get();
1314 CmdDef & theTopLevelCmdDef()
1316 LASSERT(singleton_, /**/);
1317 return singleton_->pimpl_->toplevel_cmddef_;
1321 SpellChecker * theSpellChecker()
1323 if (!singleton_->pimpl_->spell_checker_)
1325 return singleton_->pimpl_->spell_checker_;
1329 void setSpellChecker()
1331 #if defined(USE_MACOSX_PACKAGING)
1332 if (lyxrc.spellchecker == "native") {
1333 if (!singleton_->pimpl_->apple_spell_checker_)
1334 singleton_->pimpl_->apple_spell_checker_ = new AppleSpellChecker();
1335 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->apple_spell_checker_;
1339 #if defined(USE_ASPELL)
1340 if (lyxrc.spellchecker == "aspell") {
1341 if (!singleton_->pimpl_->aspell_checker_)
1342 singleton_->pimpl_->aspell_checker_ = new AspellChecker();
1343 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1347 #if defined(USE_ENCHANT)
1348 if (lyxrc.spellchecker == "enchant") {
1349 if (!singleton_->pimpl_->enchant_checker_)
1350 singleton_->pimpl_->enchant_checker_ = new EnchantChecker();
1351 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1355 #if defined(USE_HUNSPELL)
1356 if (lyxrc.spellchecker == "hunspell") {
1357 if (!singleton_->pimpl_->hunspell_checker_)
1358 singleton_->pimpl_->hunspell_checker_ = new HunspellChecker();
1359 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1363 singleton_->pimpl_->spell_checker_ = 0;