home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
src
/
commands.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-06
|
16KB
|
575 lines
/* commands.c -- Interactive calling of commands/functions
Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Jade is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#include <string.h>
_PR void commands_init(void);
/* Symbols of the Lisp functions called to get input. */
static VALUE sym_prompt_for_function, sym_prompt_for_buffer,
sym_prompt_for_char, sym_prompt_for_command, sym_prompt_for_directory,
sym_prompt_for_file, sym_prompt_for_number, sym_prompt_for_string,
sym_prompt_for_symbol, sym_prompt_for_variable, sym_prompt_for_lisp,
sym_read_event;
static VALUE sym_interactive;
/* Prefix argument for the next command and the current command. */
static VALUE prefix_arg, current_prefix_arg;
/* Command being executed and command last executed. */
_PR VALUE this_command, last_command;
VALUE this_command, last_command;
_PR VALUE var_this_command(VALUE val);
DEFUN("this-command", var_this_command, subr_this_command, (VALUE val), V_Var, DOC_this_command) /*
::doc:this_command::
This variable holds the command currently being evaluated, or nil if no
command is active. The `command' is whatever is being evaluated; it could
be a function, a form or even a list of forms (from a menu).
::end:: */
{
if(val)
this_command = val;
return(this_command);
}
_PR VALUE var_last_command(VALUE val);
DEFUN("last-command", var_last_command, subr_last_command, (VALUE val), V_Var, DOC_last_command) /*
::doc:last_command::
This variable holds the last interactive command evaluated. This will either
be from a keybinding or a menu. Setting the value of the `next-keymap-path'
variable is not considered a command. After a command finishes this variable
takes the value of `this-command'.
::end:: */
{
if(val)
last_command = val;
return(last_command);
}
_PR VALUE var_prefix_arg(VALUE val);
DEFUN("prefix-arg", var_prefix_arg, subr_prefix_arg, (VALUE val), V_Var, DOC_prefix_arg) /*
::doc:prefix_arg::
Value of the prefix argument for the next command.
::end:: */
{
if(val)
prefix_arg = val;
return(prefix_arg);
}
_PR VALUE var_current_prefix_arg(VALUE val);
DEFUN("current-prefix-arg", var_current_prefix_arg, subr_current_prefix_arg, (VALUE val), V_Var, DOC_current_prefix_arg) /*
::doc:current_prefix_arg::
Value of the prefix argument for the current command.
::end:: */
{
if(val)
current_prefix_arg = val;
return(current_prefix_arg);
}
/* Search the definition of the command CMD for an interactive calling
spec. Return it or NULL. */
static VALUE
interactive_spec(VALUE cmd)
{
VALUE fun, spec = NULL;
if(SYMBOLP(cmd))
fun = cmd_symbol_function(cmd, sym_t);
else
fun = cmd;
if(!VOIDP(fun) && !NILP(fun))
{
if((VTYPE(fun) >= V_Subr0) && (VTYPE(fun) <= V_SubrN))
spec = VSUBR(fun)->subr_IntSpec;
else if(CONSP(fun))
{
if(VCAR(fun) == sym_autoload)
{
VALUE tmp = move_down_list(fun, 2);
if(CONSP(tmp) && !NILP(VCAR(tmp)))
{
GCVAL gcv_cmd;
PUSHGC(gcv_cmd, cmd);
fun = load_autoload(cmd, fun);
POPGC;
if(!fun || !CONSP(fun))
return(NULL);
}
else
return(NULL);
}
if(VCAR(fun) == sym_lambda)
{
/* A lambda expression, test its first proper form. */
fun = move_down_list(fun, 2);
if(CONSP(fun)
&& (STRINGP(VCAR(fun)) || NUMBERP(VCAR(fun)))
&& CONSP(VCDR(fun)))
{
/* A doc-string */
fun = VCDR(fun);
}
if(CONSP(fun))
{
fun = VCAR(fun);
if(CONSP(fun)
&& (VCAR(fun) == sym_interactive))
{
/* got it. */
spec = CONSP(VCDR(fun)) ? VCAR(VCDR(fun)) : sym_nil;
}
}
}
}
}
return(spec);
}
_PR VALUE cmd_call_command(VALUE cmd, VALUE arg);
DEFUN_INT("call-command", cmd_call_command, subr_call_command, (VALUE cmd, VALUE cmd_arg), V_Subr2, DOC_call_command, "CEnter command:\nP") /*
::doc:call_command::
call-command COMMAND [PREFIX-ARG]
Invoke the command COMMAND. This can be one of,
1. A symbol whose function value is to be called, the symbol must be of
type `commandp'; any interactive calling specification will be
used to find arguments to give to the function. (see `interactive')
2. A lambda-expression to call as a function name
3. A single Lisp form to be evaluated by eval
If PREFIX-ARG is non-nil it specifies the value of the COMMAND's
current-prefix-arg. This is used in call-command's interactive spec so that
any entered arg is given to the invoked COMMAND.
::end:: */
{
VALUE res = NULL;
this_command = cmd;
if(last_command == sym_t)
undo_distinct(); /* last was an insertion */
undo_new_group();
/* Move the prefix arg. */
if(NILP(cmd_arg))
cmd_arg = prefix_arg;
prefix_arg = sym_nil;
current_prefix_arg = cmd_arg;
if(SYMBOLP(cmd) || (CONSP(cmd) && VCAR(cmd) == sym_lambda))
{
/* A named command; call it properly taking note of any interactive
declaration. */
VALUE int_spec = interactive_spec(cmd);
VALUE args = sym_nil;
VALUE *argsp = &args;
GCVAL gcv_cmd;
bool clear_block = FALSE;
if(int_spec == NULL)
{
cmd_signal(sym_error, list_2(MKSTR("Not a command"), cmd));
goto exit;
}
PUSHGC(gcv_cmd, cmd);
if(STRINGP(int_spec))
{
u_char *spec_str = VSTR(int_spec);
u_char c;
GCVAL gcv_args;
while(1)
{
/* check for read-only flag */
if(*spec_str == '*')
{
if(read_only(curr_vw->vw_Tx))
{
POPGC;
goto exit;
}
else
spec_str++;
}
else if(*spec_str == '-')
{
/* clear block after building args. */
clear_block = TRUE;
spec_str++;
}
else
break;
}
PUSHGC(gcv_args, args);
while((c = *spec_str++) != 0)
{
VALUE prompt, arg = sym_nil;
if(c != '\n')
{
/* Non-null code. */
bool can_be_nil = FALSE;
if(*spec_str == '\n')
{
/* no prompt */
prompt = sym_nil;
spec_str++;
}
else
{
/* copy the prompt */
u_char *end = memchr(spec_str, '\n',
STRING_LEN(int_spec) -
(spec_str - VSTR(int_spec)));
if(!end)
end = VSTR(int_spec) + STRING_LEN(int_spec);
prompt = string_dupn(spec_str, end - spec_str);
if(memchr(spec_str, '%', end - spec_str))
{
/* Format characters; format it. */
prompt = cmd_format(cmd_cons(sym_nil,
cmd_cons(prompt, args)));
if(!prompt || !STRINGP(prompt))
prompt = string_dupn(spec_str, end - spec_str);
}
spec_str = *end ? end + 1 : end;
}
switch(c)
{
case 'a':
arg = call_lisp1(sym_prompt_for_function, prompt);
break;
case 'b':
arg = call_lisp2(sym_prompt_for_buffer, prompt, sym_t);
break;
case 'B':
arg = call_lisp1(sym_prompt_for_buffer, prompt);
break;
case 'c':
arg = call_lisp1(sym_prompt_for_char, prompt);
break;
case 'C':
arg = call_lisp1(sym_prompt_for_command, prompt);
break;
case 'd':
arg = cmd_cursor_pos();
break;
case 'D':
arg = call_lisp1(sym_prompt_for_directory, prompt);
break;
case 'e':
arg = cmd_current_event();
break;
case 'E':
arg = cmd_current_event_string();
break;
case 'f':
arg = call_lisp2(sym_prompt_for_file, prompt, sym_t);
break;
case 'F':
arg = call_lisp1(sym_prompt_for_file, prompt);
break;
case 'k':
arg = call_lisp1(sym_read_event, prompt);
break;
case 'm':
case 'M':
arg = (c == 'm') ? cmd_block_start(sym_nil)
: cmd_block_end(sym_nil);
if(!arg || NI