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 "LayoutFile.h"
22 #include "BufferList.h"
25 #include "ConverterCache.h"
26 #include "Converter.h"
27 #include "CutAndPaste.h"
29 #include "ErrorList.h"
31 #include "FuncStatus.h"
35 #include "LyXAction.h"
38 #include "ModuleList.h"
41 #include "ServerSocket.h"
44 #include "frontends/alert.h"
45 #include "frontends/Application.h"
47 #include "support/lassert.h"
48 #include "support/debug.h"
49 #include "support/environment.h"
50 #include "support/ExceptionMessage.h"
51 #include "support/filetools.h"
52 #include "support/gettext.h"
53 #include "support/lstrings.h"
54 #include "support/Messages.h"
55 #include "support/os.h"
56 #include "support/Package.h"
57 #include "support/Path.h"
58 #include "support/Systemcall.h"
60 #include <boost/bind.hpp>
61 #include <boost/scoped_ptr.hpp>
72 using namespace lyx::support;
76 namespace Alert = frontend::Alert;
77 namespace os = support::os;
81 // Are we using the GUI at all? We default to true and this is changed
82 // to false when the export feature is used.
88 // Filled with the command line arguments "foo" of "-sysdir foo" or
90 string cl_system_support;
91 string cl_user_support;
97 void showFileError(string const & error)
99 Alert::warning(_("Could not read configuration file"),
100 bformat(_("Error while reading the configuration file\n%1$s.\n"
101 "Please check your installation."), from_utf8(error)));
105 void reconfigureUserLyXDir()
107 string const configure_command = package().configure_command();
109 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
110 PathChanger p(package().user_support());
112 one.startscript(Systemcall::Wait, configure_command);
113 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
119 /// The main application class private implementation.
124 // Set the default User Interface language as soon as possible.
125 // The language used will be derived from the environment
127 messages_["GUI"] = Messages();
129 /// our function handler
132 BufferList buffer_list_;
134 KeyMap toplevel_keymap_;
136 CmdDef toplevel_cmddef_;
138 boost::scoped_ptr<Server> lyx_server_;
140 boost::scoped_ptr<ServerSocket> lyx_socket_;
142 boost::scoped_ptr<frontend::Application> application_;
143 /// lyx session, containing lastfiles, lastfilepos, and lastopened
144 boost::scoped_ptr<Session> session_;
146 /// Files to load at start.
147 vector<string> files_to_load_;
149 /// The messages translators.
150 map<string, Messages> messages_;
152 /// The file converters.
153 Converters converters_;
155 // The system converters copy after reading lyxrc.defaults.
156 Converters system_converters_;
161 Movers system_movers_;
163 /// has this user started lyx for the first time?
165 /// the parsed command line batch command if any
166 vector<string> batch_commands;
170 frontend::Application * theApp()
173 return singleton_->pimpl_->application_.get();
186 void LyX::exit(int exit_code) const
189 // Something wrong happened so better save everything, just in
194 // Properly crash in debug mode in order to get a useful backtrace.
198 // In release mode, try to exit gracefully.
200 theApp()->exit(exit_code);
208 LASSERT(singleton_, /**/);
213 LyX const & LyX::cref()
215 LASSERT(singleton_, /**/);
228 BufferList & LyX::bufferList()
230 return pimpl_->buffer_list_;
234 BufferList const & LyX::bufferList() const
236 return pimpl_->buffer_list_;
240 Session & LyX::session()
242 LASSERT(pimpl_->session_.get(), /**/);
243 return *pimpl_->session_.get();
247 Session const & LyX::session() const
249 LASSERT(pimpl_->session_.get(), /**/);
250 return *pimpl_->session_.get();
254 LyXFunc & LyX::lyxFunc()
256 return pimpl_->lyxfunc_;
260 LyXFunc const & LyX::lyxFunc() const
262 return pimpl_->lyxfunc_;
266 Server & LyX::server()
268 LASSERT(pimpl_->lyx_server_.get(), /**/);
269 return *pimpl_->lyx_server_.get();
273 Server const & LyX::server() const
275 LASSERT(pimpl_->lyx_server_.get(), /**/);
276 return *pimpl_->lyx_server_.get();
280 ServerSocket & LyX::socket()
282 LASSERT(pimpl_->lyx_socket_.get(), /**/);
283 return *pimpl_->lyx_socket_.get();
287 ServerSocket const & LyX::socket() const
289 LASSERT(pimpl_->lyx_socket_.get(), /**/);
290 return *pimpl_->lyx_socket_.get();
294 frontend::Application & LyX::application()
296 LASSERT(pimpl_->application_.get(), /**/);
297 return *pimpl_->application_.get();
301 frontend::Application const & LyX::application() const
303 LASSERT(pimpl_->application_.get(), /**/);
304 return *pimpl_->application_.get();
308 CmdDef & LyX::topLevelCmdDef()
310 return pimpl_->toplevel_cmddef_;
314 Converters & LyX::converters()
316 return pimpl_->converters_;
320 Converters & LyX::systemConverters()
322 return pimpl_->system_converters_;
326 Messages & LyX::getMessages(string const & language)
328 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
330 if (it != pimpl_->messages_.end())
333 pair<map<string, Messages>::iterator, bool> result =
334 pimpl_->messages_.insert(make_pair(language, Messages(language)));
336 LASSERT(result.second, /**/);
337 return result.first->second;
341 Messages & LyX::getGuiMessages()
343 return pimpl_->messages_["GUI"];
347 void LyX::setRcGuiLanguage()
349 if (lyxrc.gui_language == "auto")
351 Language const * language = languages.getLanguage(lyxrc.gui_language);
352 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
353 if (!setEnv("LANGUAGE", language->code()))
354 LYXERR(Debug::LOCALE, "\t... failed!");
355 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
356 if (!setEnv("LC_ALL", "en_US"))
357 LYXERR(Debug::LOCALE, "\t... failed!");
358 pimpl_->messages_["GUI"] = Messages();
362 int LyX::exec(int & argc, char * argv[])
364 // Here we need to parse the command line. At least
365 // we need to parse for "-dbg" and "-help"
366 easyParse(argc, argv);
369 init_package(to_utf8(from_local8bit(argv[0])),
370 cl_system_support, cl_user_support,
371 top_build_dir_is_one_level_up);
372 } catch (ExceptionMessage const & message) {
373 if (message.type_ == ErrorException) {
374 Alert::error(message.title_, message.details_);
376 } else if (message.type_ == WarningException) {
377 Alert::warning(message.title_, message.details_);
381 // Reinit the messages machinery in case package() knows
382 // something interesting about the locale directory.
386 // FIXME: create a ConsoleApplication
387 int exit_status = init(argc, argv);
393 // this is correct, since return values are inverted.
394 exit_status = !loadFiles();
396 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
401 BufferList::iterator begin = pimpl_->buffer_list_.begin();
403 bool final_success = false;
404 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
406 if (buf != buf->masterBuffer())
408 bool success = false;
409 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
410 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
411 for (; bcit != bcend; bcit++) {
412 buf->dispatch(*bcit, &success);
413 final_success |= success;
417 return !final_success;
420 // Let the frontend parse and remove all arguments that it knows
421 pimpl_->application_.reset(createApplication(argc, argv));
423 // Reestablish our defaults, as Qt overwrites them
424 // after createApplication()
427 // Parse and remove all known arguments in the LyX singleton
428 // Give an error for all remaining ones.
429 int exit_status = init(argc, argv);
431 // Kill the application object before exiting.
432 pimpl_->application_.reset();
439 /* Create a CoreApplication class that will provide the main event loop
440 * and the socket callback registering. With Qt4, only QtCore
441 * library would be needed.
442 * When this is done, a server_mode could be created and the following two
443 * line would be moved out from here.
445 // Note: socket callback must be registered after init(argc, argv)
446 // such that package().temp_dir() is properly initialized.
447 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
448 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
449 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
451 // Start the real execution loop.
452 exit_status = pimpl_->application_->exec();
460 void LyX::prepareExit()
462 // Clear the clipboard and selection stack:
463 cap::clearCutStack();
464 cap::clearSelection();
466 // close buffers first
467 pimpl_->buffer_list_.closeAll();
469 // register session changes and shutdown server and socket
471 if (pimpl_->session_)
472 pimpl_->session_->writeFile();
473 pimpl_->session_.reset();
474 pimpl_->lyx_server_.reset();
475 pimpl_->lyx_socket_.reset();
478 // do any other cleanup procedures now
479 if (package().temp_dir() != package().system_temp_dir()) {
480 string const abs_tmpdir = package().temp_dir().absFilename();
481 if (!contains(package().temp_dir().absFilename(), "lyx_tmpdir")) {
482 docstring const msg =
483 bformat(_("%1$s does not appear like a LyX created temporary directory."),
484 from_utf8(abs_tmpdir));
485 Alert::warning(_("Cannot remove temporary directory"), msg);
487 LYXERR(Debug::INFO, "Deleting tmp dir "
488 << package().temp_dir().absFilename());
489 if (!package().temp_dir().destroyDirectory()) {
490 docstring const msg =
491 bformat(_("Unable to remove the temporary directory %1$s"),
492 from_utf8(package().temp_dir().absFilename()));
493 Alert::warning(_("Unable to remove temporary directory"), msg);
498 // Kill the application object before exiting. This avoids crashes
499 // when exiting on Linux.
500 if (pimpl_->application_)
501 pimpl_->application_.reset();
505 void LyX::earlyExit(int status)
507 LASSERT(pimpl_->application_.get(), /**/);
508 // LyX::pimpl_::application_ is not initialised at this
509 // point so it's safe to just exit after some cleanup.
515 int LyX::init(int & argc, char * argv[])
517 // check for any spurious extra arguments
518 // other than documents
519 for (int argi = 1; argi < argc ; ++argi) {
520 if (argv[argi][0] == '-') {
522 bformat(_("Wrong command line option `%1$s'. Exiting."),
523 from_utf8(argv[argi]))) << endl;
528 // Initialization of LyX (reads lyxrc and more)
529 LYXERR(Debug::INIT, "Initializing LyX::init...");
530 bool success = init();
531 LYXERR(Debug::INIT, "Initializing LyX::init...done");
535 // Remaining arguments are assumed to be files to load.
536 for (int argi = argc - 1; argi >= 1; --argi)
537 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
540 pimpl_->files_to_load_.push_back(
541 i18nLibFileSearch("examples", "splash.lyx").absFilename());
548 bool LyX::loadFiles()
550 LASSERT(!use_gui, /**/);
552 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
553 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
555 for (; it != end; ++it) {
556 // get absolute path of file and add ".lyx" to
557 // the filename if necessary
558 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
564 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
565 if (buf->loadLyXFile(fname)) {
566 ErrorList const & el = buf->errorList("Parse");
568 for_each(el.begin(), el.end(),
569 boost::bind(&LyX::printError, this, _1));
572 pimpl_->buffer_list_.release(buf);
580 void LyX::execBatchCommands()
582 // The advantage of doing this here is that the event loop
583 // is already started. So any need for interaction will be
586 // if reconfiguration is needed.
587 while (LayoutFileList::get().empty()) {
588 switch (Alert::prompt(
589 _("No textclass is found"),
590 _("LyX cannot continue because no textclass is found. "
591 "You can either reconfigure normally, or reconfigure using "
592 "default textclasses, or quit LyX."),
599 // regular reconfigure
600 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
603 // reconfigure --without-latex-config
604 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
605 " --without-latex-config"));
608 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
613 // create the first main window
614 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
616 if (!pimpl_->files_to_load_.empty()) {
617 // if some files were specified at command-line we assume that the
618 // user wants to edit *these* files and not to restore the session.
619 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
620 pimpl_->lyxfunc_.dispatch(
621 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
623 // clear this list to save a few bytes of RAM
624 pimpl_->files_to_load_.clear();
627 pimpl_->application_->restoreGuiSession();
629 // Execute batch commands if available
630 if (pimpl_->batch_commands.empty())
633 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
634 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
635 for (; bcit != bcend; bcit++) {
636 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
637 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(*bcit));
645 The SIGHUP signal does not exist on Windows and does not need to be handled.
647 Windows handles SIGFPE and SIGSEGV signals as expected.
649 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
650 cause a new thread to be spawned. This may well result in unexpected
651 behaviour by the single-threaded LyX.
653 SIGTERM signals will come only from another process actually sending
654 that signal using 'raise' in Windows' POSIX compatability layer. It will
655 not come from the general "terminate process" methods that everyone
656 actually uses (and which can't be trapped). Killing an app 'politely' on
657 Windows involves first sending a WM_CLOSE message, something that is
658 caught already by the Qt frontend.
660 For more information see:
662 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
663 ...signals are mostly useless on Windows for a variety of reasons that are
666 'UNIX Application Migration Guide, Chapter 9'
667 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
669 'How To Terminate an Application "Cleanly" in Win32'
670 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
674 static void error_handler(int err_sig)
676 // Throw away any signals other than the first one received.
677 static sig_atomic_t handling_error = false;
680 handling_error = true;
682 // We have received a signal indicating a fatal error, so
683 // try and save the data ASAP.
684 LyX::cref().emergencyCleanup();
686 // These lyxerr calls may or may not work:
688 // Signals are asynchronous, so the main program may be in a very
689 // fragile state when a signal is processed and thus while a signal
690 // handler function executes.
691 // In general, therefore, we should avoid performing any
692 // I/O operations or calling most library and system functions from
695 // This shouldn't matter here, however, as we've already invoked
700 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
704 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
707 lyxerr << "\nlyx: SIGSEGV signal caught\n"
708 "Sorry, you have found a bug in LyX. "
709 "Please read the bug-reporting instructions "
710 "in Help->Introduction and send us a bug report, "
711 "if necessary. Thanks !\nBye." << endl;
719 // Deinstall the signal handlers
721 signal(SIGHUP, SIG_DFL);
723 signal(SIGINT, SIG_DFL);
724 signal(SIGFPE, SIG_DFL);
725 signal(SIGSEGV, SIG_DFL);
726 signal(SIGTERM, SIG_DFL);
729 if (err_sig == SIGSEGV ||
730 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
732 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
741 void LyX::printError(ErrorItem const & ei)
743 docstring tmp = _("LyX: ") + ei.error + char_type(':')
745 cerr << to_utf8(tmp) << endl;
752 signal(SIGHUP, error_handler);
754 signal(SIGFPE, error_handler);
755 signal(SIGSEGV, error_handler);
756 signal(SIGINT, error_handler);
757 signal(SIGTERM, error_handler);
758 // SIGPIPE can be safely ignored.
760 lyxrc.tempdir_path = package().temp_dir().absFilename();
761 lyxrc.document_path = package().document_dir().absFilename();
763 if (lyxrc.example_path.empty()) {
764 lyxrc.example_path = addPath(package().system_support().absFilename(),
767 if (lyxrc.template_path.empty()) {
768 lyxrc.template_path = addPath(package().system_support().absFilename(),
773 // Read configuration files
776 // This one may have been distributed along with LyX.
777 if (!readRcFile("lyxrc.dist"))
780 // Set the language defined by the distributor.
783 // Set the PATH correctly.
784 #if !defined (USE_POSIX_PACKAGING)
785 // Add the directory containing the LyX executable to the path
786 // so that LyX can find things like tex2lyx.
787 if (package().build_support().empty())
788 prependEnvPath("PATH", package().binary_dir().absFilename());
790 if (!lyxrc.path_prefix.empty())
791 prependEnvPath("PATH", lyxrc.path_prefix);
793 // Check that user LyX directory is ok.
794 if (queryUserLyXDir(package().explicit_user_support()))
795 reconfigureUserLyXDir();
797 // no need for a splash when there is no GUI
802 // This one is generated in user_support directory by lib/configure.py.
803 if (!readRcFile("lyxrc.defaults"))
806 // Query the OS to know what formats are viewed natively
807 formats.setAutoOpen();
809 // Read lyxrc.dist again to be able to override viewer auto-detection.
810 readRcFile("lyxrc.dist");
812 system_lyxrc = lyxrc;
813 system_formats = formats;
814 pimpl_->system_converters_ = pimpl_->converters_;
815 pimpl_->system_movers_ = pimpl_->movers_;
816 system_lcolor = lcolor;
818 // This one is edited through the preferences dialog.
819 if (!readRcFile("preferences"))
822 if (!readEncodingsFile("encodings", "unicodesymbols"))
824 if (!readLanguagesFile("languages"))
827 // Set the language defined by the user.
831 LYXERR(Debug::INIT, "Reading layouts...");
837 // read keymap and ui files in batch mode as well
838 // because InsetInfo needs to know these to produce
839 // the correct output
841 // Set up command definitions
842 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
845 pimpl_->toplevel_keymap_.read("site");
846 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
847 // load user bind file user.bind
848 pimpl_->toplevel_keymap_.read("user");
850 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
852 if (lyxerr.debugging(Debug::LYXRC))
855 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
856 if (!lyxrc.path_prefix.empty())
857 prependEnvPath("PATH", lyxrc.path_prefix);
859 FileName const document_path(lyxrc.document_path);
860 if (document_path.exists() && document_path.isDirectory())
861 package().document_dir() = document_path;
863 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
864 if (package().temp_dir().empty()) {
865 Alert::error(_("Could not create temporary directory"),
866 bformat(_("Could not create a temporary directory in\n"
868 "Make sure that this path exists and is writable and try again."),
869 from_utf8(lyxrc.tempdir_path)));
870 // createLyXTmpDir() tries sufficiently hard to create a
871 // usable temp dir, so the probability to come here is
872 // close to zero. We therefore don't try to overcome this
873 // problem with e.g. asking the user for a new path and
874 // trying again but simply exit.
878 LYXERR(Debug::INIT, "LyX tmp dir: `"
879 << package().temp_dir().absFilename() << '\'');
881 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
882 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
884 // This must happen after package initialization and after lyxrc is
885 // read, therefore it can't be done by a static object.
886 ConverterCache::init();
892 void LyX::emergencyCleanup() const
894 // what to do about tmpfiles is non-obvious. we would
895 // like to delete any we find, but our lyxdir might
896 // contain documents etc. which might be helpful on
899 pimpl_->buffer_list_.emergencyWriteAll();
901 if (pimpl_->lyx_server_)
902 pimpl_->lyx_server_->emergencyCleanup();
903 pimpl_->lyx_server_.reset();
904 pimpl_->lyx_socket_.reset();
909 // return true if file does not exist or is older than configure.py.
910 static bool needsUpdate(string const & file)
912 // We cannot initialize configure_script directly because the package
913 // is not initialized yet when static objects are constructed.
914 static FileName configure_script;
915 static bool firstrun = true;
918 FileName(addName(package().system_support().absFilename(),
924 FileName(addName(package().user_support().absFilename(), file));
925 return !absfile.exists()
926 || configure_script.lastModified() > absfile.lastModified();
930 bool LyX::queryUserLyXDir(bool explicit_userdir)
932 // Does user directory exist?
933 FileName const sup = package().user_support();
934 if (sup.exists() && sup.isDirectory()) {
937 return needsUpdate("lyxrc.defaults")
938 || needsUpdate("lyxmodules.lst")
939 || needsUpdate("textclass.lst")
940 || needsUpdate("packages.lst");
943 first_start = !explicit_userdir;
945 // If the user specified explicitly a directory, ask whether
946 // to create it. If the user says "no", then exit.
947 if (explicit_userdir &&
949 _("Missing user LyX directory"),
950 bformat(_("You have specified a non-existent user "
951 "LyX directory, %1$s.\n"
952 "It is needed to keep your own configuration."),
953 from_utf8(package().user_support().absFilename())),
955 _("&Create directory"),
957 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
958 earlyExit(EXIT_FAILURE);
961 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
962 from_utf8(sup.absFilename()))) << endl;
964 if (!sup.createDirectory(0755)) {
965 // Failed, so let's exit.
966 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
968 earlyExit(EXIT_FAILURE);
975 bool LyX::readRcFile(string const & name)
977 LYXERR(Debug::INIT, "About to read " << name << "... ");
979 FileName const lyxrc_path = libFileSearch(string(), name);
980 if (!lyxrc_path.empty()) {
981 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
982 if (lyxrc.read(lyxrc_path) < 0) {
987 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
992 // Read the languages file `name'
993 bool LyX::readLanguagesFile(string const & name)
995 LYXERR(Debug::INIT, "About to read " << name << "...");
997 FileName const lang_path = libFileSearch(string(), name);
998 if (lang_path.empty()) {
1002 languages.read(lang_path);
1007 // Read the encodings file `name'
1008 bool LyX::readEncodingsFile(string const & enc_name,
1009 string const & symbols_name)
1011 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1012 << symbols_name << "...");
1014 FileName const symbols_path = libFileSearch(string(), symbols_name);
1015 if (symbols_path.empty()) {
1016 showFileError(symbols_name);
1020 FileName const enc_path = libFileSearch(string(), enc_name);
1021 if (enc_path.empty()) {
1022 showFileError(enc_name);
1025 encodings.read(enc_path, symbols_path);
1032 /// return the the number of arguments consumed
1033 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
1035 int parse_dbg(string const & arg, string const &, string &)
1038 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1039 Debug::showTags(lyxerr);
1042 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1044 lyxerr.level(Debug::value(arg));
1045 Debug::showLevel(lyxerr, lyxerr.level());
1050 int parse_help(string const &, string const &, string &)
1053 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1054 "Command line switches (case sensitive):\n"
1055 "\t-help summarize LyX usage\n"
1056 "\t-userdir dir set user directory to dir\n"
1057 "\t-sysdir dir set system directory to dir\n"
1058 "\t-geometry WxH+X+Y set geometry of the main window\n"
1059 "\t-dbg feature[,feature]...\n"
1060 " select the features to debug.\n"
1061 " Type `lyx -dbg' to see the list of features\n"
1062 "\t-x [--execute] command\n"
1063 " where command is a lyx command.\n"
1064 "\t-e [--export] fmt\n"
1065 " where fmt is the export format of choice.\n"
1066 " Look on Tools->Preferences->File formats->Format\n"
1067 " to get an idea which parameters should be passed.\n"
1068 "\t-i [--import] fmt file.xxx\n"
1069 " where fmt is the import format of choice\n"
1070 " and file.xxx is the file to be imported.\n"
1071 "\t-version summarize version and build info\n"
1072 "Check the LyX man page for more details.")) << endl;
1078 int parse_version(string const &, string const &, string &)
1080 lyxerr << "LyX " << lyx_version
1081 << " (" << lyx_release_date << ")" << endl;
1082 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1084 lyxerr << lyx_version_info << endl;
1090 int parse_sysdir(string const & arg, string const &, string &)
1093 Alert::error(_("No system directory"),
1094 _("Missing directory for -sysdir switch"));
1097 cl_system_support = arg;
1102 int parse_userdir(string const & arg, string const &, string &)
1105 Alert::error(_("No user directory"),
1106 _("Missing directory for -userdir switch"));
1109 cl_user_support = arg;
1114 int parse_execute(string const & arg, string const &, string & batch)
1117 Alert::error(_("Incomplete command"),
1118 _("Missing command string after --execute switch"));
1126 int parse_export(string const & type, string const &, string & batch)
1129 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1130 "--export switch")) << endl;
1133 batch = "buffer-export " + type;
1139 int parse_import(string const & type, string const & file, string & batch)
1142 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1143 "--import switch")) << endl;
1147 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1151 batch = "buffer-import " + type + ' ' + file;
1156 int parse_geometry(string const & arg1, string const &, string &)
1159 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1160 // remove also the arg
1163 // don't remove "-geometry"
1172 void LyX::easyParse(int & argc, char * argv[])
1174 map<string, cmd_helper> cmdmap;
1176 cmdmap["-dbg"] = parse_dbg;
1177 cmdmap["-help"] = parse_help;
1178 cmdmap["--help"] = parse_help;
1179 cmdmap["-version"] = parse_version;
1180 cmdmap["--version"] = parse_version;
1181 cmdmap["-sysdir"] = parse_sysdir;
1182 cmdmap["-userdir"] = parse_userdir;
1183 cmdmap["-x"] = parse_execute;
1184 cmdmap["--execute"] = parse_execute;
1185 cmdmap["-e"] = parse_export;
1186 cmdmap["--export"] = parse_export;
1187 cmdmap["-i"] = parse_import;
1188 cmdmap["--import"] = parse_import;
1189 cmdmap["-geometry"] = parse_geometry;
1191 for (int i = 1; i < argc; ++i) {
1192 map<string, cmd_helper>::const_iterator it
1193 = cmdmap.find(argv[i]);
1195 // don't complain if not found - may be parsed later
1196 if (it == cmdmap.end())
1200 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1202 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1205 int const remove = 1 + it->second(arg, arg2, batch);
1207 pimpl_->batch_commands.push_back(batch);
1209 // Now, remove used arguments by shifting
1210 // the following ones remove places down.
1213 for (int j = i; j < argc; ++j)
1214 argv[j] = argv[j + remove];
1221 FuncStatus getStatus(FuncRequest const & action)
1223 return LyX::ref().lyxFunc().getStatus(action);
1227 void dispatch(FuncRequest const & action)
1229 LyX::ref().lyxFunc().dispatch(action);
1233 BufferList & theBufferList()
1235 return LyX::ref().bufferList();
1239 LyXFunc & theLyXFunc()
1241 return LyX::ref().lyxFunc();
1245 Server & theServer()
1247 // FIXME: this should not be use_gui dependent
1248 LASSERT(use_gui, /**/);
1249 return LyX::ref().server();
1253 ServerSocket & theServerSocket()
1255 // FIXME: this should not be use_gui dependent
1256 LASSERT(use_gui, /**/);
1257 return LyX::ref().socket();
1261 KeyMap & theTopLevelKeymap()
1263 return LyX::ref().pimpl_->toplevel_keymap_;
1267 Converters & theConverters()
1269 return LyX::ref().converters();
1273 Converters & theSystemConverters()
1275 return LyX::ref().systemConverters();
1279 Movers & theMovers()
1281 return LyX::ref().pimpl_->movers_;
1285 Mover const & getMover(string const & fmt)
1287 return LyX::ref().pimpl_->movers_(fmt);
1291 void setMover(string const & fmt, string const & command)
1293 LyX::ref().pimpl_->movers_.set(fmt, command);
1297 Movers & theSystemMovers()
1299 return LyX::ref().pimpl_->system_movers_;
1303 Messages & getMessages(string const & language)
1305 return LyX::ref().getMessages(language);
1309 Messages & getGuiMessages()
1311 return LyX::ref().getGuiMessages();