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"
43 #include "ToolbarBackend.h"
45 #include "frontends/alert.h"
46 #include "frontends/Application.h"
48 #include "support/lassert.h"
49 #include "support/debug.h"
50 #include "support/environment.h"
51 #include "support/ExceptionMessage.h"
52 #include "support/filetools.h"
53 #include "support/gettext.h"
54 #include "support/lstrings.h"
55 #include "support/Messages.h"
56 #include "support/os.h"
57 #include "support/Package.h"
58 #include "support/Path.h"
59 #include "support/Systemcall.h"
61 #include <boost/bind.hpp>
62 #include <boost/scoped_ptr.hpp>
73 using namespace lyx::support;
77 namespace Alert = frontend::Alert;
78 namespace os = support::os;
82 // Are we using the GUI at all? We default to true and this is changed
83 // to false when the export feature is used.
89 // Filled with the command line arguments "foo" of "-sysdir foo" or
91 string cl_system_support;
92 string cl_user_support;
98 void showFileError(string const & error)
100 Alert::warning(_("Could not read configuration file"),
101 bformat(_("Error while reading the configuration file\n%1$s.\n"
102 "Please check your installation."), from_utf8(error)));
106 void reconfigureUserLyXDir()
108 string const configure_command = package().configure_command();
110 lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl;
111 PathChanger p(package().user_support());
113 one.startscript(Systemcall::Wait, configure_command);
114 lyxerr << "LyX: " << to_utf8(_("Done!")) << endl;
120 /// The main application class private implementation.
125 // Set the default User Interface language as soon as possible.
126 // The language used will be derived from the environment
128 messages_["GUI"] = Messages();
130 /// our function handler
133 BufferList buffer_list_;
135 KeyMap toplevel_keymap_;
137 CmdDef toplevel_cmddef_;
139 boost::scoped_ptr<Server> lyx_server_;
141 boost::scoped_ptr<ServerSocket> lyx_socket_;
143 boost::scoped_ptr<frontend::Application> application_;
144 /// lyx session, containing lastfiles, lastfilepos, and lastopened
145 boost::scoped_ptr<Session> session_;
147 /// Files to load at start.
148 vector<string> files_to_load_;
150 /// The messages translators.
151 map<string, Messages> messages_;
153 /// The file converters.
154 Converters converters_;
156 // The system converters copy after reading lyxrc.defaults.
157 Converters system_converters_;
162 Movers system_movers_;
164 /// has this user started lyx for the first time?
166 /// the parsed command line batch command if any
167 string batch_command;
171 frontend::Application * theApp()
174 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::setGuiLanguage(string const & language)
349 pimpl_->messages_["GUI"] = Messages(language);
353 int LyX::exec(int & argc, char * argv[])
355 // Here we need to parse the command line. At least
356 // we need to parse for "-dbg" and "-help"
357 easyParse(argc, argv);
360 init_package(to_utf8(from_local8bit(argv[0])),
361 cl_system_support, cl_user_support,
362 top_build_dir_is_one_level_up);
363 } catch (ExceptionMessage const & message) {
364 if (message.type_ == ErrorException) {
365 Alert::error(message.title_, message.details_);
367 } else if (message.type_ == WarningException) {
368 Alert::warning(message.title_, message.details_);
372 // Reinit the messages machinery in case package() knows
373 // something interesting about the locale directory.
377 // FIXME: create a ConsoleApplication
378 int exit_status = init(argc, argv);
386 if (pimpl_->batch_command.empty() || pimpl_->buffer_list_.empty()) {
391 BufferList::iterator begin = pimpl_->buffer_list_.begin();
393 bool final_success = false;
394 for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) {
396 if (buf != buf->masterBuffer())
398 bool success = false;
399 buf->dispatch(pimpl_->batch_command, &success);
400 final_success |= success;
403 return !final_success;
406 // Let the frontend parse and remove all arguments that it knows
407 pimpl_->application_.reset(createApplication(argc, argv));
409 // Parse and remove all known arguments in the LyX singleton
410 // Give an error for all remaining ones.
411 int exit_status = init(argc, argv);
413 // Kill the application object before exiting.
414 pimpl_->application_.reset();
421 /* Create a CoreApplication class that will provide the main event loop
422 * and the socket callback registering. With Qt4, only QtCore
423 * library would be needed.
424 * When this is done, a server_mode could be created and the following two
425 * line would be moved out from here.
427 // Note: socket callback must be registered after init(argc, argv)
428 // such that package().temp_dir() is properly initialized.
429 pimpl_->lyx_server_.reset(new Server(&pimpl_->lyxfunc_, lyxrc.lyxpipes));
430 pimpl_->lyx_socket_.reset(new ServerSocket(&pimpl_->lyxfunc_,
431 FileName(package().temp_dir().absFilename() + "/lyxsocket")));
433 // Start the real execution loop.
434 exit_status = pimpl_->application_->exec();
442 void LyX::prepareExit()
444 // Clear the clipboard and selection stack:
445 cap::clearCutStack();
446 cap::clearSelection();
448 // close buffers first
449 pimpl_->buffer_list_.closeAll();
451 // register session changes and shutdown server and socket
453 if (pimpl_->session_)
454 pimpl_->session_->writeFile();
455 pimpl_->session_.reset();
456 pimpl_->lyx_server_.reset();
457 pimpl_->lyx_socket_.reset();
460 // do any other cleanup procedures now
461 if (package().temp_dir() != package().system_temp_dir()) {
462 LYXERR(Debug::INFO, "Deleting tmp dir "
463 << package().temp_dir().absFilename());
465 if (!package().temp_dir().destroyDirectory()) {
466 docstring const msg =
467 bformat(_("Unable to remove the temporary directory %1$s"),
468 from_utf8(package().temp_dir().absFilename()));
469 Alert::warning(_("Unable to remove temporary directory"), msg);
473 // Kill the application object before exiting. This avoids crashes
474 // when exiting on Linux.
475 if (pimpl_->application_)
476 pimpl_->application_.reset();
480 void LyX::earlyExit(int status)
482 LASSERT(pimpl_->application_.get(), /**/);
483 // LyX::pimpl_::application_ is not initialised at this
484 // point so it's safe to just exit after some cleanup.
490 int LyX::init(int & argc, char * argv[])
492 // check for any spurious extra arguments
493 // other than documents
494 for (int argi = 1; argi < argc ; ++argi) {
495 if (argv[argi][0] == '-') {
497 bformat(_("Wrong command line option `%1$s'. Exiting."),
498 from_utf8(argv[argi]))) << endl;
503 // Initialization of LyX (reads lyxrc and more)
504 LYXERR(Debug::INIT, "Initializing LyX::init...");
505 bool success = init();
506 LYXERR(Debug::INIT, "Initializing LyX::init...done");
510 // Remaining arguments are assumed to be files to load.
511 for (int argi = argc - 1; argi >= 1; --argi)
512 pimpl_->files_to_load_.push_back(to_utf8(from_local8bit(argv[argi])));
515 pimpl_->files_to_load_.push_back(
516 i18nLibFileSearch("examples", "splash.lyx").absFilename());
523 void LyX::addFileToLoad(string const & fname)
525 vector<string>::const_iterator cit = find(
526 pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(),
529 if (cit == pimpl_->files_to_load_.end())
530 pimpl_->files_to_load_.push_back(fname);
534 void LyX::loadFiles()
536 vector<string>::const_iterator it = pimpl_->files_to_load_.begin();
537 vector<string>::const_iterator end = pimpl_->files_to_load_.end();
539 for (; it != end; ++it) {
540 // get absolute path of file and add ".lyx" to
541 // the filename if necessary
542 FileName fname = fileSearch(string(), os::internal_path(*it), "lyx",
548 Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFilename(), false);
549 if (buf->loadLyXFile(fname)) {
550 ErrorList const & el = buf->errorList("Parse");
552 for_each(el.begin(), el.end(),
553 boost::bind(&LyX::printError, this, _1));
556 pimpl_->buffer_list_.release(buf);
561 void LyX::execBatchCommands()
563 // The advantage of doing this here is that the event loop
564 // is already started. So any need for interaction will be
567 // if reconfiguration is needed.
568 while (LayoutFileList::get().empty()) {
569 switch (Alert::prompt(
570 _("No textclass is found"),
571 _("LyX cannot continue because no textclass is found. "
572 "You can either reconfigure normally, or reconfigure using "
573 "default textclasses, or quit LyX."),
580 // regular reconfigure
581 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE, ""));
584 // reconfigure --without-latex-config
585 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_RECONFIGURE,
586 " --without-latex-config"));
589 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_LYX_QUIT));
594 // create the first main window
595 pimpl_->lyxfunc_.dispatch(FuncRequest(LFUN_WINDOW_NEW, geometryArg));
597 if (!pimpl_->files_to_load_.empty()) {
598 // if some files were specified at command-line we assume that the
599 // user wants to edit *these* files and not to restore the session.
600 for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) {
601 pimpl_->lyxfunc_.dispatch(
602 FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i]));
604 // clear this list to save a few bytes of RAM
605 pimpl_->files_to_load_.clear();
608 pimpl_->application_->restoreGuiSession();
610 // Execute batch commands if available
611 if (pimpl_->batch_command.empty())
614 LYXERR(Debug::INIT, "About to handle -x '" << pimpl_->batch_command << '\'');
616 pimpl_->lyxfunc_.dispatch(lyxaction.lookupFunc(pimpl_->batch_command));
623 The SIGHUP signal does not exist on Windows and does not need to be handled.
625 Windows handles SIGFPE and SIGSEGV signals as expected.
627 Cntl+C interrupts (mapped to SIGINT by Windows' POSIX compatability layer)
628 cause a new thread to be spawned. This may well result in unexpected
629 behaviour by the single-threaded LyX.
631 SIGTERM signals will come only from another process actually sending
632 that signal using 'raise' in Windows' POSIX compatability layer. It will
633 not come from the general "terminate process" methods that everyone
634 actually uses (and which can't be trapped). Killing an app 'politely' on
635 Windows involves first sending a WM_CLOSE message, something that is
636 caught already by the Qt frontend.
638 For more information see:
640 http://aspn.activestate.com/ASPN/Mail/Message/ActiveTcl/2034055
641 ...signals are mostly useless on Windows for a variety of reasons that are
644 'UNIX Application Migration Guide, Chapter 9'
645 http://msdn.microsoft.com/library/en-us/dnucmg/html/UCMGch09.asp
647 'How To Terminate an Application "Cleanly" in Win32'
648 http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
652 static void error_handler(int err_sig)
654 // Throw away any signals other than the first one received.
655 static sig_atomic_t handling_error = false;
658 handling_error = true;
660 // We have received a signal indicating a fatal error, so
661 // try and save the data ASAP.
662 LyX::cref().emergencyCleanup();
664 // These lyxerr calls may or may not work:
666 // Signals are asynchronous, so the main program may be in a very
667 // fragile state when a signal is processed and thus while a signal
668 // handler function executes.
669 // In general, therefore, we should avoid performing any
670 // I/O operations or calling most library and system functions from
673 // This shouldn't matter here, however, as we've already invoked
678 lyxerr << "\nlyx: SIGHUP signal caught\nBye." << endl;
682 lyxerr << "\nlyx: SIGFPE signal caught\nBye." << endl;
685 lyxerr << "\nlyx: SIGSEGV signal caught\n"
686 "Sorry, you have found a bug in LyX. "
687 "Please read the bug-reporting instructions "
688 "in Help->Introduction and send us a bug report, "
689 "if necessary. Thanks !\nBye." << endl;
697 // Deinstall the signal handlers
699 signal(SIGHUP, SIG_DFL);
701 signal(SIGINT, SIG_DFL);
702 signal(SIGFPE, SIG_DFL);
703 signal(SIGSEGV, SIG_DFL);
704 signal(SIGTERM, SIG_DFL);
707 if (err_sig == SIGSEGV ||
708 (err_sig != SIGHUP && !getEnv("LYXDEBUG").empty()))
710 if (err_sig == SIGSEGV || !getEnv("LYXDEBUG").empty())
719 void LyX::printError(ErrorItem const & ei)
721 docstring tmp = _("LyX: ") + ei.error + char_type(':')
723 cerr << to_utf8(tmp) << endl;
730 signal(SIGHUP, error_handler);
732 signal(SIGFPE, error_handler);
733 signal(SIGSEGV, error_handler);
734 signal(SIGINT, error_handler);
735 signal(SIGTERM, error_handler);
736 // SIGPIPE can be safely ignored.
738 lyxrc.tempdir_path = package().temp_dir().absFilename();
739 lyxrc.document_path = package().document_dir().absFilename();
741 if (lyxrc.example_path.empty()) {
742 lyxrc.example_path = addPath(package().system_support().absFilename(),
745 if (lyxrc.template_path.empty()) {
746 lyxrc.template_path = addPath(package().system_support().absFilename(),
751 // Read configuration files
754 // This one may have been distributed along with LyX.
755 if (!readRcFile("lyxrc.dist"))
758 // Set the language defined by the distributor.
759 //setGuiLanguage(lyxrc.gui_language);
761 // Set the PATH correctly.
762 #if !defined (USE_POSIX_PACKAGING)
763 // Add the directory containing the LyX executable to the path
764 // so that LyX can find things like tex2lyx.
765 if (package().build_support().empty())
766 prependEnvPath("PATH", package().binary_dir().absFilename());
768 if (!lyxrc.path_prefix.empty())
769 prependEnvPath("PATH", lyxrc.path_prefix);
771 // Check that user LyX directory is ok.
772 if (queryUserLyXDir(package().explicit_user_support()))
773 reconfigureUserLyXDir();
775 // no need for a splash when there is no GUI
780 // This one is generated in user_support directory by lib/configure.py.
781 if (!readRcFile("lyxrc.defaults"))
784 // Query the OS to know what formats are viewed natively
785 formats.setAutoOpen();
787 // Read lyxrc.dist again to be able to override viewer auto-detection.
788 readRcFile("lyxrc.dist");
790 system_lyxrc = lyxrc;
791 system_formats = formats;
792 pimpl_->system_converters_ = pimpl_->converters_;
793 pimpl_->system_movers_ = pimpl_->movers_;
794 system_lcolor = lcolor;
796 // This one is edited through the preferences dialog.
797 if (!readRcFile("preferences"))
800 if (!readEncodingsFile("encodings", "unicodesymbols"))
802 if (!readLanguagesFile("languages"))
806 LYXERR(Debug::INIT, "Reading layouts...");
812 // read keymap and ui files in batch mode as well
813 // because InsetInfo needs to know these to produce
814 // the correct output
816 // Set the language defined by the user.
817 //setGuiLanguage(lyxrc.gui_language);
819 // Set up command definitions
820 pimpl_->toplevel_cmddef_.read(lyxrc.def_file);
823 pimpl_->toplevel_keymap_.read("site");
824 pimpl_->toplevel_keymap_.read(lyxrc.bind_file);
825 // load user bind file user.bind
826 pimpl_->toplevel_keymap_.read("user");
828 pimpl_->lyxfunc_.initKeySequences(&pimpl_->toplevel_keymap_);
831 if (use_gui && !readUIFile(lyxrc.ui_file))
834 if (lyxerr.debugging(Debug::LYXRC))
837 os::windows_style_tex_paths(lyxrc.windows_style_tex_paths);
838 if (!lyxrc.path_prefix.empty())
839 prependEnvPath("PATH", lyxrc.path_prefix);
841 FileName const document_path(lyxrc.document_path);
842 if (document_path.exists() && document_path.isDirectory())
843 package().document_dir() = document_path;
845 package().temp_dir() = createLyXTmpDir(FileName(lyxrc.tempdir_path));
846 if (package().temp_dir().empty()) {
847 Alert::error(_("Could not create temporary directory"),
848 bformat(_("Could not create a temporary directory in\n"
849 "%1$s. Make sure that this\n"
850 "path exists and is writable and try again."),
851 from_utf8(lyxrc.tempdir_path)));
852 // createLyXTmpDir() tries sufficiently hard to create a
853 // usable temp dir, so the probability to come here is
854 // close to zero. We therefore don't try to overcome this
855 // problem with e.g. asking the user for a new path and
856 // trying again but simply exit.
860 LYXERR(Debug::INIT, "LyX tmp dir: `"
861 << package().temp_dir().absFilename() << '\'');
863 LYXERR(Debug::INIT, "Reading session information '.lyx/session'...");
864 pimpl_->session_.reset(new Session(lyxrc.num_lastfiles));
866 // This must happen after package initialization and after lyxrc is
867 // read, therefore it can't be done by a static object.
868 ConverterCache::init();
874 void LyX::emergencyCleanup() const
876 // what to do about tmpfiles is non-obvious. we would
877 // like to delete any we find, but our lyxdir might
878 // contain documents etc. which might be helpful on
881 pimpl_->buffer_list_.emergencyWriteAll();
883 if (pimpl_->lyx_server_)
884 pimpl_->lyx_server_->emergencyCleanup();
885 pimpl_->lyx_server_.reset();
886 pimpl_->lyx_socket_.reset();
891 // return true if file does not exist or is older than configure.py.
892 static bool needsUpdate(string const & file)
894 // We cannot initialize configure_script directly because the package
895 // is not initialized yet when static objects are constructed.
896 static FileName configure_script;
897 static bool firstrun = true;
900 FileName(addName(package().system_support().absFilename(),
906 FileName(addName(package().user_support().absFilename(), file));
907 return !absfile.exists()
908 || configure_script.lastModified() > absfile.lastModified();
912 bool LyX::queryUserLyXDir(bool explicit_userdir)
914 // Does user directory exist?
915 FileName const sup = package().user_support();
916 if (sup.exists() && sup.isDirectory()) {
919 return needsUpdate("lyxrc.defaults")
920 || needsUpdate("lyxmodules.lst")
921 || needsUpdate("textclass.lst")
922 || needsUpdate("packages.lst");
925 first_start = !explicit_userdir;
927 // If the user specified explicitly a directory, ask whether
928 // to create it. If the user says "no", then exit.
929 if (explicit_userdir &&
931 _("Missing user LyX directory"),
932 bformat(_("You have specified a non-existent user "
933 "LyX directory, %1$s.\n"
934 "It is needed to keep your own configuration."),
935 from_utf8(package().user_support().absFilename())),
937 _("&Create directory"),
939 lyxerr << to_utf8(_("No user LyX directory. Exiting.")) << endl;
940 earlyExit(EXIT_FAILURE);
943 lyxerr << to_utf8(bformat(_("LyX: Creating directory %1$s"),
944 from_utf8(sup.absFilename()))) << endl;
946 if (!sup.createDirectory(0755)) {
947 // Failed, so let's exit.
948 lyxerr << to_utf8(_("Failed to create directory. Exiting."))
950 earlyExit(EXIT_FAILURE);
957 bool LyX::readRcFile(string const & name)
959 LYXERR(Debug::INIT, "About to read " << name << "... ");
961 FileName const lyxrc_path = libFileSearch(string(), name);
962 if (!lyxrc_path.empty()) {
963 LYXERR(Debug::INIT, "Found in " << lyxrc_path);
964 if (lyxrc.read(lyxrc_path) < 0) {
969 LYXERR(Debug::INIT, "Not found." << lyxrc_path);
975 // Read the ui file `name'
976 bool LyX::readUIFile(string const & name, bool include)
986 LexerKeyword uitags[] = {
987 { "include", ui_include },
988 { "menuset", ui_menuset },
989 { "toolbars", ui_toolbars },
990 { "toolbarset", ui_toolbarset }
993 // Ensure that a file is read only once (prevents include loops)
994 static list<string> uifiles;
995 list<string>::const_iterator it = uifiles.begin();
996 list<string>::const_iterator end = uifiles.end();
997 it = find(it, end, name);
999 LYXERR(Debug::INIT, "UI file '" << name << "' has been read already. "
1000 << "Is this an include loop?");
1004 LYXERR(Debug::INIT, "About to read " << name << "...");
1009 ui_path = libFileSearch("ui", name, "inc");
1010 if (ui_path.empty())
1011 ui_path = libFileSearch("ui",
1012 changeExtension(name, "inc"));
1015 ui_path = libFileSearch("ui", name, "ui");
1017 if (ui_path.empty()) {
1018 LYXERR(Debug::INIT, "Could not find " << name);
1019 showFileError(name);
1023 uifiles.push_back(name);
1025 LYXERR(Debug::INIT, "Found " << name << " in " << ui_path);
1027 lex.setFile(ui_path);
1029 lyxerr << "Unable to set LyXLeX for ui file: " << ui_path
1033 if (lyxerr.debugging(Debug::PARSER))
1034 lex.printTable(lyxerr);
1036 while (lex.isOK()) {
1037 switch (lex.lex()) {
1040 string const file = lex.getString();
1041 if (!readUIFile(file, true))
1046 theApp()->readMenus(lex);
1050 toolbarbackend.readToolbars(lex);
1054 toolbarbackend.readToolbarSettings(lex);
1058 if (!rtrim(lex.getString()).empty())
1059 lex.printError("LyX::ReadUIFile: "
1060 "Unknown menu tag: `$$Token'");
1068 // Read the languages file `name'
1069 bool LyX::readLanguagesFile(string const & name)
1071 LYXERR(Debug::INIT, "About to read " << name << "...");
1073 FileName const lang_path = libFileSearch(string(), name);
1074 if (lang_path.empty()) {
1075 showFileError(name);
1078 languages.read(lang_path);
1083 // Read the encodings file `name'
1084 bool LyX::readEncodingsFile(string const & enc_name,
1085 string const & symbols_name)
1087 LYXERR(Debug::INIT, "About to read " << enc_name << " and "
1088 << symbols_name << "...");
1090 FileName const symbols_path = libFileSearch(string(), symbols_name);
1091 if (symbols_path.empty()) {
1092 showFileError(symbols_name);
1096 FileName const enc_path = libFileSearch(string(), enc_name);
1097 if (enc_path.empty()) {
1098 showFileError(enc_name);
1101 encodings.read(enc_path, symbols_path);
1110 /// return the the number of arguments consumed
1111 typedef boost::function<int(string const &, string const &)> cmd_helper;
1113 int parse_dbg(string const & arg, string const &)
1116 lyxerr << to_utf8(_("List of supported debug flags:")) << endl;
1117 Debug::showTags(lyxerr);
1120 lyxerr << to_utf8(bformat(_("Setting debug level to %1$s"), from_utf8(arg))) << endl;
1122 lyxerr.level(Debug::value(arg));
1123 Debug::showLevel(lyxerr, lyxerr.level());
1128 int parse_help(string const &, string const &)
1131 to_utf8(_("Usage: lyx [ command line switches ] [ name.lyx ... ]\n"
1132 "Command line switches (case sensitive):\n"
1133 "\t-help summarize LyX usage\n"
1134 "\t-userdir dir set user directory to dir\n"
1135 "\t-sysdir dir set system directory to dir\n"
1136 "\t-geometry WxH+X+Y set geometry of the main window\n"
1137 "\t-dbg feature[,feature]...\n"
1138 " select the features to debug.\n"
1139 " Type `lyx -dbg' to see the list of features\n"
1140 "\t-x [--execute] command\n"
1141 " where command is a lyx command.\n"
1142 "\t-e [--export] fmt\n"
1143 " where fmt is the export format of choice.\n"
1144 " Look on Tools->Preferences->File formats->Format\n"
1145 " to get an idea which parameters should be passed.\n"
1146 "\t-i [--import] fmt file.xxx\n"
1147 " where fmt is the import format of choice\n"
1148 " and file.xxx is the file to be imported.\n"
1149 "\t-version summarize version and build info\n"
1150 "Check the LyX man page for more details.")) << endl;
1156 int parse_version(string const &, string const &)
1158 lyxerr << "LyX " << lyx_version
1159 << " (" << lyx_release_date << ")" << endl;
1160 lyxerr << "Built on " << __DATE__ << ", " << __TIME__ << endl;
1162 lyxerr << lyx_version_info << endl;
1168 int parse_sysdir(string const & arg, string const &)
1171 Alert::error(_("No system directory"),
1172 _("Missing directory for -sysdir switch"));
1175 cl_system_support = arg;
1180 int parse_userdir(string const & arg, string const &)
1183 Alert::error(_("No user directory"),
1184 _("Missing directory for -userdir switch"));
1187 cl_user_support = arg;
1192 int parse_execute(string const & arg, string const &)
1195 Alert::error(_("Incomplete command"),
1196 _("Missing command string after --execute switch"));
1204 int parse_export(string const & type, string const &)
1207 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1208 "--export switch")) << endl;
1211 batch = "buffer-export " + type;
1217 int parse_import(string const & type, string const & file)
1220 lyxerr << to_utf8(_("Missing file type [eg latex, ps...] after "
1221 "--import switch")) << endl;
1225 lyxerr << to_utf8(_("Missing filename for --import")) << endl;
1229 batch = "buffer-import " + type + ' ' + file;
1234 int parse_geometry(string const & arg1, string const &)
1237 #if defined(_WIN32) || (defined(__CYGWIN__) && defined(X_DISPLAY_MISSING))
1238 // remove also the arg
1241 // don't remove "-geometry"
1250 void LyX::easyParse(int & argc, char * argv[])
1252 map<string, cmd_helper> cmdmap;
1254 cmdmap["-dbg"] = parse_dbg;
1255 cmdmap["-help"] = parse_help;
1256 cmdmap["--help"] = parse_help;
1257 cmdmap["-version"] = parse_version;
1258 cmdmap["--version"] = parse_version;
1259 cmdmap["-sysdir"] = parse_sysdir;
1260 cmdmap["-userdir"] = parse_userdir;
1261 cmdmap["-x"] = parse_execute;
1262 cmdmap["--execute"] = parse_execute;
1263 cmdmap["-e"] = parse_export;
1264 cmdmap["--export"] = parse_export;
1265 cmdmap["-i"] = parse_import;
1266 cmdmap["--import"] = parse_import;
1267 cmdmap["-geometry"] = parse_geometry;
1269 for (int i = 1; i < argc; ++i) {
1270 map<string, cmd_helper>::const_iterator it
1271 = cmdmap.find(argv[i]);
1273 // don't complain if not found - may be parsed later
1274 if (it == cmdmap.end())
1278 (i + 1 < argc) ? to_utf8(from_local8bit(argv[i + 1])) : string();
1280 (i + 2 < argc) ? to_utf8(from_local8bit(argv[i + 2])) : string();
1282 int const remove = 1 + it->second(arg, arg2);
1284 // Now, remove used arguments by shifting
1285 // the following ones remove places down.
1288 for (int j = i; j < argc; ++j)
1289 argv[j] = argv[j + remove];
1294 pimpl_->batch_command = batch;
1298 FuncStatus getStatus(FuncRequest const & action)
1300 return LyX::ref().lyxFunc().getStatus(action);
1304 void dispatch(FuncRequest const & action)
1306 LyX::ref().lyxFunc().dispatch(action);
1310 BufferList & theBufferList()
1312 return LyX::ref().bufferList();
1316 LyXFunc & theLyXFunc()
1318 return LyX::ref().lyxFunc();
1322 Server & theServer()
1324 // FIXME: this should not be use_gui dependent
1325 LASSERT(use_gui, /**/);
1326 return LyX::ref().server();
1330 ServerSocket & theServerSocket()
1332 // FIXME: this should not be use_gui dependent
1333 LASSERT(use_gui, /**/);
1334 return LyX::ref().socket();
1338 KeyMap & theTopLevelKeymap()
1340 return LyX::ref().pimpl_->toplevel_keymap_;
1344 Converters & theConverters()
1346 return LyX::ref().converters();
1350 Converters & theSystemConverters()
1352 return LyX::ref().systemConverters();
1356 Movers & theMovers()
1358 return LyX::ref().pimpl_->movers_;
1362 Mover const & getMover(string const & fmt)
1364 return LyX::ref().pimpl_->movers_(fmt);
1368 void setMover(string const & fmt, string const & command)
1370 LyX::ref().pimpl_->movers_.set(fmt, command);
1374 Movers & theSystemMovers()
1376 return LyX::ref().pimpl_->system_movers_;
1380 Messages & getMessages(string const & language)
1382 return LyX::ref().getMessages(language);
1386 Messages & getGuiMessages()
1388 return LyX::ref().getGuiMessages();