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 "AspellChecker.h"
22 #include "BufferList.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
28 #include "EnchantChecker.h"
30 #include "ErrorList.h"
32 #include "FuncStatus.h"
33 #include "HunspellChecker.h"
36 #include "LayoutFile.h"
38 #include "LyXAction.h"
41 #include "ModuleList.h"
44 #include "ServerSocket.h"
47 #include "frontends/alert.h"
48 #include "frontends/Application.h"
50 #include "graphics/Previews.h"
52 #include "support/lassert.h"
53 #include "support/debug.h"
54 #include "support/environment.h"
55 #include "support/ExceptionMessage.h"
56 #include "support/filetools.h"
57 #include "support/gettext.h"
58 #include "support/lstrings.h"
59 #include "support/Messages.h"
60 #include "support/os.h"
61 #include "support/Package.h"
62 #include "support/Path.h"
63 #include "support/Systemcall.h"
65 #include <boost/bind.hpp>
66 #include <boost/scoped_ptr.hpp>
77 using namespace lyx::support;
81 namespace Alert = frontend::Alert;
82 namespace os = support::os;
86 // Are we using the GUI at all? We default to true and this is changed
87 // to false when the export feature is used.
93 // Filled with the command line arguments "foo" of "-sysdir foo" or
95 string cl_system_support;
96 string cl_user_support;
100 LyX * singleton_ = 0;
102 void showFileError(string const & error)
104 Alert::warning(_("Could not read configuration file"),
105 bformat(_("Error while reading the configuration file\n%1$s.\n"
106 "Please check your installation."), from_utf8(error)));
110 void reconfigureUserLyXDir()
112 string const configure_command = package().configure_command();
114 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
115 PathChanger p(package().user_support());
117 one.startscript(Systemcall::Wait, configure_command);
118 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
123 /// The main application class private implementation.
126 Impl() : spell_checker_(0), aspell_checker_(0), enchant_checker_(0), hunspell_checker_(0)
128 // Set the default User Interface language as soon as possible.
129 // The language used will be derived from the environment
131 messages_["GUI"] = Messages();
136 delete aspell_checker_;
137 delete enchant_checker_;
138 delete hunspell_checker_;
141 /// our function handler
144 BufferList buffer_list_;
146 KeyMap toplevel_keymap_;
148 CmdDef toplevel_cmddef_;
150 boost::scoped_ptr<Server> lyx_server_;
152 boost::scoped_ptr<ServerSocket> lyx_socket_;
154 boost::scoped_ptr<frontend::Application> application_;
155 /// lyx session, containing lastfiles, lastfilepos, and lastopened
156 boost::scoped_ptr<Session> session_;
158 /// Files to load at start.
159 vector<string> files_to_load_;
161 /// The messages translators.
162 map<string, Messages> messages_;
164 /// The file converters.
165 Converters converters_;
167 // The system converters copy after reading lyxrc.defaults.
168 Converters system_converters_;
173 Movers system_movers_;
175 /// has this user started lyx for the first time?
177 /// the parsed command line batch command if any
178 vector<string> batch_commands;
181 graphics::Previews preview_;
183 SpellChecker * spell_checker_;
185 SpellChecker * aspell_checker_;
187 SpellChecker * enchant_checker_;
189 SpellChecker * hunspell_checker_;
193 frontend::Application * theApp()
196 return singleton_->pimpl_->application_.get();
209 void lyx_exit(int exit_code)
212 // Something wrong happened so better save everything, just in
217 // Properly crash in debug mode in order to get a useful backtrace.
221 // In release mode, try to exit gracefully.
223 theApp()->exit(exit_code);
237 Messages & LyX::messages(string const & language)
239 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
241 if (it != pimpl_->messages_.end())
244 pair<map<string, Messages>::iterator, bool> result =
245 pimpl_->messages_.insert(make_pair(language, Messages(language)));
247 LASSERT(result.second, /**/);
248 return result.first->second;
252 void setRcGuiLanguage()
254 LASSERT(singleton_, /**/);
255 if (lyxrc.gui_language == "auto")
257 Language const * language = languages.getLanguage(lyxrc.gui_language);
259 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
260 if (!setEnv("LANGUAGE", language->code()))
261 LYXERR(Debug::LOCALE, "\t... failed!");
263 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
264 if (!setEnv("LC_ALL", "en_US"))
265 LYXERR(Debug::LOCALE, "\t... failed!");
267 singleton_->pimpl_->messages_["GUI"] = Messages();
271 int LyX::exec(int & argc, char * argv[])
273 // Here we need to parse the command line. At least
274 // we need to parse for "-dbg" and "-help"
275 easyParse(argc, argv);
278 init_package(to_utf8(from_local8bit(argv[0])),
279 cl_system_support, cl_user_support,
280 top_build_dir_is_one_level_up);
281 } catch (ExceptionMessage const & message) {
282 if (message.type_ == ErrorException) {
283 Alert::error(message.title_, message.details_);
285 } else if (message.type_ == WarningException) {
286 Alert::warning(message.title_, message.details_);
290 // Reinit the messages machinery in case package() knows
291 // something interesting about the locale directory.
295 // FIXME: create a ConsoleApplication
296 int exit_status = init(argc, argv);
302 // this is correct, since return values are inverted.
303 exit_status = !loadFiles();
305 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
310 BufferList::iterator begin = pimpl_->buffer_list_.begin();
312 bool final_success = false;
313 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
315 if (buf != buf->masterBuffer())
317 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
318 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
320 for (; bcit != bcend; bcit++) {
321 LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit);
322 buf->dispatch(*bcit, dr);
323 final_success |= !dr.error();
327 return !final_success;
330 // Let the frontend parse and remove all arguments that it knows
331 pimpl_->application_.reset(createApplication(argc, argv));
333 // Reestablish our defaults, as Qt overwrites them
334 // after createApplication()
337 // Parse and remove all known arguments in the LyX singleton
338 // Give an error for all remaining ones.
339 int exit_status = init(argc, argv);
341 // Kill the application object before exiting.
342 pimpl_->application_.reset();
349 /* Create a CoreApplication class that will provide the main event loop
350 * and the socket callback registering. With Qt4, only QtCore
351 * library would be needed.
352 * When this is done, a server_mode could be created and the following two
353 * line would be moved out from here.
355 // Note: socket callback must be registered after init(argc, argv)
356 // such that package().temp_dir() is properly initialized.
357 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
358 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
359 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
361 // Start the real execution loop.
362 exit_status = pimpl_->application_->exec();
370 void LyX::prepareExit()
372 // Clear the clipboard and selection stack:
373 cap::clearCutStack();
374 cap::clearSelection();
376 // Write the index file of the converter cache
377 ConverterCache::get().writeIndex();
379 // close buffers first
380 pimpl_->buffer_list_.closeAll();
382 // register session changes and shutdown server and socket
384 if (pimpl_->session_)
385 pimpl_->session_->writeFile();
386 pimpl_->session_.reset();
387 pimpl_->lyx_server_.reset();
388 pimpl_->lyx_socket_.reset();
391 // do any other cleanup procedures now
392 if (package().temp_dir() != package().system_temp_dir()) {
393 string const abs_tmpdir = package().temp_dir().absFilename();
394 if (!contains(package().temp_dir().absFilename(), "lyx_tmpdir")) {
395 docstring const msg =
396 bformat(_("%1$s does not appear like a LyX created temporary directory."),
397 from_utf8(abs_tmpdir));
398 Alert::warning(_("Cannot remove temporary directory"), msg);
400 LYXERR(Debug::INFO, "Deleting tmp dir "
401 << package().temp_dir().absFilename());
402 if (!package().temp_dir().destroyDirectory()) {
403 docstring const msg =
404 bformat(_("Unable to remove the temporary directory %1$s"),
405 from_utf8(package().temp_dir().absFilename()));
406 Alert::warning(_("Unable to remove temporary directory"), msg);
411 // Kill the application object before exiting. This avoids crashes
412 // when exiting on Linux.
413 if (pimpl_->application_)
414 pimpl_->application_.reset();
418 void LyX::earlyExit(int status)
420 LASSERT(pimpl_->application_.get(), /**/);
421 // LyX::pimpl_::application_ is not initialised at this
422 // point so it's safe to just exit after some cleanup.
428 int LyX::init(int & argc, char * argv[])
430 // check for any spurious extra arguments
431 // other than documents
432 for (int argi = 1; argi < argc ; ++argi) {
433 if (argv[argi][0] == '-') {
435 bformat(_("Wrong command line option `%1$s'. Exiting."),
436 from_utf8(argv[argi]))) << endl;
441 // Initialization of LyX (reads lyxrc and more)
442 LYXERR(Debug::INIT, "Initializing LyX::init...");
443 bool success = init();
444 LYXERR(Debug::INIT, "Initializing LyX::init...done");
448 // Remaining arguments are assumed to be files to load.
449 for (int argi = argc - 1; argi >= 1; --argi)
450 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
453 pimpl_->files_to_load_.push_back(
454 i18nLibFileSearch("examples", "splash.lyx").absFilename());
461 bool LyX::loadFiles()
463 LASSERT(!use_gui, /**/);
465 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
466 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
468 for (; it != end; ++it) {
469 // get absolute path of file and add ".lyx" to
470 // the filename if necessary
471 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
477 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
478 if (buf->loadLyXFile(fname)) {
479 ErrorList const & el = buf->errorList("Parse");
481 for_each(el.begin(), el.end(),
482 boost::bind(&LyX::printError, this, _1));
485 pimpl_->buffer_list_.release(buf);
493 void execBatchCommands()
495 LASSERT(singleton_, /**/);
496 singleton_->execCommands();
500 void LyX::execCommands()
502 // The advantage of doing this here is that the event loop
503 // is already started. So any need for interaction will be
506 // if reconfiguration is needed.
507 while (LayoutFileList::get().empty()) {
508 switch (Alert::prompt(
509 _("No textclass is found"),
510 _("LyX cannot continue because no textclass is found. "
511 "You can either reconfigure normally, or reconfigure using "
512 "default textclasses, or quit LyX."),
519 // regular reconfigure
520 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
523 // reconfigure --without-latex-config
524 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
525 " --without-latex-config"));
528 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
533 // create the first main window
534 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
536 if (!pimpl_->files_to_load_.empty()) {
537 // if some files were specified at command-line we assume that the
538 // user wants to edit *these* files and not to restore the session.
539 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
540 pimpl_->lyxfunc_.dispatch(
541 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
543 // clear this list to save a few bytes of RAM
544 pimpl_->files_to_load_.clear();
546 pimpl_->application_->restoreGuiSession();
548 // Execute batch commands if available
549 if (pimpl_->batch_commands.empty())
552 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
553 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
554 for (; bcit != bcend; bcit++) {
555 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
556 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(*bcit));
564 The SIGHUP signal does not exist on Windows and does not need to be handled.
566 Windows handles SIGFPE and SIGSEGV signals as expected.
568 Ctrl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
569 cause a new thread to be spawned. This may well result in unexpected
570 behaviour by the single-threaded LyX.
572 SIGTERM signals will come only from another process actually sending
573 that signal using 'raise' in Windows' POSIX compatability layer. It will
574 not come from the general "terminate process" methods that everyone
575 actually uses (and which can't be trapped). Killing an app 'politely' on
576 Windows involves first sending a WM_CLOSE message, something that is
577 caught already by the Qt frontend.
579 For more information see:
581 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
582 ...signals are mostly useless on Windows for a variety of reasons that are
585 'UNIX Application Migration Guide, Chapter 9'
586 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
588 'How To Terminate an Application "Cleanly" in Win32'
589 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
593 static void error_handler(int err_sig)
595 // Throw away any signals other than the first one received.
596 static sig_atomic_t handling_error = false;
599 handling_error = true;
601 // We have received a signal indicating a fatal error, so
602 // try and save the data ASAP.
605 // These lyxerr calls may or may not work:
607 // Signals are asynchronous, so the main program may be in a very
608 // fragile state when a signal is processed and thus while a signal
609 // handler function executes.
610 // In general, therefore, we should avoid performing any
611 // I/O operations or calling most library and system functions from
614 // This shouldn't matter here, however, as we've already invoked
619 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
623 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
626 lyxerr << "\nlyx: SIGSEGV signal caught\n"
627 "Sorry, you have found a bug in LyX. "
628 "Please read the bug-reporting instructions "
629 "in Help->Introduction and send us a bug report, "
630 "if necessary. Thanks !\nBye." << endl;
638 // Deinstall the signal handlers
640 signal(SIGHUP, SIG_DFL);
642 signal(SIGINT, SIG_DFL);
643 signal(SIGFPE, SIG_DFL);
644 signal(SIGSEGV, SIG_DFL);
645 signal(SIGTERM, SIG_DFL);
648 if (err_sig == SIGSEGV ||
649 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
651 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
660 void LyX::printError(ErrorItem const & ei)
662 docstring tmp = _("LyX: ") + ei.error + char_type(':')
664 cerr << to_utf8(tmp) << endl;
671 signal(SIGHUP, error_handler);
673 signal(SIGFPE, error_handler);
674 signal(SIGSEGV, error_handler);
675 signal(SIGINT, error_handler);
676 signal(SIGTERM, error_handler);
677 // SIGPIPE can be safely ignored.
679 lyxrc.tempdir_path = package().temp_dir().absFilename();
680 lyxrc.document_path = package().document_dir().absFilename();
682 if (lyxrc.example_path.empty()) {
683 lyxrc.example_path = addPath(package().system_support().absFilename(),
686 if (lyxrc.template_path.empty()) {
687 lyxrc.template_path = addPath(package().system_support().absFilename(),
692 // Read configuration files
695 // This one may have been distributed along with LyX.
696 if (!readRcFile("lyxrc.dist"))
699 // Set the language defined by the distributor.
702 // Set the PATH correctly.
703 #if !defined (USE_POSIX_PACKAGING)
704 // Add the directory containing the LyX executable to the path
705 // so that LyX can find things like tex2lyx.
706 if (package().build_support().empty())
707 prependEnvPath("PATH", package().binary_dir().absFilename());
709 if (!lyxrc.path_prefix.empty())
710 prependEnvPath("PATH", lyxrc.path_prefix);
712 // Check that user LyX directory is ok.
713 if (queryUserLyXDir(package().explicit_user_support()))
714 reconfigureUserLyXDir();
716 // no need for a splash when there is no GUI
721 // This one is generated in user_support directory by lib/configure.py.
722 if (!readRcFile("lyxrc.defaults"))
725 // Query the OS to know what formats are viewed natively
726 formats.setAutoOpen();
728 // Read lyxrc.dist again to be able to override viewer auto-detection.
729 readRcFile("lyxrc.dist");
731 // Set again the language defined by the distributor.
734 system_lyxrc = lyxrc;
735 system_formats = formats;
736 pimpl_->system_converters_ = pimpl_->converters_;
737 pimpl_->system_movers_ = pimpl_->movers_;
738 system_lcolor = lcolor;
740 // This one is edited through the preferences dialog.
741 if (!readRcFile("preferences"))
744 if (!readEncodingsFile("encodings", "unicodesymbols"))
746 if (!readLanguagesFile("languages"))
749 // Set the language defined by the user.
753 LYXERR(Debug::INIT, "Reading layouts...");
757 theModuleList.read();
759 // read keymap and ui files in batch mode as well
760 // because InsetInfo needs to know these to produce
761 // the correct output
763 // Set up command definitions
764 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
767 pimpl_->toplevel_keymap_.read("site");
768 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
769 // load user bind file user.bind
770 pimpl_->toplevel_keymap_.read("user", 0, KeyMap::MissingOK);
772 if (lyxerr.debugging(Debug::LYXRC))
775 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
776 if (!lyxrc.path_prefix.empty())
777 prependEnvPath("PATH", lyxrc.path_prefix);
779 FileName const document_path(lyxrc.document_path);
780 if (document_path.exists() && document_path.isDirectory())
781 package().document_dir() = document_path;
783 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
784 if (package().temp_dir().empty()) {
785 Alert::error(_("Could not create temporary directory"),
786 bformat(_("Could not create a temporary directory in\n"
788 "Make sure that this path exists and is writable and try again."),
789 from_utf8(lyxrc.tempdir_path)));
790 // createLyXTmpDir() tries sufficiently hard to create a
791 // usable temp dir, so the probability to come here is
792 // close to zero. We therefore don't try to overcome this
793 // problem with e.g. asking the user for a new path and
794 // trying again but simply exit.
798 LYXERR(Debug::INIT, "LyX tmp dir: `"
799 << package().temp_dir().absFilename() << '\'');
801 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
802 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
804 // This must happen after package initialization and after lyxrc is
805 // read, therefore it can't be done by a static object.
806 ConverterCache::init();
812 void emergencyCleanup()
814 // what to do about tmpfiles is non-obvious. we would
815 // like to delete any we find, but our lyxdir might
816 // contain documents etc. which might be helpful on
819 singleton_->pimpl_->buffer_list_.emergencyWriteAll();
821 if (singleton_->pimpl_->lyx_server_)
822 singleton_->pimpl_->lyx_server_->emergencyCleanup();
823 singleton_->pimpl_->lyx_server_.reset();
824 singleton_->pimpl_->lyx_socket_.reset();
829 // return true if file does not exist or is older than configure.py.
830 static bool needsUpdate(string const & file)
832 // We cannot initialize configure_script directly because the package
833 // is not initialized yet when static objects are constructed.
834 static FileName configure_script;
835 static bool firstrun = true;
838 FileName(addName(package().system_support().absFilename(),
844 FileName(addName(package().user_support().absFilename(), file));
845 return !absfile.exists()
846 || configure_script.lastModified() > absfile.lastModified();
850 bool LyX::queryUserLyXDir(bool explicit_userdir)
852 // Does user directory exist?
853 FileName const sup = package().user_support();
854 if (sup.exists() && sup.isDirectory()) {
857 return needsUpdate("lyxrc.defaults")
858 || needsUpdate("lyxmodules.lst")
859 || needsUpdate("textclass.lst")
860 || needsUpdate("packages.lst");
863 first_start = !explicit_userdir;
865 // If the user specified explicitly a directory, ask whether
866 // to create it. If the user says "no", then exit.
867 if (explicit_userdir &&
869 _("Missing user LyX directory"),
870 bformat(_("You have specified a non-existent user "
871 "LyX directory, %1$s.\n"
872 "It is needed to keep your own configuration."),
873 from_utf8(package().user_support().absFilename())),
875 _("&Create directory"),
877 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
878 earlyExit(EXIT_FAILURE);
881 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
882 from_utf8(sup.absFilename()))) << endl;
884 if (!sup.createDirectory(0755)) {
885 // Failed, so let's exit.
886 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
888 earlyExit(EXIT_FAILURE);
895 bool LyX::readRcFile(string const & name)
897 LYXERR(Debug::INIT, "About to read " << name << "... ");
899 FileName const lyxrc_path = libFileSearch(string(), name);
900 if (!lyxrc_path.empty()) {
901 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
902 if (lyxrc.read(lyxrc_path) < 0) {
907 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
912 // Read the languages file `name'
913 bool LyX::readLanguagesFile(string const & name)
915 LYXERR(Debug::INIT, "About to read " << name << "...");
917 FileName const lang_path = libFileSearch(string(), name);
918 if (lang_path.empty()) {
922 languages.read(lang_path);
927 // Read the encodings file `name'
928 bool LyX::readEncodingsFile(string const & enc_name,
929 string const & symbols_name)
931 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
932 << symbols_name << "...");
934 FileName const symbols_path = libFileSearch(string(), symbols_name);
935 if (symbols_path.empty()) {
936 showFileError(symbols_name);
940 FileName const enc_path = libFileSearch(string(), enc_name);
941 if (enc_path.empty()) {
942 showFileError(enc_name);
945 encodings.read(enc_path, symbols_path);
952 /// return the the number of arguments consumed
953 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
955 int parse_dbg(string const & arg, string const &, string &)
958 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
959 Debug::showTags(lyxerr);
962 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
964 lyxerr.setLevel(Debug::value(arg));
965 Debug::showLevel(lyxerr, lyxerr.level());
970 int parse_help(string const &, string const &, string &)
973 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
974 "Command line switches (case sensitive):\n"
975 "\t-help summarize LyX usage\n"
976 "\t-userdir dir set user directory to dir\n"
977 "\t-sysdir dir set system directory to dir\n"
978 "\t-geometry WxH+X+Y set geometry of the main window\n"
979 "\t-dbg feature[,feature]...\n"
980 " select the features to debug.\n"
981 " Type `lyx -dbg' to see the list of features\n"
982 "\t-x [--execute] command\n"
983 " where command is a lyx command.\n"
984 "\t-e [--export] fmt\n"
985 " where fmt is the export format of choice.\n"
986 " Look on Tools->Preferences->File formats->Format\n"
987 " to get an idea which parameters should be passed.\n"
988 " Note that the order of -e and -x switches matters.\n"
989 "\t-i [--import] fmt file.xxx\n"
990 " where fmt is the import format of choice\n"
991 " and file.xxx is the file to be imported.\n"
992 "\t--batch execute commands and exit\n"
993 "\t-version summarize version and build info\n"
994 "Check the LyX man page for more details.")) << endl;
1000 int parse_version(string const &, string const &, string &)
1002 lyxerr << "LyX " << lyx_version
1003 << " (" << lyx_release_date << ")" << endl;
1004 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1006 lyxerr << lyx_version_info << endl;
1012 int parse_sysdir(string const & arg, string const &, string &)
1015 Alert::error(_("No system directory"),
1016 _("Missing directory for -sysdir switch"));
1019 cl_system_support = arg;
1024 int parse_userdir(string const & arg, string const &, string &)
1027 Alert::error(_("No user directory"),
1028 _("Missing directory for -userdir switch"));
1031 cl_user_support = arg;
1036 int parse_execute(string const & arg, string const &, string & batch)
1039 Alert::error(_("Incomplete command"),
1040 _("Missing command string after --execute switch"));
1048 int parse_export(string const & type, string const &, string & batch)
1051 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1052 "--export switch")) << endl;
1055 batch = "buffer-export " + type;
1061 int parse_import(string const & type, string const & file, string & batch)
1064 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1065 "--import switch")) << endl;
1069 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1073 batch = "buffer-import " + type + ' ' + file;
1078 int parse_geometry(string const & arg1, string const &, string &)
1081 // don't remove "-geometry", it will be pruned out later in the
1082 // frontend if need be.
1087 int parse_batch(string const &, string const &, string &)
1097 void LyX::easyParse(int & argc, char * argv[])
1099 map<string, cmd_helper> cmdmap;
1101 cmdmap["-dbg"] = parse_dbg;
1102 cmdmap["-help"] = parse_help;
1103 cmdmap["--help"] = parse_help;
1104 cmdmap["-version"] = parse_version;
1105 cmdmap["--version"] = parse_version;
1106 cmdmap["-sysdir"] = parse_sysdir;
1107 cmdmap["-userdir"] = parse_userdir;
1108 cmdmap["-x"] = parse_execute;
1109 cmdmap["--execute"] = parse_execute;
1110 cmdmap["-e"] = parse_export;
1111 cmdmap["--export"] = parse_export;
1112 cmdmap["-i"] = parse_import;
1113 cmdmap["--import"] = parse_import;
1114 cmdmap["-geometry"] = parse_geometry;
1115 cmdmap["--batch"] = parse_batch;
1117 for (int i = 1; i < argc; ++i) {
1118 map<string, cmd_helper>::const_iterator it
1119 = cmdmap.find(argv[i]);
1121 // don't complain if not found - may be parsed later
1122 if (it == cmdmap.end())
1126 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1128 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1131 int const remove = 1 + it->second(arg, arg2, batch);
1133 pimpl_->batch_commands.push_back(batch);
1135 // Now, remove used arguments by shifting
1136 // the following ones remove places down.
1139 for (int j = i; j < argc; ++j)
1140 argv[j] = argv[j + remove];
1147 FuncStatus getStatus(FuncRequest const & action)
1149 LASSERT(singleton_, /**/);
1150 return singleton_->pimpl_->lyxfunc_.getStatus(action);
1154 void dispatch(FuncRequest const & action)
1156 LASSERT(singleton_, /**/);
1157 singleton_->pimpl_->lyxfunc_.dispatch(action);
1161 BufferList & theBufferList()
1163 LASSERT(singleton_, /**/);
1164 return singleton_->pimpl_->buffer_list_;
1168 LyXFunc & theLyXFunc()
1170 LASSERT(singleton_, /**/);
1171 return singleton_->pimpl_->lyxfunc_;
1175 Server & theServer()
1177 // FIXME: this should not be use_gui dependent
1178 LASSERT(use_gui, /**/);
1179 LASSERT(singleton_, /**/);
1180 return *singleton_->pimpl_->lyx_server_.get();
1184 ServerSocket & theServerSocket()
1186 // FIXME: this should not be use_gui dependent
1187 LASSERT(use_gui, /**/);
1188 LASSERT(singleton_, /**/);
1189 return *singleton_->pimpl_->lyx_socket_.get();
1193 KeyMap & theTopLevelKeymap()
1195 LASSERT(singleton_, /**/);
1196 return singleton_->pimpl_->toplevel_keymap_;
1200 Converters & theConverters()
1202 LASSERT(singleton_, /**/);
1203 return singleton_->pimpl_->converters_;
1207 Converters & theSystemConverters()
1209 LASSERT(singleton_, /**/);
1210 return singleton_->pimpl_->system_converters_;
1214 Movers & theMovers()
1216 LASSERT(singleton_, /**/);
1217 return singleton_->pimpl_->movers_;
1221 Mover const & getMover(string const & fmt)
1223 LASSERT(singleton_, /**/);
1224 return singleton_->pimpl_->movers_(fmt);
1228 void setMover(string const & fmt, string const & command)
1230 LASSERT(singleton_, /**/);
1231 singleton_->pimpl_->movers_.set(fmt, command);
1235 Movers & theSystemMovers()
1237 LASSERT(singleton_, /**/);
1238 return singleton_->pimpl_->system_movers_;
1242 Messages & getMessages(string const & language)
1244 LASSERT(singleton_, /**/);
1245 return singleton_->messages(language);
1249 Messages & getGuiMessages()
1251 LASSERT(singleton_, /**/);
1252 return singleton_->pimpl_->messages_["GUI"];
1256 graphics::Previews & thePreviews()
1258 LASSERT(singleton_, /**/);
1259 return singleton_->pimpl_->preview_;
1263 Session & theSession()
1265 LASSERT(singleton_, /**/);
1266 return *singleton_->pimpl_->session_.get();
1270 CmdDef & theTopLevelCmdDef()
1272 LASSERT(singleton_, /**/);
1273 return singleton_->pimpl_->toplevel_cmddef_;
1277 SpellChecker * theSpellChecker()
1279 if (!singleton_->pimpl_->spell_checker_)
1281 return singleton_->pimpl_->spell_checker_;
1285 void setSpellChecker()
1287 #if defined(USE_ASPELL)
1288 if (lyxrc.spellchecker == "aspell") {
1289 if (!singleton_->pimpl_->aspell_checker_)
1290 singleton_->pimpl_->aspell_checker_ = new AspellChecker();
1291 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->aspell_checker_;
1295 #if defined(USE_ENCHANT)
1296 if (lyxrc.spellchecker == "enchant") {
1297 if (!singleton_->pimpl_->enchant_checker_)
1298 singleton_->pimpl_->enchant_checker_ = new EnchantChecker();
1299 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->enchant_checker_;
1303 #if defined(USE_HUNSPELL)
1304 if (lyxrc.spellchecker == "hunspell") {
1305 if (!singleton_->pimpl_->hunspell_checker_)
1306 singleton_->pimpl_->hunspell_checker_ = new HunspellChecker();
1307 singleton_->pimpl_->spell_checker_ = singleton_->pimpl_->hunspell_checker_;
1311 singleton_->pimpl_->spell_checker_ = 0;