diff --git a/development/cmake/Install.cmake b/development/cmake/Install.cmake index 02fa35c542..4629d7e00f 100755 --- a/development/cmake/Install.cmake +++ b/development/cmake/Install.cmake @@ -16,12 +16,13 @@ endmacro(lyx_install) lyx_install(${TOP_SRC_DIR}/lib bind bind . de fi pt sv) +lyx_install(${TOP_SRC_DIR}/lib commands def .) lyx_install(${TOP_SRC_DIR}/lib doc lyx . cs da de es eu fr he hu it nl nb pl pt ro ru sk sl sv) lyx_install(${TOP_SRC_DIR}/lib doc * clipart) lyx_install(${TOP_SRC_DIR}/lib doc/es * clipart) lyx_install(${TOP_SRC_DIR}/lib examples * . ca cs da de es eu fr he hu it nl pl pt ro ru sl) lyx_install(${TOP_SRC_DIR}/lib fonts * .) -lyx_install(${TOP_SRC_DIR}/lib images * . math) +lyx_install(${TOP_SRC_DIR}/lib images * . math commands) lyx_install(${TOP_SRC_DIR}/lib kbd * .) lyx_install(${TOP_SRC_DIR}/lib layouts * .) lyx_install(${TOP_SRC_DIR}/lib lyx2lyx * .) diff --git a/development/scons/SConstruct b/development/scons/SConstruct index 2e6ffe13d7..f003635094 100644 --- a/development/scons/SConstruct +++ b/development/scons/SConstruct @@ -1571,7 +1571,8 @@ ui_files = [frontend_env.Uic4('$BUILDDIR/src/frontends/qt4/ui/%s' % x.split('.') resource = frontend_env.Qrc(frontend_env.qtResource( '$BUILDDIR/src/frontends/qt4/Resource.qrc', ['$TOP_SRCDIR/lib/images/%s' % x for x in lib_images_files] + - ['$TOP_SRCDIR/lib/images/math/%s' % x for x in lib_images_math_files])) + ['$TOP_SRCDIR/lib/images/math/%s' % x for x in lib_images_math_files] + + ['$TOP_SRCDIR/lib/images/commands/%s' % x for x in lib_images_commands_files])) # # moc qt4_moc_files, the moced files are included in the original files # @@ -1933,6 +1934,7 @@ if 'install' in BUILD_TARGETS or 'installer' in BUILD_TARGETS: ('bind/fi', lib_bind_fi_files), ('bind/pt', lib_bind_pt_files), ('bind/sv', lib_bind_sv_files), + ('commands', lib_commands_files), ('doc', lib_doc_files), ('doc/biblio', lib_doc_biblio_files), ('doc/clipart', lib_doc_clipart_files), @@ -1978,6 +1980,7 @@ if 'install' in BUILD_TARGETS or 'installer' in BUILD_TARGETS: ('fonts', lib_fonts_files), ('images', lib_images_files), ('images/math', lib_images_math_files), + ('images/commands', lib_images_commands_files), ('kbd', lib_kbd_files), ('layouts', lib_layouts_files + lib_layouts_inc_files + lib_layouts_module_files), ('lyx2lyx', lib_lyx2lyx_files), diff --git a/development/scons/scons_manifest.py b/development/scons/scons_manifest.py index af042da107..002d050d4d 100644 --- a/development/scons/scons_manifest.py +++ b/development/scons/scons_manifest.py @@ -2028,6 +2028,10 @@ lib_images_math_extra_files = Split(''' ''') +lib_images_commands_files = Split(''' +''') + + lib_images_attic_extra_files = Split(''' dialog-show_mathpanel.png ''') @@ -2695,6 +2699,11 @@ lib_bind_de_files = Split(''' ''') +lib_commands_files = Split(''' + default.def +''') + + boost_extra_files = Split(''' LICENSE_1_0.txt Makefile.am diff --git a/lib/Makefile.am b/lib/Makefile.am index 3d16f140f7..6e4421ff46 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -64,6 +64,10 @@ dist_bind_DATA = \ bind/xemacs.bind \ bind/aqua.bind +commandsdir = $(pkgdatadir)/commands +dist_commands_DATA = \ + commands/default.cmd + caexamplesdir = $(pkgdatadir)/examples/ca dist_caexamples_DATA = \ examples/ca/splash.lyx @@ -854,6 +858,9 @@ dist_imagesmath_DATA = \ images/math/xi2.png \ images/math/zeta.png +imagescommandsdir = $(imagesdir)/commands +dist_imagescommands_DATA = + kbddir = $(pkgdatadir)/kbd dist_kbd_DATA = \ kbd/american-2.kmap \ diff --git a/lib/commands/default.def b/lib/commands/default.def new file mode 100644 index 0000000000..c2a60c6c8d --- /dev/null +++ b/lib/commands/default.def @@ -0,0 +1,19 @@ +# -*- text -*- + +# file default.def +# This file is part of LyX, the document processor. +# Licence details can be found in the file COPYING. + +# author Bernhard Roider + +# Full author contact details are available in file CREDITS. + +# This is the default command definition file. + +# DO NOT CHANGE THIS DEFAULT COMMAND DEFINITION FILE! It will be replaced +# with every new install of LyX and your changes will be lost. +# Instead, customize a copy of this file placed in +# ~/.lyx/commands/default.bind +# +# Happy tuning! + diff --git a/src/CmdDef.cpp b/src/CmdDef.cpp new file mode 100644 index 0000000000..2508fab865 --- /dev/null +++ b/src/CmdDef.cpp @@ -0,0 +1,202 @@ +/** + * \file CmdDef.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bernhard Roider + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "CmdDef.h" + +#include "LyXAction.h" +#include "debug.h" +#include "Lexer.h" + +#include "support/filetools.h" +#include "support/lstrings.h" + +using std::endl; +using std::string; + +namespace lyx { + +using support::FileName; +using support::i18nLibFileSearch; +using support::trim; + + +namespace { + +enum CmdDefTags { + BN_DEFFILE, + BN_DEFINE +}; + +keyword_item cmdDefTags[] = { + { "\\def_file", BN_DEFFILE }, + { "\\define", BN_DEFINE } +}; + +} + + +bool CmdDef::read(string const & def_file) +{ + const int cmdDefCount = sizeof(cmdDefTags) / sizeof(keyword_item); + + Lexer lexrc(cmdDefTags, cmdDefCount); + if (lyxerr.debugging(Debug::PARSER)) + lexrc.printTable(lyxerr); + + FileName const tmp(i18nLibFileSearch("commands", def_file, "def")); + lexrc.setFile(tmp); + if (!lexrc.isOK()) { + lyxerr << "CmdDef::read: cannot open def file:" + << tmp << endl; + return false; + } + +// LYXERR(Debug::KBMAP) << "Reading def file:" << tmp << endl; + + bool error = false; + while (lexrc.isOK()) { + switch (lexrc.lex()) { + case Lexer::LEX_UNDEF: + lexrc.printError("Unknown tag `$$Token'"); + error = true; + continue; + case Lexer::LEX_FEOF: + continue; + case BN_DEFINE: + { + string name, def; + + if (lexrc.next()) { + name = lexrc.getString(); + } else { + lexrc.printError("BN_DEFINE: Missing command name"); + error = true; + break; + } + + if (lexrc.next(true)) { + def = lexrc.getString(); + } else { + lexrc.printError("BN_DEFINE: missing command definition"); + error = true; + break; + } + + newCmdDefResult e = newCmdDef(name, def); + switch (e) { + case CmdDefNameEmpty: + lexrc.printError("BN_DEFINE: Command name is empty"); + error = true; + break; + case CmdDefExists: + lexrc.printError("BN_DEFINE: Command `" + name + "' already defined"); + error = true; + break; + case CmdDefInvalid: + lexrc.printError("BN_DEFINE: Command definition for `" + name + "' is not valid"); + error = true; + } + + break; + } + case BN_DEFFILE: + if (lexrc.next()) { + string const tmp(lexrc.getString()); + error |= !read(tmp); + } else { + lexrc.printError("BN_DEFFILE: Missing file name"); + error = true; + break; + + } + break; + } + } + + if (error) + lyxerr << "CmdDef::read: error while reading def file:" + << tmp << endl; + return !error; +} + + +bool CmdDef::lock(string const & name, FuncRequest & func) +{ + if (cmdDefMap.empty()) + { + func = FuncRequest::unknown; + return false; + } + + string const name2 = trim(name); + + CmdDefMap::const_iterator pos = cmdDefMap.find(name2); + + if (pos == cmdDefMap.end()) + { + func = FuncRequest::unknown; + return false; + } + + if (pos->second->locked) + { + func = FuncRequest::noaction; + return false; + } + + pos->second->locked = true; + func = pos->second->func; + return true; +} + + +void CmdDef::release(string const & name) +{ + if (cmdDefMap.empty()) + return; + + string const name2 = trim(name); + + CmdDefMap::const_iterator pos = cmdDefMap.find(name2); + + if (pos == cmdDefMap.end()) + return; + + pos->second->locked = false; +} + +CmdDef::newCmdDefResult CmdDef::newCmdDef(string const & name, + string const & def) +{ + string const name2 = trim(name); + + if (name2.empty()) + return CmdDefNameEmpty; + + if (cmdDefMap.find(name) != cmdDefMap.end()) + return CmdDefExists; + + FuncRequest func = lyxaction.lookupFunc(def); + if (func.action == LFUN_NOACTION || + func.action == LFUN_UNKNOWN_ACTION) { + return CmdDefInvalid; + } + + boost::shared_ptr info; + info.reset(new CmdDefInfo(func)); + cmdDefMap[name2] = info; + + return CmdDefOk; +} + + +} // namespace lyx diff --git a/src/CmdDef.h b/src/CmdDef.h new file mode 100644 index 0000000000..2b15f5565b --- /dev/null +++ b/src/CmdDef.h @@ -0,0 +1,87 @@ +// -*- C++ -*- +/** + * \file CmdDef.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Bernhard Roider + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef CMDDEF_H +#define CMDDEF_H + +#include "FuncRequest.h" + +#include "support/docstream.h" + +#include + +#include +#include + + +namespace lyx { + +/// Creates command definitions +class CmdDef { +private: + /// information for a definition + struct CmdDefInfo { + CmdDefInfo(FuncRequest const & f): func(f), locked(false) {} + /// the expanded FuncRequest + FuncRequest func; + /// to avoid recursive calls + bool locked; + }; + + + /// type for map between a macro name and its info + typedef std::map > CmdDefMap; + +public: + + /// Parse a def file + bool read(std::string const & def_file); + + /** + * Look up a definition, lock it and return the + * associated action if it is not locked. + * @param name the name of the command + * @param func contains the action on success + * @return true if lock was successful + */ + bool lock(std::string const & name, FuncRequest & func); + + /// release a locked definition + void release(std::string const & name); + +private: + + /// possible reasons for not allowed definitions + enum newCmdDefResult { + CmdDefOk, + CmdDefNameEmpty, + CmdDefInvalid, + CmdDefExists + }; + + /** + * Add a new command definition. + * @param name internal recursion level + */ + newCmdDefResult newCmdDef(std::string const & name, + std::string const & def); + + /// + CmdDefMap cmdDefMap; +}; + +/// Implementation is in LyX.cpp +extern CmdDef & theTopLevelCmdDef(); + + +} // namespace lyx + +#endif // CMDDEF_H diff --git a/src/FuncRequest.cpp b/src/FuncRequest.cpp index 296728aca2..634111f147 100644 --- a/src/FuncRequest.cpp +++ b/src/FuncRequest.cpp @@ -24,6 +24,8 @@ using std::string; namespace lyx { +FuncRequest const FuncRequest::unknown(LFUN_UNKNOWN_ACTION); +FuncRequest const FuncRequest::noaction(LFUN_NOACTION); FuncRequest::FuncRequest(Origin o) : action(LFUN_NOACTION), origin(o), x(0), y(0), diff --git a/src/FuncRequest.h b/src/FuncRequest.h index e5c7afadad..9ea6dc4344 100644 --- a/src/FuncRequest.h +++ b/src/FuncRequest.h @@ -67,6 +67,10 @@ public: /// access the whole argument docstring const & argument() const { return argument_; } + /// + static FuncRequest const unknown; + /// + static FuncRequest const noaction; public: // should be private /// the action kb_action action; diff --git a/src/LyX.cpp b/src/LyX.cpp index 85abc0f1d7..4b326b137d 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -29,6 +29,7 @@ #include "Format.h" #include "gettext.h" #include "KeyMap.h" +#include "CmdDef.h" #include "Language.h" #include "Session.h" #include "Color.h" @@ -164,6 +165,8 @@ struct LyX::Singletons /// boost::scoped_ptr toplevel_keymap_; /// + boost::scoped_ptr toplevel_cmddef_; + /// boost::scoped_ptr lyx_server_; /// boost::scoped_ptr lyx_socket_; @@ -315,6 +318,13 @@ KeyMap & LyX::topLevelKeymap() } +CmdDef & LyX::topLevelCmdDef() +{ + BOOST_ASSERT(pimpl_->toplevel_cmddef_.get()); + return *pimpl_->toplevel_cmddef_.get(); +} + + Converters & LyX::converters() { return pimpl_->converters_; @@ -961,6 +971,10 @@ bool LyX::init() // Set the language defined by the user. //setGuiLanguage(lyxrc.gui_language); + // Set up command definitions + pimpl_->toplevel_cmddef_.reset(new CmdDef); + pimpl_->toplevel_cmddef_->read(lyxrc.def_file); + // Set up bindings pimpl_->toplevel_keymap_.reset(new KeyMap); defaultKeyBindings(pimpl_->toplevel_keymap_.get()); diff --git a/src/LyX.h b/src/LyX.h index 8347dba478..e7b18f40e3 100644 --- a/src/LyX.h +++ b/src/LyX.h @@ -38,6 +38,7 @@ class Mover; class Movers; class Session; class KeyMap; +class CmdDef; extern bool use_gui; @@ -86,6 +87,9 @@ public: KeyMap & topLevelKeymap(); KeyMap const & topLevelKeymap() const; + /// + CmdDef & topLevelCmdDef(); + /// Converters & converters(); Converters & systemConverters(); diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index fc2d9a3d64..325252e423 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -134,6 +134,7 @@ void LyXAction::init() { LFUN_BUFFER_WRITE, "buffer-write", ReadOnly, Buffer }, { LFUN_BUFFER_WRITE_AS, "buffer-write-as", ReadOnly, Buffer }, { LFUN_BUFFER_WRITE_ALL, "buffer-write-all", ReadOnly, Buffer }, + { LFUN_CALL, "call", NoBuffer, System }, { LFUN_CANCEL, "cancel", NoBuffer, System }, { LFUN_CAPTION_INSERT, "caption-insert", Noop, Edit }, { LFUN_CHAR_BACKWARD, "char-backward", ReadOnly | NoUpdate, Edit }, diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 0e78caf8f2..247136330d 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -28,6 +28,7 @@ #include "BufferList.h" #include "BufferParams.h" #include "BufferView.h" +#include "CmdDef.h" #include "Color.h" #include "Cursor.h" #include "CutAndPaste.h" @@ -664,6 +665,23 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const FuncRequest func(lyxaction.lookupFunc(firstcmd)); func.origin = cmd.origin; flag = getStatus(func); + break; + } + + case LFUN_CALL: { + FuncRequest func; + std::string name(to_utf8(cmd.argument())); + if (LyX::ref().topLevelCmdDef().lock(name, func)) { + func.origin = cmd.origin; + flag = getStatus(func); + LyX::ref().topLevelCmdDef().release(name); + } else { + // catch recursion or unknown command definiton + // all operations until the recursion or unknown command + // definiton occures are performed, so set the state to enabled + enable = true; + } + break; } case LFUN_BUFFER_NEW: @@ -1632,6 +1650,28 @@ void LyXFunc::dispatch(FuncRequest const & cmd) break; } + case LFUN_CALL: { + FuncRequest func; + if (LyX::ref().topLevelCmdDef().lock(argument, func)) { + func.origin = cmd.origin; + dispatch(func); + LyX::ref().topLevelCmdDef().release(argument); + } else { + if (func.action == LFUN_UNKNOWN_ACTION) { + // unknown command definition + lyxerr << "Warning: unknown command definition `" + << argument << "'" + << endl; + } else { + // recursion detected + lyxerr << "Warning: Recursion in the command definition `" + << argument << "' detected" + << endl; + } + } + break; + } + case LFUN_PREFERENCES_SAVE: { lyxrc.write(makeAbsPath("preferences", package().user_support().absFilename()), diff --git a/src/LyXRC.cpp b/src/LyXRC.cpp index 16358855ee..698a8f294b 100644 --- a/src/LyXRC.cpp +++ b/src/LyXRC.cpp @@ -84,6 +84,7 @@ keyword_item lyxrcTags[] = { { "\\custom_export_command", LyXRC::RC_CUSTOM_EXPORT_COMMAND }, { "\\custom_export_format", LyXRC::RC_CUSTOM_EXPORT_FORMAT }, { "\\date_insert_format", LyXRC::RC_DATE_INSERT_FORMAT }, + { "\\def_file", LyXRC::RC_DEFFILE }, { "\\default_language", LyXRC::RC_DEFAULT_LANGUAGE }, { "\\default_papersize", LyXRC::RC_DEFAULT_PAPERSIZE }, { "\\dialogs_iconify_with_main", LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN }, @@ -189,6 +190,7 @@ LyXRC::LyXRC() void LyXRC::setDefaults() { bind_file = "cua"; + def_file = "default"; ui_file = "default"; // Get printer from the environment. If fail, use default "", // assuming that everything is set up correctly. @@ -370,6 +372,12 @@ int LyXRC::read(Lexer & lexrc) } break; + case RC_DEFFILE: + if (lexrc.next()) { + def_file = os::internal_path(lexrc.getString()); + } + break; + case RC_UIFILE: if (lexrc.next()) { ui_file = os::internal_path(lexrc.getString()); @@ -1226,7 +1234,7 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c << "### LyX, The Document Processor\n" << "###\n" << "### Copyright 1995 Matthias Ettrich\n" - << "### Copyright 1995-2001 The LyX Team.\n" + << "### Copyright 1995-2007 The LyX Team.\n" << "###\n" << "### ========================================================\n" << "\n" @@ -1252,6 +1260,15 @@ void LyXRC::write(ostream & os, bool ignore_system_lyxrc, string const & name) c if (tag != RC_LAST) break; + case RC_DEFFILE: + if (ignore_system_lyxrc || + def_file != system_lyxrc.def_file) { + string const path = os::external_path(def_file); + os << "\\def_file \"" << path << "\"\n"; + } + if (tag != RC_LAST) + break; + // // Misc Section // diff --git a/src/LyXRC.h b/src/LyXRC.h index 01fb3692ea..877c3d9f0b 100644 --- a/src/LyXRC.h +++ b/src/LyXRC.h @@ -58,6 +58,7 @@ public: RC_CUSTOM_EXPORT_COMMAND, RC_CUSTOM_EXPORT_FORMAT, RC_DATE_INSERT_FORMAT, + RC_DEFFILE, RC_DEFAULT_LANGUAGE, RC_DEFAULT_PAPERSIZE, RC_DIALOGS_ICONIFY_WITH_MAIN, @@ -171,6 +172,8 @@ public: /// std::string bind_file; /// + std::string def_file; + /// std::string ui_file; /// std::string printer; diff --git a/src/Makefile.am b/src/Makefile.am index a4eb8f4fda..6c5c9b63ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,8 @@ liblyxcore_la_SOURCES = \ Changes.h \ Chktex.cpp \ Chktex.h \ + CmdDef.cpp \ + CmdDef.h \ Color.cpp \ Color.h \ config.h.in \ diff --git a/src/frontends/qt4/GuiToolbar.cpp b/src/frontends/qt4/GuiToolbar.cpp index 4d19f6dc26..9b727beaf7 100644 --- a/src/frontends/qt4/GuiToolbar.cpp +++ b/src/frontends/qt4/GuiToolbar.cpp @@ -188,6 +188,10 @@ static QIcon getIcon(FuncRequest const & f, bool unknown) path = "math/"; name1 = find_png(to_utf8(f.argument())); break; + case LFUN_CALL: + path = "commands/"; + name1 = to_utf8(f.argument()); + break; default: name2 = lyxaction.getActionName(f.action); name1 = name2; diff --git a/src/lfuns.h b/src/lfuns.h index 7ce7d675bf..2948a6da1a 100644 --- a/src/lfuns.h +++ b/src/lfuns.h @@ -404,6 +404,8 @@ enum kb_action { LFUN_MASTER_BUFFER_VIEW, // Tommaso, 20070920 LFUN_MASTER_BUFFER_UPDATE, // Tommaso, 20070920 LFUN_INFO_INSERT, // bpeng, 20071007 + // 295 + LFUN_CALL, // broider, 20071002 LFUN_LASTACTION // end of the table };