X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FLyX.cpp;h=d2484d152e1f25195eeca966702258200a77744d;hb=4c724a6072013247ac178f0acec06825585c6c55;hp=99ce873b61c0394db4ea9517df9b6eb55e655a3b;hpb=d1db30a188b17b88702282cd24374f6179f2789d;p=lyx.git diff --git a/src/LyX.cpp b/src/LyX.cpp index 99ce873b61..d2484d152e 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -33,6 +33,7 @@ #include "FuncStatus.h" #include "HunspellChecker.h" #include "KeyMap.h" +#include "Language.h" #include "LaTeXFonts.h" #include "LayoutFile.h" #include "Lexer.h" @@ -49,6 +50,7 @@ #include "frontends/alert.h" #include "frontends/Application.h" +#include "support/ConsoleApplication.h" #include "support/lassert.h" #include "support/debug.h" #include "support/environment.h" @@ -59,8 +61,6 @@ #include "support/Messages.h" #include "support/os.h" #include "support/Package.h" -#include "support/PathChanger.h" -#include "support/Systemcall.h" #include "support/bind.h" #include @@ -76,6 +76,10 @@ using namespace std; using namespace lyx::support; +#if defined (USE_MACOSX_PACKAGING) +#include +#endif + namespace lyx { namespace Alert = frontend::Alert; @@ -122,18 +126,6 @@ void showFileError(string const & error) "Please check your installation."), from_utf8(error))); } - -void reconfigureUserLyXDir() -{ - string const configure_command = package().configure_command(); - - lyxerr << to_utf8(_("LyX: reconfiguring user directory")) << endl; - PathChanger p(package().user_support()); - Systemcall one; - one.startscript(Systemcall::Wait, configure_command); - lyxerr << "LyX: " << to_utf8(_("Done!")) << endl; -} - } // namespace anon /// The main application class private implementation. @@ -183,8 +175,6 @@ struct LyX::Impl { /// Movers system_movers_; - /// has this user started lyx for the first time? - bool first_start; /// the parsed command line batch command if any vector batch_commands; @@ -204,6 +194,27 @@ struct LyX::Impl { }; +/// The main application class for console mode +class LyXConsoleApp : public ConsoleApplication +{ +public: + LyXConsoleApp(LyX * lyx, int & argc, char * argv[]) + : ConsoleApplication(lyx_package, argc, argv), lyx_(lyx), + argc_(argc), argv_(argv) + { + } + void doExec() + { + int const exit_status = lyx_->execWithoutGui(argc_, argv_); + exit(exit_status); + } +private: + LyX * lyx_; + int & argc_; + char ** argv_; +}; + + /// frontend::Application * theApp() { @@ -296,39 +307,13 @@ int LyX::exec(int & argc, char * argv[]) setLocale(); if (!use_gui) { - // FIXME: create a ConsoleApplication - int exit_status = init(argc, argv); - if (exit_status) { - prepareExit(); - return exit_status; - } + LyXConsoleApp app(this, argc, argv); - // this is correct, since return values are inverted. - exit_status = !loadFiles(); + // Reestablish our defaults, as Qt overwrites them + // after creating app + setLocale();//??? - if (pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) { - prepareExit(); - return exit_status; - } - - BufferList::iterator begin = pimpl_->buffer_list_.begin(); - - bool final_success = false; - for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) { - Buffer * buf = *I; - if (buf != buf->masterBuffer()) - continue; - vector::const_iterator bcit = pimpl_->batch_commands.begin(); - vector::const_iterator bcend = pimpl_->batch_commands.end(); - DispatchResult dr; - for (; bcit != bcend; ++bcit) { - LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit); - buf->dispatch(*bcit, dr); - final_success |= !dr.error(); - } - } - prepareExit(); - return !final_success; + return app.exec(); } // Let the frontend parse and remove all arguments that it knows @@ -356,7 +341,7 @@ int LyX::exec(int & argc, char * argv[]) // FIXME /* Create a CoreApplication class that will provide the main event loop - * and the socket callback registering. With Qt4, only QtCore + * and the socket callback registering. With Qt, only QtCore * library would be needed. * When this is done, a server_mode could be created and the following two * line would be moved out from here. @@ -419,10 +404,8 @@ void LyX::prepareExit() LYXERR(Debug::INFO, "Deleting tmp dir " << package().temp_dir().absFileName()); if (!package().temp_dir().destroyDirectory()) { - docstring const msg = - bformat(_("Unable to remove the temporary directory %1$s"), - from_utf8(package().temp_dir().absFileName())); - Alert::warning(_("Unable to remove temporary directory"), msg); + LYXERR0(bformat(_("Unable to remove the temporary directory %1$s"), + from_utf8(package().temp_dir().absFileName()))); } } } @@ -481,39 +464,70 @@ int LyX::init(int & argc, char * argv[]) } -bool LyX::loadFiles() +int LyX::execWithoutGui(int & argc, char * argv[]) { - LATTEST(!use_gui); - bool success = true; + int exit_status = init(argc, argv); + if (exit_status) { + prepareExit(); + return exit_status; + } + + // Used to keep track of which buffers were explicitly loaded by user request. + // This is necessary because master and child document buffers are loaded, even + // if they were not named on the command line. We do not want to dispatch to + // those. + vector command_line_buffers; + + // Load the files specified on the command line vector::const_iterator it = pimpl_->files_to_load_.begin(); vector::const_iterator end = pimpl_->files_to_load_.end(); - for (; it != end; ++it) { - // get absolute path of file and add ".lyx" to - // the filename if necessary + // get absolute path of file and add ".lyx" to the filename if necessary FileName fname = fileSearch(string(), os::internal_path(*it), "lyx", - may_not_exist); + may_not_exist); if (fname.empty()) continue; Buffer * buf = pimpl_->buffer_list_.newBuffer(fname.absFileName()); + LYXERR(Debug::FILES, "Loading " << fname); if (buf->loadLyXFile() == Buffer::ReadSuccess) { ErrorList const & el = buf->errorList("Parse"); if (!el.empty()) - for_each(el.begin(), el.end(), - bind(&LyX::printError, this, _1)); - } - else { + for_each(el.begin(), el.end(), + bind(&LyX::printError, this, _1)); + command_line_buffers.push_back(buf); + } else { pimpl_->buffer_list_.release(buf); docstring const error_message = - bformat(_("LyX failed to load the following file: %1$s"), - from_utf8(fname.absFileName())); + bformat(_("LyX failed to load the following file: %1$s"), + from_utf8(fname.absFileName())); lyxerr << to_utf8(error_message) << endl; - success = false; + exit_status = 1; // failed } } - return success; + + if (exit_status || pimpl_->batch_commands.empty() || pimpl_->buffer_list_.empty()) { + prepareExit(); + return exit_status; + } + + // Iterate through the buffers that were specified on the command line + bool final_success = false; + vector::iterator buf_it = command_line_buffers.begin(); + for (; buf_it != command_line_buffers.end(); ++buf_it) { + Buffer * buf = *buf_it; + vector::const_iterator bcit = pimpl_->batch_commands.begin(); + vector::const_iterator bcend = pimpl_->batch_commands.end(); + DispatchResult dr; + for (; bcit != bcend; ++bcit) { + LYXERR(Debug::ACTION, "Buffer::dispatch: cmd: " << *bcit); + buf->dispatch(*bcit, dr); + final_success |= !dr.error(); + } + } + prepareExit(); + return !final_success; } @@ -563,10 +577,8 @@ void LyX::execCommands() // if some files were specified at command-line we assume that the // user wants to edit *these* files and not to restore the session. for (size_t i = 0; i != pimpl_->files_to_load_.size(); ++i) { - FileName const abs_path = - support::makeAbsPath(pimpl_->files_to_load_[i]); lyx::dispatch( - FuncRequest(LFUN_FILE_OPEN, abs_path.absoluteFilePath())); + FuncRequest(LFUN_FILE_OPEN, pimpl_->files_to_load_[i])); } // clear this list to save a few bytes of RAM pimpl_->files_to_load_.clear(); @@ -668,7 +680,7 @@ static void error_handler(int err_sig) if (!msg.empty()) { lyxerr << "\nlyx: " << msg << endl; // try to make a GUI message - Alert::error(_("LyX crashed!"), msg); + Alert::error(_("LyX crashed!"), msg, true); } // Deinstall the signal handlers @@ -707,6 +719,96 @@ void LyX::printError(ErrorItem const & ei) cerr << to_utf8(tmp) << endl; } +#if defined (USE_MACOSX_PACKAGING) +namespace { + // Unexposed--extract an environment variable name from its NAME=VALUE + // representation + std::string varname(const char* line) + { + size_t nameLen = strcspn(line, "="); + if (nameLen == strlen(line)) { + return std::string(); + } else { + return std::string(line, nameLen); + } + } +} + +void cleanDuplicateEnvVars() +{ + std::set seen; + std::set dupes; + + // Create a list of the environment variables that appear more than once + for (char **read = *_NSGetEnviron(); *read; read++) { + std::string name = varname(*read); + if (name.size() == 0) { + continue; + } + if (seen.find(name) != seen.end()) { + dupes.insert(name); + } else { + seen.insert(name); + } + } + + // Loop over the list of duplicated variables + std::set::iterator dupe = dupes.begin(); + std::set::iterator const dend = dupes.end(); + for (; dupe != dend; ++dupe) { + const char *name = (*dupe).c_str(); + char *val = getenv(name); + if (val != NULL) { + LYXERR(Debug::INIT, "Duplicate environment variable: " << name); + // unsetenv removes *all* instances of the variable from the environment + unsetenv(name); + + // replace with the value from getenv (in practice appears to be the + // first value in the list) + setenv(name, val, 0); + } + } +} +#endif + + +static void initTemplatePath() +{ + FileName const package_template_path = + FileName(addName(package().system_support().absFileName(), "templates")); + + if (lyxrc.template_path.empty()) { + lyxrc.template_path = package_template_path.absFileName(); + } +#if defined (USE_MACOSX_PACKAGING) + FileName const user_template_path = + FileName(addName(package().user_support().absFileName(), "templates")); + + if (package_template_path != FileName(lyxrc.template_path) && + user_template_path != FileName(lyxrc.template_path)) + { + return; + } + FileName const user_template_link = + FileName(addName(user_template_path.absFileName(),"SystemTemplates")); + if (user_template_link.isSymLink() && !equivalent(user_template_link, package_template_path)) { + user_template_link.removeFile(); + } + if (!user_template_link.exists()) { + if (!package_template_path.link(user_template_link)) { + FileName const user_support = package().user_support(); + if (user_support.exists() && user_support.isDirectory()) { + LYXERR(Debug::INIT, "Cannot create symlink " + user_template_link.absFileName()); + lyxrc.template_path = package_template_path.absFileName(); + } + return; + } + LYXERR(Debug::INIT, "Symlink \"" << user_template_link.absFileName() << "\" created."); + } + lyxrc.template_path = user_template_path.absFileName(); +#endif +} + bool LyX::init() { @@ -719,6 +821,10 @@ bool LyX::init() signal(SIGTERM, error_handler); // SIGPIPE can be safely ignored. +#if defined (USE_MACOSX_PACKAGING) + cleanDuplicateEnvVars(); +#endif + lyxrc.tempdir_path = package().temp_dir().absFileName(); lyxrc.document_path = package().document_dir().absFileName(); @@ -726,10 +832,7 @@ bool LyX::init() lyxrc.example_path = addPath(package().system_support().absFileName(), "examples"); } - if (lyxrc.template_path.empty()) { - lyxrc.template_path = addPath(package().system_support().absFileName(), - "templates"); - } + initTemplatePath(); // init LyXDir environment variable string const lyx_dir = package().lyx_dir().absFileName(); @@ -758,7 +861,7 @@ bool LyX::init() return false; // Set the PATH correctly. -#if !defined (USE_POSIX_PACKAGING) +#if !defined (USE_POSIX_PACKAGING) && !defined (USE_HAIKU_PACKAGING) // Add the directory containing the LyX executable to the path // so that LyX can find things like tex2lyx. if (package().build_support().empty()) @@ -769,11 +872,13 @@ bool LyX::init() // Check that user LyX directory is ok. { - string const lock_file = package().user_support().absFileName() + ".lyx_configure_lock"; + string const lock_file = package().getConfigureLockName(); int fd = fileLock(lock_file.c_str()); if (queryUserLyXDir(package().explicit_user_support())) { - reconfigureUserLyXDir(); + package().reconfigureUserLyXDir(""); + // Now the user directory is present on first start. + initTemplatePath(); } fileUnlock(fd, lock_file.c_str()); } @@ -846,6 +951,7 @@ bool LyX::init() lyxrc.print(); os::windows_style_tex_paths(lyxrc.windows_style_tex_paths); + // Prepend path prefix a second time to take the user preferences into a account if (!lyxrc.path_prefix.empty()) prependEnvPath("PATH", replaceEnvironmentPath(lyxrc.path_prefix)); @@ -899,27 +1005,6 @@ void emergencyCleanup() } -// return true if file does not exist or is older than configure.py. -static bool needsUpdate(string const & file) -{ - // We cannot initialize configure_script directly because the package - // is not initialized yet when static objects are constructed. - static FileName configure_script; - static bool firstrun = true; - if (firstrun) { - configure_script = - FileName(addName(package().system_support().absFileName(), - "configure.py")); - firstrun = false; - } - - FileName absfile = - FileName(addName(package().user_support().absFileName(), file)); - return !absfile.exists() - || configure_script.lastModified() > absfile.lastModified(); -} - - bool LyX::queryUserLyXDir(bool explicit_userdir) { // Does user directory exist? @@ -927,10 +1012,10 @@ bool LyX::queryUserLyXDir(bool explicit_userdir) if (sup.exists() && sup.isDirectory()) { first_start = false; - return needsUpdate("lyxrc.defaults") - || needsUpdate("lyxmodules.lst") - || needsUpdate("textclass.lst") - || needsUpdate("packages.lst"); + return configFileNeedsUpdate("lyxrc.defaults") + || configFileNeedsUpdate("lyxmodules.lst") + || configFileNeedsUpdate("textclass.lst") + || configFileNeedsUpdate("packages.lst"); } first_start = !explicit_userdir; @@ -1089,9 +1174,9 @@ int parse_version(string const &, string const &, string &) { cout << "LyX " << lyx_version << " (" << lyx_release_date << ")" << endl; - cout << to_utf8(bformat(_("Built on %1$s[[date]], %2$s[[time]]"), - from_ascii(__DATE__), from_ascii(__TIME__))) << endl; - + if (string(lyx_git_commit_hash) != "none") + cout << to_utf8(_(" Git commit hash ")) + << string(lyx_git_commit_hash).substr(0,8) << endl; cout << lyx_version_info << endl; exit(0); return 0; @@ -1244,7 +1329,7 @@ void LyX::easyParse(int & argc, char * argv[]) cmdmap["-userdir"] = parse_userdir; cmdmap["-x"] = parse_execute; cmdmap["--execute"] = parse_execute; - cmdmap["-e"] = parse_export; + cmdmap["-e"] = parse_export; cmdmap["--export"] = parse_export; cmdmap["-E"] = parse_export_to; cmdmap["--export-to"] = parse_export_to; @@ -1297,7 +1382,7 @@ FuncStatus getStatus(FuncRequest const & action) } -void dispatch(FuncRequest const & action) +DispatchResult const & dispatch(FuncRequest const & action) { LAPPERR(theApp()); return theApp()->dispatch(action); @@ -1307,7 +1392,7 @@ void dispatch(FuncRequest const & action) void dispatch(FuncRequest const & action, DispatchResult & dr) { LAPPERR(theApp()); - return theApp()->dispatch(action, dr); + theApp()->dispatch(action, dr); }