CmdDef.cpp/h: A class that manages command definitions. The definitions are

by default read from lib/commands/default.def 
              A .def file allows to define a command with
              \define "Name" "lfun"
              where Name is the name of the new command and lfun is the code
              to be executed.
              \def_file "FileName"
              allows to include another .def file.
              The implementation of CmdDef is similar to KeyMap, i.e. there is 
              one instance created in the LyX.cpp that reads the .def file, holds 
              a list containing all definitions, and supplies access methods.


LFUN_CALL:    The new lfun is used to execute a command definition, e.g.
              call Name

If a toolbar item has the associated action "call Name" then the image 
lib/images/commands/Name.png is used for the button.



git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@21093 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Bernhard Roider 2007-10-20 23:27:03 +00:00
parent 3e6d4a6168
commit 1a77c867a2
18 changed files with 424 additions and 3 deletions

View File

@ -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 * .)

View File

@ -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),

View File

@ -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

View File

@ -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 \

19
lib/commands/default.def Normal file
View File

@ -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!

202
src/CmdDef.cpp Normal file
View File

@ -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 <config.h>
#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<CmdDefInfo> info;
info.reset(new CmdDefInfo(func));
cmdDefMap[name2] = info;
return CmdDefOk;
}
} // namespace lyx

87
src/CmdDef.h Normal file
View File

@ -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 <boost/shared_ptr.hpp>
#include <vector>
#include <deque>
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<std::string, boost::shared_ptr<CmdDefInfo> > 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

View File

@ -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),

View File

@ -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;

View File

@ -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<KeyMap> toplevel_keymap_;
///
boost::scoped_ptr<CmdDef> toplevel_cmddef_;
///
boost::scoped_ptr<Server> lyx_server_;
///
boost::scoped_ptr<ServerSocket> 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());

View File

@ -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();

View File

@ -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 },

View File

@ -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()),

View File

@ -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
//

View File

@ -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;

View File

@ -100,6 +100,8 @@ liblyxcore_la_SOURCES = \
Changes.h \
Chktex.cpp \
Chktex.h \
CmdDef.cpp \
CmdDef.h \
Color.cpp \
Color.h \
config.h.in \

View File

@ -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;

View File

@ -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
};