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();
185 void LyX::exit(int exit_code) const
188 // Something wrong happened so better save everything, just in
193 // Properly crash in debug mode in order to get a useful backtrace.
197 // In release mode, try to exit gracefully.
199 theApp()->exit(exit_code);
207 LASSERT(singleton_, /**/);
212 LyX const & LyX::cref()
214 LASSERT(singleton_, /**/);
227 BufferList & LyX::bufferList()
229 return pimpl_->buffer_list_;
233 BufferList const & LyX::bufferList() const
235 return pimpl_->buffer_list_;
239 Session & LyX::session()
241 LASSERT(pimpl_->session_.get(), /**/);
242 return *pimpl_->session_.get();
246 Session const & LyX::session() const
248 LASSERT(pimpl_->session_.get(), /**/);
249 return *pimpl_->session_.get();
253 LyXFunc & LyX::lyxFunc()
255 return pimpl_->lyxfunc_;
259 LyXFunc const & LyX::lyxFunc() const
261 return pimpl_->lyxfunc_;
265 Server & LyX::server()
267 LASSERT(pimpl_->lyx_server_.get(), /**/);
268 return *pimpl_->lyx_server_.get();
272 Server const & LyX::server() const
274 LASSERT(pimpl_->lyx_server_.get(), /**/);
275 return *pimpl_->lyx_server_.get();
279 ServerSocket & LyX::socket()
281 LASSERT(pimpl_->lyx_socket_.get(), /**/);
282 return *pimpl_->lyx_socket_.get();
286 ServerSocket const & LyX::socket() const
288 LASSERT(pimpl_->lyx_socket_.get(), /**/);
289 return *pimpl_->lyx_socket_.get();
293 frontend::Application & LyX::application()
295 LASSERT(pimpl_->application_.get(), /**/);
296 return *pimpl_->application_.get();
300 frontend::Application const & LyX::application() const
302 LASSERT(pimpl_->application_.get(), /**/);
303 return *pimpl_->application_.get();
307 CmdDef & LyX::topLevelCmdDef()
309 return pimpl_->toplevel_cmddef_;
313 Converters & LyX::converters()
315 return pimpl_->converters_;
319 Converters & LyX::systemConverters()
321 return pimpl_->system_converters_;
325 Messages & LyX::getMessages(string const & language)
327 map<string, Messages>::iterator it = pimpl_->messages_.find(language);
329 if (it != pimpl_->messages_.end())
332 pair<map<string, Messages>::iterator, bool> result =
333 pimpl_->messages_.insert(make_pair(language, Messages(language)));
335 LASSERT(result.second, /**/);
336 return result.first->second;
340 Messages & LyX::getGuiMessages()
342 return pimpl_->messages_["GUI"];
346 void LyX::setRcGuiLanguage()
348 if (lyxrc.gui_language == "auto")
350 Language const * language = languages.getLanguage(lyxrc.gui_language);
351 LYXERR(Debug::LOCALE, "Setting LANGUAGE to " << language->code());
352 if (!setEnv("LANGUAGE", language->code()))
353 LYXERR(Debug::LOCALE, "\t... failed!");
354 LYXERR(Debug::LOCALE, "Setting LC_ALL to en_US");
355 if (!setEnv("LC_ALL", "en_US"))
356 LYXERR(Debug::LOCALE, "\t... failed!");
357 pimpl_->messages_["GUI"] = Messages();
361 int LyX::exec(int & argc, char * argv[])
363 // Here we need to parse the command line. At least
364 // we need to parse for "-dbg" and "-help"
365 easyParse(argc, argv);
368 init_package(to_utf8(from_local8bit(argv[0])),
369 cl_system_support, cl_user_support,
370 top_build_dir_is_one_level_up);
371 } catch (ExceptionMessage const & message) {
372 if (message.type_ == ErrorException) {
373 Alert::error(message.title_, message.details_);
375 } else if (message.type_ == WarningException) {
376 Alert::warning(message.title_, message.details_);
380 // Reinit the messages machinery in case package() knows
381 // something interesting about the locale directory.
385 // FIXME: create a ConsoleApplication
386 int exit_status = init(argc, argv);
392 // this is correct, since return values are inverted.
393 exit_status = !loadFiles();
395 if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) {
400 BufferList::iterator begin = pimpl_->buffer_list_.begin();
402 bool final_success = false;
403 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
405 if (buf != buf->masterBuffer())
407 bool success = false;
408 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
409 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
410 for (; bcit != bcend; bcit++) {
411 buf->dispatch(*bcit, &success);
412 final_success |= success;
416 return !final_success;
419 // Let the frontend parse and remove all arguments that it knows
420 pimpl_->application_.reset(createApplication(argc, argv));
422 // Reestablish our defaults, as Qt overwrites them
423 // after createApplication()
426 // Parse and remove all known arguments in the LyX singleton
427 // Give an error for all remaining ones.
428 int exit_status = init(argc, argv);
430 // Kill the application object before exiting.
431 pimpl_->application_.reset();
438 /* Create a CoreApplication class that will provide the main event loop
439 * and the socket callback registering. With Qt4, only QtCore
440 * library would be needed.
441 * When this is done, a server_mode could be created and the following two
442 * line would be moved out from here.
444 // Note: socket callback must be registered after init(argc, argv)
445 // such that package().temp_dir() is properly initialized.
446 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
447 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
448 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
450 // Start the real execution loop.
451 exit_status = pimpl_->application_->exec();
459 void LyX::prepareExit()
461 // Clear the clipboard and selection stack:
462 cap::clearCutStack();
463 cap::clearSelection();
465 // close buffers first
466 pimpl_->buffer_list_.closeAll();
468 // register session changes and shutdown server and socket
470 if (pimpl_->session_)
471 pimpl_->session_->writeFile();
472 pimpl_->session_.reset();
473 pimpl_->lyx_server_.reset();
474 pimpl_->lyx_socket_.reset();
477 // do any other cleanup procedures now
478 if (package().temp_dir() != package().system_temp_dir()) {
479 string const abs_tmpdir = package().temp_dir().absFilename();
480 if (!contains(package().temp_dir().absFilename(), "lyx_tmpdir")) {
481 docstring const msg =
482 bformat(_("%1$s does not appear like a LyX created temporary directory."),
483 from_utf8(abs_tmpdir));
484 Alert::warning(_("Cannot remove temporary directory"), msg);
486 LYXERR(Debug::INFO, "Deleting tmp dir "
487 << package().temp_dir().absFilename());
488 if (!package().temp_dir().destroyDirectory()) {
489 docstring const msg =
490 bformat(_("Unable to remove the temporary directory %1$s"),
491 from_utf8(package().temp_dir().absFilename()));
492 Alert::warning(_("Unable to remove temporary directory"), msg);
497 // Kill the application object before exiting. This avoids crashes
498 // when exiting on Linux.
499 if (pimpl_->application_)
500 pimpl_->application_.reset();
504 void LyX::earlyExit(int status)
506 LASSERT(pimpl_->application_.get(), /**/);
507 // LyX::pimpl_::application_ is not initialised at this
508 // point so it's safe to just exit after some cleanup.
514 int LyX::init(int & argc, char * argv[])
516 // check for any spurious extra arguments
517 // other than documents
518 for (int argi = 1; argi < argc ; ++argi) {
519 if (argv[argi][0] == '-') {
521 bformat(_("Wrong command line option `%1$s'. Exiting."),
522 from_utf8(argv[argi]))) << endl;
527 // Initialization of LyX (reads lyxrc and more)
528 LYXERR(Debug::INIT, "Initializing LyX::init...");
529 bool success = init();
530 LYXERR(Debug::INIT, "Initializing LyX::init...done");
534 // Remaining arguments are assumed to be files to load.
535 for (int argi = argc - 1; argi >= 1; --argi)
536 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
539 pimpl_->files_to_load_.push_back(
540 i18nLibFileSearch("examples", "splash.lyx").absFilename());
547 bool LyX::loadFiles()
549 LASSERT(!use_gui, /**/);
551 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
552 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
554 for (; it != end; ++it) {
555 // get absolute path of file and add ".lyx" to
556 // the filename if necessary
557 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
563 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
564 if (buf->loadLyXFile(fname)) {
565 ErrorList const & el = buf->errorList("Parse");
567 for_each(el.begin(), el.end(),
568 boost::bind(&LyX::printError, this, _1));
571 pimpl_->buffer_list_.release(buf);
579 void LyX::execBatchCommands()
581 // The advantage of doing this here is that the event loop
582 // is already started. So any need for interaction will be
585 // if reconfiguration is needed.
586 while (LayoutFileList::get().empty()) {
587 switch (Alert::prompt(
588 _("No textclass is found"),
589 _("LyX cannot continue because no textclass is found. "
590 "You can either reconfigure normally, or reconfigure using "
591 "default textclasses, or quit LyX."),
598 // regular reconfigure
599 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
602 // reconfigure --without-latex-config
603 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
604 " --without-latex-config"));
607 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
612 // create the first main window
613 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
615 if (!pimpl_->files_to_load_.empty()) {
616 // if some files were specified at command-line we assume that the
617 // user wants to edit *these* files and not to restore the session.
618 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
619 pimpl_->lyxfunc_.dispatch(
620 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
622 // clear this list to save a few bytes of RAM
623 pimpl_->files_to_load_.clear();
626 pimpl_->application_->restoreGuiSession();
628 // Execute batch commands if available
629 if (pimpl_->batch_commands.empty())
632 vector<string>::const_iterator bcit = pimpl_->batch_commands.begin();
633 vector<string>::const_iterator bcend = pimpl_->batch_commands.end();
634 for (; bcit != bcend; bcit++) {
635 LYXERR(Debug::INIT, "About to handle -x '" << *bcit << '\'');
636 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(*bcit));
644 The SIGHUP signal does not exist on Windows and does not need to be handled.
646 Windows handles SIGFPE and SIGSEGV signals as expected.
648 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
649 cause a new thread to be spawned. This may well result in unexpected
650 behaviour by the single-threaded LyX.
652 SIGTERM signals will come only from another process actually sending
653 that signal using 'raise' in Windows' POSIX compatability layer. It will
654 not come from the general "terminate process" methods that everyone
655 actually uses (and which can't be trapped). Killing an app 'politely' on
656 Windows involves first sending a WM_CLOSE message, something that is
657 caught already by the Qt frontend.
659 For more information see:
661 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
662 ...signals are mostly useless on Windows for a variety of reasons that are
665 'UNIX Application Migration Guide, Chapter 9'
666 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
668 'How To Terminate an Application "Cleanly" in Win32'
669 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
673 static void error_handler(int err_sig)
675 // Throw away any signals other than the first one received.
676 static sig_atomic_t handling_error = false;
679 handling_error = true;
681 // We have received a signal indicating a fatal error, so
682 // try and save the data ASAP.
683 LyX::cref().emergencyCleanup();
685 // These lyxerr calls may or may not work:
687 // Signals are asynchronous, so the main program may be in a very
688 // fragile state when a signal is processed and thus while a signal
689 // handler function executes.
690 // In general, therefore, we should avoid performing any
691 // I/O operations or calling most library and system functions from
694 // This shouldn't matter here, however, as we've already invoked
699 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
703 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
706 lyxerr << "\nlyx: SIGSEGV signal caught\n"
707 "Sorry, you have found a bug in LyX. "
708 "Please read the bug-reporting instructions "
709 "in Help->Introduction and send us a bug report, "
710 "if necessary. Thanks !\nBye." << endl;
718 // Deinstall the signal handlers
720 signal(SIGHUP, SIG_DFL);
722 signal(SIGINT, SIG_DFL);
723 signal(SIGFPE, SIG_DFL);
724 signal(SIGSEGV, SIG_DFL);
725 signal(SIGTERM, SIG_DFL);
728 if (err_sig == SIGSEGV ||
729 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
731 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
740 void LyX::printError(ErrorItem const & ei)
742 docstring tmp = _("LyX: ") + ei.error + char_type(':')
744 cerr << to_utf8(tmp) << endl;
751 signal(SIGHUP, error_handler);
753 signal(SIGFPE, error_handler);
754 signal(SIGSEGV, error_handler);
755 signal(SIGINT, error_handler);
756 signal(SIGTERM, error_handler);
757 // SIGPIPE can be safely ignored.
759 lyxrc.tempdir_path = package().temp_dir().absFilename();
760 lyxrc.document_path = package().document_dir().absFilename();
762 if (lyxrc.example_path.empty()) {
763 lyxrc.example_path = addPath(package().system_support().absFilename(),
766 if (lyxrc.template_path.empty()) {
767 lyxrc.template_path = addPath(package().system_support().absFilename(),
772 // Read configuration files
775 // This one may have been distributed along with LyX.
776 if (!readRcFile("lyxrc.dist"))
779 // Set the language defined by the distributor.
782 // Set the PATH correctly.
783 #if !defined (USE_POSIX_PACKAGING)
784 // Add the directory containing the LyX executable to the path
785 // so that LyX can find things like tex2lyx.
786 if (package().build_support().empty())
787 prependEnvPath("PATH", package().binary_dir().absFilename());
789 if (!lyxrc.path_prefix.empty())
790 prependEnvPath("PATH", lyxrc.path_prefix);
792 // Check that user LyX directory is ok.
793 if (queryUserLyXDir(package().explicit_user_support()))
794 reconfigureUserLyXDir();
796 // no need for a splash when there is no GUI
801 // This one is generated in user_support directory by lib/configure.py.
802 if (!readRcFile("lyxrc.defaults"))
805 // Query the OS to know what formats are viewed natively
806 formats.setAutoOpen();
808 // Read lyxrc.dist again to be able to override viewer auto-detection.
809 readRcFile("lyxrc.dist");
811 system_lyxrc = lyxrc;
812 system_formats = formats;
813 pimpl_->system_converters_ = pimpl_->converters_;
814 pimpl_->system_movers_ = pimpl_->movers_;
815 system_lcolor = lcolor;
817 // This one is edited through the preferences dialog.
818 if (!readRcFile("preferences"))
821 if (!readEncodingsFile("encodings", "unicodesymbols"))
823 if (!readLanguagesFile("languages"))
826 // Set the language defined by the user.
830 LYXERR(Debug::INIT, "Reading layouts...");
836 // read keymap and ui files in batch mode as well
837 // because InsetInfo needs to know these to produce
838 // the correct output
840 // Set up command definitions
841 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
844 pimpl_->toplevel_keymap_.read("site");
845 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
846 // load user bind file user.bind
847 pimpl_->toplevel_keymap_.read("user");
849 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
851 if (lyxerr.debugging(Debug::LYXRC))
854 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
855 if (!lyxrc.path_prefix.empty())
856 prependEnvPath("PATH", lyxrc.path_prefix);
858 FileName const document_path(lyxrc.document_path);
859 if (document_path.exists() && document_path.isDirectory())
860 package().document_dir() = document_path;
862 package().set_temp_dir(createLyXTmpDir(FileName(lyxrc.tempdir_path)));
863 if (package().temp_dir().empty()) {
864 Alert::error(_("Could not create temporary directory"),
865 bformat(_("Could not create a temporary directory in\n"
867 "Make sure that this path exists and is writable and try again."),
868 from_utf8(lyxrc.tempdir_path)));
869 // createLyXTmpDir() tries sufficiently hard to create a
870 // usable temp dir, so the probability to come here is
871 // close to zero. We therefore don't try to overcome this
872 // problem with e.g. asking the user for a new path and
873 // trying again but simply exit.
877 LYXERR(Debug::INIT, "LyX tmp dir: `"
878 << package().temp_dir().absFilename() << '\'');
880 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
881 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
883 // This must happen after package initialization and after lyxrc is
884 // read, therefore it can't be done by a static object.
885 ConverterCache::init();
891 void LyX::emergencyCleanup() const
893 // what to do about tmpfiles is non-obvious. we would
894 // like to delete any we find, but our lyxdir might
895 // contain documents etc. which might be helpful on
898 pimpl_->buffer_list_.emergencyWriteAll();
900 if (pimpl_->lyx_server_)
901 pimpl_->lyx_server_->emergencyCleanup();
902 pimpl_->lyx_server_.reset();
903 pimpl_->lyx_socket_.reset();
908 // return true if file does not exist or is older than configure.py.
909 static bool needsUpdate(string const & file)
911 // We cannot initialize configure_script directly because the package
912 // is not initialized yet when static objects are constructed.
913 static FileName configure_script;
914 static bool firstrun = true;
917 FileName(addName(package().system_support().absFilename(),
923 FileName(addName(package().user_support().absFilename(), file));
924 return !absfile.exists()
925 || configure_script.lastModified() > absfile.lastModified();
929 bool LyX::queryUserLyXDir(bool explicit_userdir)
931 // Does user directory exist?
932 FileName const sup = package().user_support();
933 if (sup.exists() && sup.isDirectory()) {
936 return needsUpdate("lyxrc.defaults")
937 || needsUpdate("lyxmodules.lst")
938 || needsUpdate("textclass.lst")
939 || needsUpdate("packages.lst");
942 first_start = !explicit_userdir;
944 // If the user specified explicitly a directory, ask whether
945 // to create it. If the user says "no", then exit.
946 if (explicit_userdir &&
948 _("Missing user LyX directory"),
949 bformat(_("You have specified a non-existent user "
950 "LyX directory, %1$s.\n"
951 "It is needed to keep your own configuration."),
952 from_utf8(package().user_support().absFilename())),
954 _("&Create directory"),
956 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
957 earlyExit(EXIT_FAILURE);
960 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
961 from_utf8(sup.absFilename()))) << endl;
963 if (!sup.createDirectory(0755)) {
964 // Failed, so let's exit.
965 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
967 earlyExit(EXIT_FAILURE);
974 bool LyX::readRcFile(string const & name)
976 LYXERR(Debug::INIT, "About to read " << name << "... ");
978 FileName const lyxrc_path = libFileSearch(string(), name);
979 if (!lyxrc_path.empty()) {
980 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
981 if (lyxrc.read(lyxrc_path) < 0) {
986 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
991 // Read the languages file `name'
992 bool LyX::readLanguagesFile(string const & name)
994 LYXERR(Debug::INIT, "About to read " << name << "...");
996 FileName const lang_path = libFileSearch(string(), name);
997 if (lang_path.empty()) {
1001 languages.read(lang_path);
1006 // Read the encodings file `name'
1007 bool LyX::readEncodingsFile(string const & enc_name,
1008 string const & symbols_name)
1010 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1011 << symbols_name << "...");
1013 FileName const symbols_path = libFileSearch(string(), symbols_name);
1014 if (symbols_path.empty()) {
1015 showFileError(symbols_name);
1019 FileName const enc_path = libFileSearch(string(), enc_name);
1020 if (enc_path.empty()) {
1021 showFileError(enc_name);
1024 encodings.read(enc_path, symbols_path);
1031 /// return the the number of arguments consumed
1032 typedef boost::function<int(string const &, string const &, string &)> cmd_helper;
1034 int parse_dbg(string const & arg, string const &, string &)
1037 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1038 Debug::showTags(lyxerr);
1041 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1043 lyxerr.level(Debug::value(arg));
1044 Debug::showLevel(lyxerr, lyxerr.level());
1049 int parse_help(string const &, string const &, string &)
1052 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1053 "Command line switches (case sensitive):\n"
1054 "\t-help summarize LyX usage\n"
1055 "\t-userdir dir set user directory to dir\n"
1056 "\t-sysdir dir set system directory to dir\n"
1057 "\t-geometry WxH+X+Y set geometry of the main window\n"
1058 "\t-dbg feature[,feature]...\n"
1059 " select the features to debug.\n"
1060 " Type `lyx -dbg' to see the list of features\n"
1061 "\t-x [--execute] command\n"
1062 " where command is a lyx command.\n"
1063 "\t-e [--export] fmt\n"
1064 " where fmt is the export format of choice.\n"
1065 " Look on Tools->Preferences->File formats->Format\n"
1066 " to get an idea which parameters should be passed.\n"
1067 "\t-i [--import] fmt file.xxx\n"
1068 " where fmt is the import format of choice\n"
1069 " and file.xxx is the file to be imported.\n"
1070 "\t-version summarize version and build info\n"
1071 "Check the LyX man page for more details.")) << endl;
1077 int parse_version(string const &, string const &, string &)
1079 lyxerr << "LyX " << lyx_version
1080 << " (" << lyx_release_date << ")" << endl;
1081 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1083 lyxerr << lyx_version_info << endl;
1089 int parse_sysdir(string const & arg, string const &, string &)
1092 Alert::error(_("No system directory"),
1093 _("Missing directory for -sysdir switch"));
1096 cl_system_support = arg;
1101 int parse_userdir(string const & arg, string const &, string &)
1104 Alert::error(_("No user directory"),
1105 _("Missing directory for -userdir switch"));
1108 cl_user_support = arg;
1113 int parse_execute(string const & arg, string const &, string & batch)
1116 Alert::error(_("Incomplete command"),
1117 _("Missing command string after --execute switch"));
1125 int parse_export(string const & type, string const &, string & batch)
1128 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1129 "--export switch")) << endl;
1132 batch = "buffer-export " + type;
1138 int parse_import(string const & type, string const & file, string & batch)
1141 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1142 "--import switch")) << endl;
1146 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1150 batch = "buffer-import " + type + ' ' + file;
1155 int parse_geometry(string const & arg1, string const &, string &)
1158 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1159 // remove also the arg
1162 // don't remove "-geometry"
1171 void LyX::easyParse(int & argc, char * argv[])
1173 map<string, cmd_helper> cmdmap;
1175 cmdmap["-dbg"] = parse_dbg;
1176 cmdmap["-help"] = parse_help;
1177 cmdmap["--help"] = parse_help;
1178 cmdmap["-version"] = parse_version;
1179 cmdmap["--version"] = parse_version;
1180 cmdmap["-sysdir"] = parse_sysdir;
1181 cmdmap["-userdir"] = parse_userdir;
1182 cmdmap["-x"] = parse_execute;
1183 cmdmap["--execute"] = parse_execute;
1184 cmdmap["-e"] = parse_export;
1185 cmdmap["--export"] = parse_export;
1186 cmdmap["-i"] = parse_import;
1187 cmdmap["--import"] = parse_import;
1188 cmdmap["-geometry"] = parse_geometry;
1190 for (int i = 1; i < argc; ++i) {
1191 map<string, cmd_helper>::const_iterator it
1192 = cmdmap.find(argv[i]);
1194 // don't complain if not found - may be parsed later
1195 if (it == cmdmap.end())
1199 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1201 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1204 int const remove = 1 + it->second(arg, arg2, batch);
1206 pimpl_->batch_commands.push_back(batch);
1208 // Now, remove used arguments by shifting
1209 // the following ones remove places down.
1212 for (int j = i; j < argc; ++j)
1213 argv[j] = argv[j + remove];
1220 FuncStatus getStatus(FuncRequest const & action)
1222 return LyX::ref().lyxFunc().getStatus(action);
1226 void dispatch(FuncRequest const & action)
1228 LyX::ref().lyxFunc().dispatch(action);
1232 BufferList & theBufferList()
1234 return LyX::ref().bufferList();
1238 LyXFunc & theLyXFunc()
1240 return LyX::ref().lyxFunc();
1244 Server & theServer()
1246 // FIXME: this should not be use_gui dependent
1247 LASSERT(use_gui, /**/);
1248 return LyX::ref().server();
1252 ServerSocket & theServerSocket()
1254 // FIXME: this should not be use_gui dependent
1255 LASSERT(use_gui, /**/);
1256 return LyX::ref().socket();
1260 KeyMap & theTopLevelKeymap()
1262 return LyX::ref().pimpl_->toplevel_keymap_;
1266 Converters & theConverters()
1268 return LyX::ref().converters();
1272 Converters & theSystemConverters()
1274 return LyX::ref().systemConverters();
1278 Movers & theMovers()
1280 return LyX::ref().pimpl_->movers_;
1284 Mover const & getMover(string const & fmt)
1286 return LyX::ref().pimpl_->movers_(fmt);
1290 void setMover(string const & fmt, string const & command)
1292 LyX::ref().pimpl_->movers_.set(fmt, command);
1296 Movers & theSystemMovers()
1298 return LyX::ref().pimpl_->system_movers_;
1302 Messages & getMessages(string const & language)
1304 return LyX::ref().getMessages(language);
1308 Messages & getGuiMessages()
1310 return LyX::ref().getGuiMessages();