% File: latex.sl -*- mode: SLang; mode: fold -*-
%
% Copyright (c)
% until 2003 Guido Gonzato <
[email protected]> (as Latex4Jed)
% 2003--2007 Jörg Sommer <
[email protected]>
% $Id: latex.sl 205 2007-09-08 13:38:06Z joerg $
%
% -*- This file is part of Jörg's LaTeX Mode (JLM) -*-
%
% Description: In this file are all functions for composing, viewing,
% printing and any related problem. All what have to do
% with an external program and a latex file.
%
% License: This program 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 of
% the License, or (at your option) any later version.
%
% This program 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.
%!Fix me -- TODO:
% font_resize(n): n variable machen
% indent line in Verbatim environment like comments
% use replace_chars()
% right, left bei |
% g\bigl( ... )
% \{ confuses indention
% auto-sizing of braces, e.g. "( ()" + ")" -> "\big( () \big)"
% customization stuff
% move to comment.sl
% preview of equations with UTF-8
% dialog for open subfiles (\input, \include)
if (length(where("latex" == _get_namespaces())))
use_namespace("latex");
else
implements("latex");
#ifnexists profile_on
% profiling does not work with stack check enabled.
autoload("Global->enable_stack_check", "stkcheck");
try
{
enable_stack_check();
}
catch OpenError: {} % stkcheck not found in the path
#endif
static variable MODE="LaTeX";
define debug_msg(msg)
{
#if (BATCH)
message(msg);
#else
whatbuf();
setbuf("*traceback*");
eob();
variable x = make_printable_string(string(msg));
insert( substr(x, 2, strlen(x) - 2) );
newline();
setbuf( () );
#endif
}
define debug_pos()
{
variable arg;
if (_NARGS)
arg = string( () );
else
arg = "";
debug_msg("line = $what_line, col = "$ + string(what_column()) + "; $arg"$);
}
define debug_print_buf()
{
push_spot();
bob();
push_mark();
eob();
message( bufsubstr() );
pop_spot();
}
public variable Key_Enter = "\r", Key_Space = " ";
foreach ("latex_external->" +
["bibtex", "clearup", "compose", "makeindex", "mrproper",
"pop_log_file", "print", "select_master_file",
"cust_view", "view", "jump_to_master_buffer",
"show_bibtex_log", "show_mkidx_log"])
{
autoload((), "latex_external.sl");
}
foreach ("latex_conv->" +
["colon", "german_lat1", "german_utf8", "native_lat1", "native_utf8",
"ltx209_ltx2e"])
{
autoload((), "latex_conv.sl");
}
foreach ("latex->" +
["pst_update_pic_size", "pst_move_points"])
{
autoload((), "latex_pst.sl");
}
foreach ("latex->typo_" + ["abbrev", "dots", "german_decimal_point", "hyphen",
"percent", "slash"])
{
autoload((), "latex_typo.sl");
}
#if (_jed_version < 9919)
require("x-keydefs");
require("read_with_description");
#else
require("x-keydefs", "Global");
require("read_with_description", "Global");
#endif
%!%+
%\variable{String_Type LaTeX_Template_Dir}
%\synopsis{Directories of template files}
%\description
% You can insert text blocks via Mode->Templates or ^ct. These blocks
% are read from a file that is placed in a directory in this comma
% separated list.
%
% The default is Jed_Home_Directory/latex-templ
%\seealso{templ_insert()}
%!%-
custom_variable("LaTeX_Template_Dir",
path_concat(Jed_Home_Directory, "latex-templ"));
%!%+
%\variable{String_Type LaTeX_Default_Packages}
%\synopsis{List of packages to insert when a template will be inserted}
%\description
% You can insert text blocks via Mode->Templates or ^ct. These blocks can
% include the special sequences %:default:pkgs:% that is replaced by a list
% of \\usepackage commands with the packages given with this variable.
%
% The default is "inputenc:fontenc:babel:fixltx2e:microtype".
%\seealso{templ_insert(), insert_pkgs()}
%!%-
%
http://homepage.ruhr-uni-bochum.de/Georg.Verweyen/latexfuerword.html
custom_variable("LaTeX_Default_Packages",
"inputenc:babel:fontenc:fixltx2e:microtype");
%!%+
%\variable{String_Type LaTeX_Default_Class_Options}
%\synopsis{Default class options for a template}
%\description
% You can insert text blocks via Mode->Templates or ^ct. These blocks can
% include one of the special sequences %:default:classopt:,% or
% %:default:classopt:[% that is replaced by the content of this variable.
%
% The default is "draft".
%\seealso{templ_insert()}
%!%-
custom_variable("LaTeX_Default_Class_Options", "draft");
%!%+
%\variable{Integer_Type LaTeX_Auto_Space_After_Commands}
%\synopsis{Insert a space after a command, if a letter is inserted}
%\description
% If this variable is unequal 0 and you insert a command with
% cmd_insert() which have no arguments the cursor is placed after this
% command. If you then enter a letter, a space is inserted, because would
% treat LaTeX this as part of command which is normally an error.
%
% The default is 1, which means to insert a space, if necessary.
%\seealso{templ_insert()}
%!%-
custom_variable("LaTeX_Auto_Space_After_Commands", 1);
%!%+
%\variable{Integer_Type LaTeX_Indent_First}
%\synopsis{Defines the amount of spaces used for first indention level}
%\description
% Defines the default indention in all environments and open braces.
%
% \begin{xyz}
% text indented by LaTeX_Indent_First
% \cmd{foo% indented by LaTeX_Indent_First
% bar} indented a second time by LaTeX_Indent_First
% \end{xyz}
%
% The default is 2.
%\seealso{LaTeX_Indent_Continued}
%\seealso{LaTeX_Indent_Item}
%!%-
custom_variable("LaTeX_Indent_First", 2);
%!%+
%\variable{Integer_Type LaTeX_Indent_Continued}
%\synopsis{Defines the amount of spaces added for each deeper indention level}
%\description
% Some environments like table, array, align or gather don't allow empty
% lines to structure the LaTeX code. JLM tries to detect the end of line
% in the output and helps structuring the code in this way that all text
% in the same line in the output, but on different lines in the code is
% indented deeper than the first line.
%
% \begin{tabular}{l}
% text this line is indented by LaTeX_Indent_First spaces
% continued l. LaTeX_Indent_First + LaTeX_Indent_Continued
% third line\\ LaTeX_Indent_First + LaTeX_Indent_Continued
% text LaTeX_Indent_First
% \end{tabular}
%
% The default is 3.
%\seealso{LaTeX_Indent_First}
%\seealso{LaTeX_Indent_Item}
%!%-
custom_variable("LaTeX_Indent_Continued", 3);
%!%+
%\variable{Integer_Type LaTeX_Indent_Item}
%\synopsis{Defines the amount of spaces used to indent \item}
%\description
% \begin{itemize}
% \item indented by LaTeX_Indent_Item
% text indented by LaTeX_Indent_First
% \end{itemize}
%
% The default is 1.
%\seealso{LaTeX_Indent_Continued}
%\seealso{LaTeX_Indent_First}
%!%-
custom_variable("LaTeX_Indent_Item", 1);
%!%+
%\variable{Integer_Type LaTeX_Register_New}
%\synopsis{Ask the user about informations for new environments/commands}
%\description
% When a environment or command is inserted with *_prompt and
% it is not known, the user is prompted for the missing informations
% like number of arguments, needed packages and a description.
%
% The default is 1.
%!%-
custom_variable("LaTeX_Register_New", 1);
%!%+
%\variable{String_Type LaTeX_File_New}
%\synopsis{Name of a file, where options of new cmds, envs and pkgs are saved}
%\description
% When a command, environment or package is inserted with *_prompt and
% this variable is a non-empty string, it is used as the name of a file
% where a command is appended to save the new data. Later, you can load
% this file, with evalfile(), to import your config.
%
% The default is NULL.
%\seealso{LaTeX_Register_New}
%!%-
custom_variable("LaTeX_File_New", NULL);
%!%+
%\variable{Integer_Type LaTeX_Typo_Active}
%\synopsis{Enables/Disables typographic functions}
%\description
% Setting this variable to 0 disables all typographic functions. They
% might be work for you language or do silly things, so you don't want
% to use them. Every value different from 0 enables the functions.
%
% The default is 1.
%!%-
custom_variable("LaTeX_Typo_Active", 1);
%!%+
%\variable{Integer_Type LaTeX_Typo_Word_Size}
%\synopsis{Defines the lowest number of characters in a word}
%\description
% Some typographic functions, like typo_slash(), do different things
% depending on the leading/following number of characters is more or
% less than \var{LaTeX_Typo_Word_Size}. The typo_slash() function, e.g.,
% do not replace the / by \slash{} if the number of characters before
% the / is not at least \var{LaTeX_Typo_Word_Size}.
%
% The default is 4.
%!%-
custom_variable("LaTeX_Typo_Word_Size", 4);
%%%%%%%%%%
%
% Declarations needed somewhere before the definition
%
static define array_edit_column_format() { throw NotImplementedError; }
static define boenv() { throw NotImplementedError; }
static define bsearch_matching_brace() { throw NotImplementedError; }
static define cmd_insert() { throw NotImplementedError; }
static define cmd_parse_args() { throw NotImplementedError; }
static define env_name() { throw NotImplementedError; }
static define eoenv() { throw NotImplementedError; }
private define pkg_find() { throw NotImplementedError; }
static define is_escaped() { throw NotImplementedError; }
static define texdoc() { throw NotImplementedError; }
%%%%%%%%%%
%
% Some constants
%
static variable TeX_Command_Chars = "a-zA-Z@*";
%%%%%%%%%%
%
% Tools
%
static define is_commented()
{
% When parse_to_point() says inside a string we can't trust him. The X in
% the following text is not inside of a comment for parse_to_point()
% $\alpha % X
% \beta$
% But parse_to_point() has no informations (define_syntax()) about
% strings, so this should not be a problem.
return parse_to_point() == -2;
}
private define bocomment()
{
!if ( is_commented() )
return 0;
while ( andelse {bfind_char('%')} {is_commented()} );
return 1;
}
private define chop_star(str)
{
if (andelse {str != NULL} {str[-1] == '*'})
return str[[:-2]];
else
return str;
}
static define is_escaped()
{
variable pnt = _get_point();
bskip_chars("\\");
variable pnt2 = _get_point();
_set_point(pnt);
return (pnt - pnt2) mod 2 == 1;
}
private define trim()
{
skip_white();
push_mark();
bskip_white();
if ( looking_at_char(' ') and is_escaped() )
() = right(1);
del_region();
}
static variable verbatim_commands = "bibitem,cite,href,include,includegraphics,input,label,nolinkurl,ref,url";
static variable verbatim_environments = "verbatim,Verbatim";
static define is_verbatim()
{
if ( is_commented() )
return 1;
variable start_mark = create_user_mark();
try
{
bsearch_matching_brace();
push_mark();
bskip_chars(TeX_Command_Chars);
if ( blooking_at("\\") )
{
if ( is_list_element(verbatim_commands, bufsubstr(), ',') )
return 1;
}
else
pop_mark(0);
}
catch DataError;
finally
goto_user_mark(start_mark);
try
{
if ( bfind("\\verb") )
{
() = right(5);
what_char();
() = right(1);
if ( ffind_char( () ) )
() = right(1);
else
return 1;
if (create_user_mark() > start_mark)
return 1;
}
}
finally
goto_user_mark(start_mark);
variable e_name = env_name();
if ( andelse {e_name != NULL}
{is_list_element(verbatim_environments, __tmp(e_name), ',')} )
return 1;
return 0;
}
private variable math_environments = "gather,align,flalign,alignat,multline";
private variable anti_math_commands = "text,mbox,intertext,label,raisebox,footnote,makebox";
static define is_math()
{
if ( is_verbatim() )
return 0;
push_spot();
try
{
variable math_open = 0, math_seen = 0;
forever
{
bskip_chars("^{}$_^[]");
!if ( left(1) ) % bobp() == TRUE
return math_open;
variable is_bracket = what_char() == '[' or what_char() == ']';
if ( orelse {bocomment()} {is_escaped() != is_bracket} )
continue;
switch ( what_char() )
{ case '$':
math_open = not math_open;
math_seen = 1;
}
{ case '^' or case '_': return not math_open; }
{ case '{':
if (math_seen)
return math_open;
% This is for \raisebox, because the text is in the
% second argument
while ( left(1) and looking_at_char('}') )
bsearch_matching_brace();
() = right(1);
push_mark();
bskip_chars(TeX_Command_Chars);
variable cmd_name = bufsubstr();
() = left(1);
if ( looking_at_char('\\') and
is_list_element(anti_math_commands, cmd_name, ',') )
return 0;
}
{ case '}':
bsearch_matching_brace();
push_mark();
bskip_chars(TeX_Command_Chars);
variable cmd = chop_star( bufsubstr() );
() = left(1);
if ( looking_at_char('\\') )
{
switch (cmd)
{ case "begin":
() = right(7);
push_mark();
() = ffind_char('}');
variable e_name = bufsubstr();
if (e_name == "document")
return math_open;
if ( is_list_element(math_environments,
chop_star(e_name), ',') )
return 1;
if ( is_list_element(verbatim_environments,
chop_star(e_name), ',') )
return 0;
if (math_seen)
return math_open;
() = left(strlen(e_name) + 7);
}
{ case "end":
() = right(5);
push_mark();
() = ffind_char('}');
if ( is_list_element("document,"+math_environments,
chop_star(bufsubstr()), ',') )
return math_open;
() = bfind("\\end");
boenv();
}
{ is_list_element("chapter,section,subsection,subsubsection,paragraph",
cmd, ','):
return math_open;
}
{ is_list_element("frac,overline,underbrace", cmd, ','):
% cmd_list[cmd].math
return not math_open;
}
}
else
() = right(1);
}
{ case '[': return 1; }
{ case ']': return math_open; }
}
}
finally
pop_spot();
}
private define str_compress_tex(str)
{
variable a_str = bstring_to_array(str), ins = -1, i;
for (i=0; i < length(a_str); ++i)
{
switch (a_str[i])
{ case '%': % "%.*\n[ \t]*" -> ""
if (ins < 0)
ins = i;
do
++i;
while (andelse {i < length(a_str)} {a_str[i] != '\n'});
do
++i;
while (andelse {i < length(a_str)}
{a_str[i] == '\t' or a_str[i] == ' '});
--i;
continue;
}
{ case '\n': % "\n[ \t]*" -> " "
if (ins < 0)
ins = i;
do
++i;
while (andelse {i < length(a_str)}
{a_str[i] == '\t' or a_str[i] == ' '});
a_str[ins] = ' ';
++ins;
--i;
continue;
}
{ case '\\': % escape seqences \% and \
if (ins >= 0)
{
a_str[ins] = a_str[i];
++ins;
++i;
if (i >= length(a_str))
break;
}
}
{ case ' ' or case '\t':
variable old_i = i;
while (andelse {i+1 < length(a_str)}
{a_str[i+1] == '\t' or a_str[i+1] == ' '})
++i;
if (i - old_i > 0 and ins < 0)
ins = old_i;
}
if (ins >= 0)
{
a_str[ins] = a_str[i];
++ins;
}
}
if (ins == -1)
return str;
else
return unpack("s$ins"$, array_to_bstring(a_str));
}
static define fsearch_matching_brace()
{
if ( is_commented() )
throw UsageError, "Starting inside of a comment is not possible";
variable start_mark = create_user_mark(), open_lbraces = list_new();
if ( looking_at_char('}') )
return;
forever
{
() = right(1);
skip_chars("^{}");
!if ( looking_at_char('{') or looking_at_char('}') )
break;
if ( is_commented() )
{
eol();
continue;
}
if ( is_escaped() )
continue;
switch ( what_char() )
{ case '{':
list_append(open_lbraces, [what_line, what_column()], -1);
}
{ case '}':
if (length(open_lbraces) == 0)
return;
list_delete(open_lbraces, -1);
}
}
goto_user_mark(start_mark);
if (length(open_lbraces) > 0)
throw DataError, "No matching } found for { in line " +
string(open_lbraces[-1][0]) + " column " + string(open_lbraces[-1][1]);
else
throw DataError, "No matching } found";
}
static define bsearch_matching_brace()
{
if ( is_commented() )
throw UsageError, "Starting inside of a comment is not possible";
variable start_mark = create_user_mark(), open_rbraces = list_new();
forever
{
bskip_chars("^{}");
!if ( left(1) ) % bobp() == TRUE
break;
if ( orelse {bocomment()} {is_escaped()} )
continue;
switch ( what_char() )
{ case '{':
if (length(open_rbraces) == 0)
return;
list_delete(open_rbraces, -1);
push_mark();
bskip_chars(TeX_Command_Chars);
variable cmd = chop_star(bufsubstr());
if ( andelse {strlen(cmd) > 0} {blooking_at("\\")} )
{
() = left(1);
if (cmd == "end")
boenv();
else if ( is_list_element("begin,section,chapter,subsection,subsubsection,paragraph",
cmd, ',') )
break;
}
}
{ case '}':
list_append(open_rbraces, [what_line, what_column()], -1);
}
}
goto_user_mark(start_mark);
if (length(open_rbraces) > 0)
throw DataError, "No matching } found for { in line " +
string(open_rbraces[-1][0]) + " column " + string(open_rbraces[-1][1]);
else
throw DataError, "No matching } found";
}
static define search_not_commented(func, arg, skip)
{
forever
{
variable ret = @func(arg);
!if ( andelse {ret} {is_commented()} )
return ret;
() = right(skip);
}
}
private define make_sorted_desc_list(list)
{
variable compl = {}, keys = assoc_get_keys(list);
foreach ( keys[array_sort(keys)] )
{
variable key = ();
list_append(compl, list[key], -1);
}
return compl;
}
%%%%%%%%%%
%
% Stuff for \documentclass[]{}
%
private define doc_find()
{
bob();
!if ( search_not_commented(&fsearch, "\\documentclass", 1) )
throw DataError, "Your document misses a \\documentclass";
() = right(14); % skip \documentclass
}
private define doc_options_class()
{
variable old_buf = whatbuf();
latex_external->jump_to_master_buffer();
push_spot();
try
{
doc_find();
variable args, class;
(args,class) = cmd_parse_args(1,1);
if (length(args) == 0)
return ("", class[0]);
else
return (str_delete_chars(args[0], "\\s"), class[0]);
}
finally
{
pop_spot();
setbuf(old_buf);
}
}
%%%%%%%%%%
%
% Package stuff
%
typedef struct {
options, desc, texdoc, hook, compl
} Pkg_Type;
private variable pkg_list = Assoc_Type[Pkg_Type];
static define pkg_register(name, opt, desc, texdoc, hook)
{
try
{
% This is a tricky way to check if all variables are strings
() = _typeof([name, desc, texdoc, opt, ""]);
}
catch TypeMismatchError:
{
throw InvalidParmError, "One of the given arguments has invalid type";
}
if (strlen(name) == 0)
throw InvalidParmError, "name can not be empty";
if (hook != NULL and typeof(hook) != Ref_Type)
throw InvalidParmError, "The argument hook must be a reference or NULL";
variable tmp;
if ( assoc_key_exists(pkg_list, name) )
tmp = pkg_list[name];
else
{
tmp = @Pkg_Type;
pkg_list[name] = tmp;
}
tmp.compl = name;
tmp.options = opt;
tmp.desc = desc;
tmp.texdoc = texdoc;
tmp.hook = hook;
}
private define pkg_hook_autoloaded_by_powerdot(name)
{
doc_options_class();
exch;
pop;
if ( () == "powerdot" )
return 1;
return pkg_find(name);
}
private define pkg_hook_babel(name)
{
if ( pkg_find(name) )
return 1;
variable mark = create_user_mark();
doc_find();
push_spot();
variable class;
(,class) = cmd_parse_args(1,1);
pop_spot();
if ( class[0] == "powerdot" )
% babel must be loaded before \documentclass, otherwise hyperref
% (loaded by powerdot) didn't know it.
() = left(14);
else
% suggest the point that pkg_find() suggested
goto_user_mark(mark);
return 0;
}
pkg_register("amsmath", "", "The main package for mathematical stuff", "amsldoc", NULL);
pkg_register("amssymb", "", "Symbols from AMS-Math", "", NULL);
pkg_register("avant", "", "Sets Avant Garde as default sans serif font", "psnfss2e", NULL);
private variable _lang = getenv("LANG"), _babel_opt = "";
if (_lang != NULL and _lang != "C")
{
switch (_lang[[0:1]])
{ case "de": _babel_opt = "ngerman"; }
{ case "it": _babel_opt = "italian"; }
{ case "en": _babel_opt = "english"; }
}
pkg_register("babel", _babel_opt, "Provides local hyphenation", "", &pkg_hook_babel());
__uninitialize(&_lang);
__uninitialize(&_babel_opt);
pkg_register("bookman", "", "Sets Bookman (roman), Avant Garde (sans serif) and Courier (typewriter) as default font", "psnfss2e", NULL);
pkg_register("chancery", "", "Sets Zapf Chancery as default roman font", "psnfss2e", NULL);
pkg_register("charter", "", "Sets Charter as default roman font", "psnfss2e", NULL);
pkg_register("courier", "", "Sets Courier as default typewriter font", "psnfss2e", NULL);
pkg_register("eulervm", "euler-digits", "Sets Euler fonts as default math font", "", NULL);
pkg_register("fontenc", "T1", "", "", NULL);
pkg_register("graphicx", "final", "Package for graphics", "graphics", NULL);
pkg_register("helvet", "scaled=.92", "Sets Helvetica as default sans serif font", "psnfss2e", NULL);
pkg_register("hyperref", "draft=false,colorlinks,urlcolor=blue,breaklinks", "", "hyperref/manual", &pkg_hook_autoloaded_by_powerdot());
#if (_slang_utf8_ok)
pkg_register("inputenc", "utf8", "Provides direct input of non-ascii characters", "", NULL);
#else
pkg_register("inputenc", "latin1", "Provides direct input of non-ascii characters", "", NULL);
#endif
pkg_register("lmodern", "", "Sets Latin Modern as default font", "", NULL);
pkg_register("mathpazo", "osf,slantedGreek", "Sets Adobe Palatino as default roman font", "psnfss2e", NULL);
pkg_register("mathptmx", "", "Sets Times as default roman font", "psnfss2e", NULL);
pkg_register("newcent", "", "Sets New Century Schoolbook (roman), Avant Garde (sans serif) and Courier (typewriter) as default font", "psnfss2e", NULL);
pkg_register("pstricks", "", "Draws PS graphics with LaTeX commands", "pstricks-doc", &pkg_hook_autoloaded_by_powerdot());
pkg_register("suetterl", "", "Provides Suetterlin kind font (use \textsuetterlin and \suetterlin)", "", NULL);
pkg_register("type1ec", "", "Sets Computer Modern super as default font", "", NULL);
pkg_register("xcolor", "", "Colors for LaTeX", "", &pkg_hook_autoloaded_by_powerdot());
private define pkg_find(name)
{
eob();
variable after_last_pkg = create_user_mark();
bob();
while ( re_fsearch("\\[buR][es][geq][ipu]"R) ) % Fixme: PCRE \\(begin|(Require|use)package)
{
if ( is_commented() )
{
eol();
continue;
}
if ( looking_at("\\begin{document}") )
{
goto_user_mark(after_last_pkg);
return 0;
}
variable is_usepackage = 0;
if ( looking_at("\\usepackage") )
{
is_usepackage = 1;
() = right(11);
}
else if ( looking_at("\\RequirePackage") )
() = right(15);
else
{
() = right(1);
continue;
}
variable mark_before_args = create_user_mark();
variable p;
(, p) = cmd_parse_args(1, 1);
if ( is_list_element(str_delete_chars(p[0], "\\s"), name, ',') )
{
goto_user_mark(mark_before_args);
return 1;
}
if (is_usepackage)
% If this wasn't the expected package, move the mark behind the
% \usepackage command
move_user_mark(after_last_pkg);
}
throw DataError, "no \\begin{document} found";
}
private define pkg_insert()
{
variable opt;
if (_NARGS >= 2)
opt = ();
variable name = ();
if (name == "")
return;
variable old_buf = whatbuf();
latex_external->jump_to_master_buffer();
push_spot();
try
{
variable hook = NULL;
if ( assoc_key_exists(pkg_list, name) )
hook = pkg_list[name].hook;
if (hook != NULL)
{
if ( @hook(name) )
return;
}
else if ( pkg_find(name) )
return;
if ( eobp() )
% pkg_find() or the hook didn't found any \usepackage
{
doc_find();
(,) = cmd_parse_args(1,1);
!if ( down(1) )
newline();
}
else
{
forever
{
push_spot();
skip_white();
looking_at_char('%');
pop_spot();
!if ( () )
break;
() = down(1);
}
if ( bolp() )
% We are not in the line with the last \usepackage and
% skipped a comment
() = up(1);
}
push_spot();
bsearch("\\documentclass");
pop_spot();
if ( () )
% after \documentclass
insert("\n\\usepackage");
else
% before \documentclass
insert("\n\\RequirePackage");
if ( __is_initialized(&opt) )
{
if (opt != "")
insert("[$opt]"$);
}
else if ( assoc_key_exists(pkg_list, name) )
{
opt = pkg_list[name].options;
if (opt != "")
insert("[$opt]"$);
}
insert("{$name}"$);
!if ( eolp() )
newline();
}
finally
{
pop_spot();
setbuf(old_buf);
}
}
private define insert_pkgs(str)
{
if (str == "")
return;
foreach ( strchop(str, ':', 0) )
{
variable pkg = (), pos = is_substr(pkg, ","), opt;
if (pos)
pkg_insert(substr(pkg, 1, pos-1), substr(pkg, pos+1, strlen(pkg)) );
else
pkg_insert(pkg);
}
}
static define pkg_prompt()
{
try
{
variable pkg = read_with_description("Select a package:", "", "",
make_sorted_desc_list(pkg_list));
if (pkg == "")
return;
variable options, new_pkg = not assoc_key_exists(pkg_list, pkg);
if (new_pkg)
options = "";
else
options = pkg_list[pkg].options;
options = read_mini("Options:", "", options);
pkg_insert(pkg, options);
if (andelse {new_pkg} {LaTeX_File_New != NULL} {strlen(LaTeX_File_New) > 0})
{
variable desc = read_mini("A description for the new package:", "", "");
variable fp = fopen(LaTeX_File_New, "a");
() = fprintf(fp, "latex->pkg_register(\"%- 21s \"%s\"R, \"%s\"R, \"\", NULL);\n",
pkg + "\",", options, desc);
() = fclose(fp);
}
message("\\usepackage{$pkg} inserted."$);
}
catch UserBreakError;
}
static define pkg_loaded(pkg)
{
variable old_buf = whatbuf();
latex_external->jump_to_master_buffer();
push_spot();
try
{
variable hook = NULL;
if ( assoc_key_exists(pkg_list, pkg) )
hook = pkg_list[pkg].hook;
if (hook != NULL)
return @hook(pkg);
else
return pkg_find(pkg);
}
finally
{
pop_spot();
setbuf(old_buf);
}
}
private define pkg_options(pkg)
{
variable old_buf = whatbuf();
latex_external->jump_to_master_buffer();
push_spot();
try
{
variable hook = NULL;
if ( assoc_key_exists(pkg_list, pkg) )
hook = pkg_list[pkg].hook;
if (hook != NULL)
{
!if ( @hook(pkg) )
throw InternalError, "Package $pkg not found"$;
}
else !if ( pkg_find(pkg) )
throw InternalError, "Package $pkg not found"$;
variable args;
(args,) = cmd_parse_args(1, 0);
if (length(args) == 0)
return "";
else
return args[0];
}
finally
{
pop_spot();
setbuf(old_buf);
}
}
static define pkg_help()
{
try
{
variable pkg;
if (_NARGS)
{
pkg = ();
if ( is_substr(pkg, ":") )
pkg = strchop(pkg, ':', 0)[0];
}
else
{
pkg = read_with_description("Help for which package:", "", "",
make_sorted_desc_list(pkg_list));
if (pkg == "")
return;
}
variable help;
if ( assoc_key_exists(pkg_list, pkg) )
{
help = pkg_list[pkg].texdoc;
if (strlen(help) == 0)
help = pkg;
}
else
help = pkg;
texdoc(help);
}
catch UserBreakError;
}
%%%%%%%%%%
%
% All about indentation
%
%!%+
%\function{env_name_indent}
%\synopsis{Gets the name and the indention of the current environment}
%\usage{(String_Type name, Integer_type indent) env_name_indent()}
%\description
% This function returns the name of the environment the editing point is in
% and the count of characters before \begin{...} in this line. If it isn't
% within a environment, name is NULL and the value of indent is undefined.
%
%\seealso{boenv(), env_name()}
%!%-
%\usage{(String_Type name, Integer_type indent) env_name_indent([Integer_Type])}
% If the optional parameter is unequal to zero to editing point is moved
% there.
private define env_name_indent()
{
push_spot();
try
{
variable name = env_name(1);
return (name, what_column()-1);
}
finally
pop_spot();
}
private define bsearch_command_indent()
{
variable backslash_mark, start_mark = create_user_mark();
forever {
!if ( bsearch_char('\\') )
error("Unknown case: opening brace, but no \\");
backslash_mark = create_user_mark();
% fix me!
% \framebox[.8\textwidth]{
variable found = orelse {find_matching_delimiter('{') != 1}
{create_user_mark() > start_mark};
goto_user_mark(backslash_mark);
if (found)
% start_mark is the opening brace for the command at
% backslash_mark
break;
% else
% the found backslash is inside of {} which are closed before
% start_mark
}
return what_column()-1;
}
private define calc_indention(env_name, line)
{
if (line != NULL)
{
line = strtrim_beg(line);
foreach ( [ {"\\item", LaTeX_Indent_Item},
{"\\intertext{", LaTeX_Indent_First},
{"\\bibitem{", LaTeX_Indent_Item}, {"\\end{", 0}] )
{
variable tmp = ();
if (strncmp(line, tmp[0], strlen(tmp[0])) == 0)
return tmp[1];
}
}
switch ( chop_star(env_name) )
{ case "document" or case "verbatim" or case "Verbatim": return 0; }
{ case "gather" or case "align" or case "tabular" or case "tabularx":
() = up(1);
variable indent = LaTeX_Indent_First;
!if ( orelse {blooking_at("\\\\")}
{blooking_at("\\hline")}
{bfind("\\intertext{")}
{bfind("\\begin{"+env_name+"}")} % first line after \begin
)
indent += LaTeX_Indent_Continued;
() = down(1);
return indent;
}
{ case NULL: return 0; }
return LaTeX_Indent_First;
}
private define newline_indent_hook()
{
variable indent, start_mark = create_user_mark(), name, env_mark;
() = bocomment();
name = env_name(1);
if (name == NULL) {
% we are outside of \begin{document}
indent = 0;
env_mark = NULL;
}
else {
indent = what_column()-1;
env_mark = create_user_mark();
goto_user_mark(start_mark);
}
if (andelse {find_matching_delimiter('}') == 1}
{orelse {env_mark == NULL}
{create_user_mark() > env_mark} }) {
% we are inside of braces
name = "{";
indent = what_column()-1;
bskip_white();
!if (bolp())
indent = bsearch_command_indent();
}
goto_user_mark(start_mark);
trim();
newline();
indent += calc_indention(name, NULL);
whitespace(indent);
}
private define indent_hook()
{
variable mark = create_user_mark();
bol();
trim();
if (eolp()) mark = NULL; % catch the case of a line with only whitespaces
variable start_mark = create_user_mark();
variable indent;
switch ( what_char() )
{ case '}':
if (find_matching_delimiter('}') != 1)
error("No opening '{' found");
indent = what_column()-1;
bskip_white();
!if (bolp()) % if opening brace is behind a command \...{
indent = bsearch_command_indent();
}
{ case '{' and up(1) and left(1) and looking_at_char('%'):
indent = bsearch_command_indent() + LaTeX_Indent_First;
()=right(1);
skip_word_chars();
skip_chars("%");
!if (eolp())
% indent to the level of the command end
indent = what_column()-1;
}
% This looks somewhat tricky, but we only handle cases where the
% previous line is a comment. But we must move the editing point for
% this so we must reset it.
{ case '%' and up(1) and is_commented() or
(goto_user_mark(start_mark),0):
()=up(1);
() = bfind_char('%');
indent = what_column()-1;
}
{
variable line = line_as_string();
bol();
variable env_mark, e_name, e_indent;
e_name = env_name(1);
if (e_name == NULL) {
% we are outside of \begin{document}
e_indent = 0;
env_mark = NULL;
}
else {
e_indent = what_column()-1;
env_mark = create_user_mark();
goto_user_mark(start_mark);
}
variable name;
if (andelse {find_matching_delimiter('}') == 1}
{orelse {env_mark == NULL} {create_user_mark() > env_mark} }) {
% we are inside of braces
name = "{";
%! Fix me!
indent = what_column()-1;
bskip_white();
!if (bolp()) {
% { is not the begin of a line
indent = bsearch_command_indent();
bskip_white();
!if (bolp()) {
% the command isn't the start of the line
indent = e_indent;
name = e_name;
}
}
}
else {
indent = e_indent;
name = e_name;
}
goto_user_mark(start_mark);
indent += calc_indention(name, line);
}
goto_user_mark(start_mark);
whitespace(indent);
if (mark != NULL) goto_user_mark(mark);
}
private define wrap_hook()
{
variable mark = create_user_mark();
()=up(1);
!if ( is_commented() ) {
goto_user_mark(mark);
indent_hook();
return;
}
% The wrap happened in a comment, so continue the comment
() = bfind_char('%');
variable indent = what_column()-1;
() = right(1);
skip_white();
variable inner_indent = what_column() - indent - 2;
() = down(1);
whitespace(indent);
insert_char('%');
whitespace(inner_indent);
goto_user_mark(mark);
}
private define wrapok_hook()
{
push_spot();
variable e_n;
try
{
() = bocomment();
e_n = env_name();
}
finally
pop_spot();
if ( andelse {e_n != NULL}
{is_list_element("verbatim,Verbatim", e_n, ',')} )
return 0;
push_spot();
try
{
bskip_chars("^ \t");
bskip_chars(" \t%");
return not bolp();
}
finally
pop_spot();
}
static define indent_region()
{
variable start_mark = create_user_mark();
check_region(0);
variable end_mark = create_user_mark();
pop_mark(1);
variable beg_mark = create_user_mark();
variable env_stack = {};
variable level;
do
{
level = struct { name, indent };
try
level.name = env_name(1);
catch AnyError:
break;
if (level.name == NULL)
level.indent = 0;
else
level.indent = what_column()-1;
list_insert(env_stack, level, 0);
}
while (level.name != NULL);
goto_user_mark(beg_mark);
level = list_pop(env_stack, -1);
() = up(1);
while (down(1) and create_user_mark() < end_mark)
{
bol();
trim();
if ( eolp() )
continue;
variable line = line_as_string();
bol();
variable this_line_indention = level.indent +
calc_indention(level.name, line);
whitespace(this_line_indention);
while ( andelse {ffind_char('\\')} {not is_commented()} )
{
() = right(1);
if ( looking_at("begin{") )
{
() = right(6);
list_append(env_stack, level, -1);
level = struct { name, indent };
push_mark();
() = ffind_char('}');
level.name = bufsubstr();
level.indent = this_line_indention;
}
else
{
if ( looking_at("end{") )
{
() = right(4);
if ( looking_at(level.name+"}") )
level = list_pop(env_stack, -1);
else
throw ApplicationError, "Expected \\end{"+level.name+"}";
}
}
}
}
goto_user_mark(start_mark);
}
%%%%%%%%%%
%
% Completion in environments
%
typedef struct { pre_nl, post_nl } nl_completion_type;
private variable nl_completion = Assoc_Type[nl_completion_type];
static define set_nl_completion(env, pre, post)
{
if ( typeof(env) != String_Type )
throw InvalidParmError, "env must be a string";
if ( pre != NULL and typeof(pre) != String_Type )
throw InvalidParmError, "pre must be a string or NULL";
if ( post != NULL and typeof(post) != String_Type )
throw InvalidParmError, "post must be a string or NULL";
if ( assoc_key_exists(nl_completion, env) )
{
if (pre == NULL and post == NULL)
assoc_delete_key(nl_completion, env);
else
{
if (pre != NULL)
nl_completion[env].pre_nl = pre;
if (post != NULL)
nl_completion[env].post_nl = post;
}
}
else
{
if (pre == NULL) pre = "";
if (post == NULL) post = "";
nl_completion[env] = @nl_completion_type;
nl_completion[env].pre_nl = pre;
nl_completion[env].post_nl = post;
}
}
set_nl_completion("align", "\\\\", "");
set_nl_completion("array", "\\\\", "");
set_nl_completion("cases", "\\\\", "");
set_nl_completion("compactdesc", "", "\\item[]");
set_nl_completion("compactenum", "", "\\item ");
set_nl_completion("compactitem", "", "\\item ");
set_nl_completion("description", "", "\\item[]");
set_nl_completion("enumerate", "", "\\item ");
set_nl_completion("flalign", "\\\\", "");
set_nl_completion("gather", "\\\\", "");
set_nl_completion("itemize", "", "\\item ");
set_nl_completion("pmatrix", "\\\\", "");
set_nl_completion("tabular", "\\\\", "");
set_nl_completion("tabularx", "\\\\", "");
set_nl_completion("thebibliography", "", "\\bibitem{}");
static define newline_with_completion()
{
if ( is_commented() ) {
variable mark = create_user_mark();
bol();
skip_chars(" \t%");
% new line become a comment, too
bol();
()=ffind_char('%');
variable indent = what_column()-1;
() = right(1);
skip_white();
variable inner_indent = 0;
!if (eolp())
inner_indent = what_column() - indent - 2;
goto_user_mark(mark);
newline();
trim();
whitespace(indent);
insert_char('%');
whitespace(inner_indent);
return;
}
variable name;
(name, indent) = env_name_indent();
name = chop_star(name);
variable compl;
if ( assoc_key_exists(nl_completion, name) )
compl = nl_completion[name];
else
{
compl = @nl_completion_type;
compl.pre_nl = "";
compl.post_nl = "";
}
switch (name)
{ andelse {case "tabular" or case "tabularx"} {blooking_at("---")}:
() = left(3);
() = replace_chars(3, "\\hline");
}
{
push_spot();
variable stop_str = strtrim(compl.post_nl);
if (stop_str == "")
stop_str = strtrim(compl.pre_nl);
variable skip_chars = "^$(){}[]" + substr(stop_str, 1, 1);
variable close_stack = list_new(), open_stack = list_new();
forever
{
bskip_chars(skip_chars);
() = left(1);
if ( looking_at(stop_str) )
break;
variable ch = what_char(), counterpart, alt_counterpart = "";
switch (ch)
{ case ')' or case ']' or case '}':
if ( andelse {ch == '}'} {is_escaped()} )
ch = "\\}";
else
ch = char(ch);
list_append(close_stack, ch, -1);
continue;
}
{ case '\\':
if ( looking_at("\\end") )
boenv();
else if ( looking_at("\\begin") )
break;
continue;
}
{ case '$':
if ( is_escaped() )
{
bskip_chars("\\");
continue;
}
else
{
if (length(close_stack) == 0)
{
list_append(close_stack, "$", -1);
}
else if (close_stack[-1] == "$")
list_delete(close_stack, -1);
continue;
}
}
{ case '(': counterpart = ")"; alt_counterpart = "]"; }
{ case '[': counterpart = "]"; alt_counterpart = ")"; }
{ case '{':
if ( is_escaped() )
counterpart = "\\}";
else
counterpart = "}";
}
if (andelse {length(close_stack) != 0} {close_stack[-1] == "$"})
{
list_append(open_stack, "$", -1);
list_delete(close_stack, -1);
}
if (length(close_stack) == 0)
list_append(open_stack, counterpart, -1);
else
{
if (close_stack[-1] == counterpart or
close_stack[-1] == alt_counterpart)
list_delete(close_stack, -1);
else
list_append(open_stack, counterpart, -1);
}
}
pop_spot();
if (andelse {length(close_stack) != 0} {close_stack[-1] == "$"})
list_append(open_stack, "$", -1);
while (length(open_stack) > 0)
{
variable looking_for = list_pop(open_stack, 0);
if ( looking_at(looking_for) )
() = right( strlen(looking_for) );
else
insert(looking_for);
}
insert( compl.pre_nl );
}
trim();
newline();
whitespace( indent + calc_indention(name, compl.post_nl) );
insert( compl.post_nl );
if ( andelse {strlen(compl.post_nl) > 0}
{is_substr("]}", char(compl.post_nl[-1]))} )
() = left(1);
}
%%%%%%%%%%
%
% Environemts -- all between \begin{} and \end{}
%
typedef struct {
args, desc, deps, hook, compl
} Env_Type;
private variable env_list = Assoc_Type[Env_Type];
static define env_register(name, args, desc, deps, hook)
{
try
{
% This is a tricky way to check if all variables are strings
() = _typeof([name, desc, ""]);
}
catch TypeMismatchError:
{
throw InvalidParmError, "One of the given arguments has invalid type";
}
if (strlen(name) == 0)
throw InvalidParmError, "name can not be empty";
if (typeof(args) != Integer_Type)
throw InvalidParmError, "The argument args must be an integer";
if (typeof(deps) != String_Type and typeof(deps) != Ref_Type)
throw InvalidParmError, "The argument deps must be a string or a reference";
if (hook != NULL and typeof(hook) != Ref_Type)
throw InvalidParmError, "The argument hook must be a reference or NULL";
variable tmp;
if ( assoc_key_exists(env_list, name) )
tmp = env_list[name];
else
{
tmp = @Env_Type;
env_list[name] = tmp;
}
tmp.compl = name;
tmp.args = args;
tmp.deps = deps;
tmp.desc = desc;
tmp.hook = hook;
}
private define env_hook_Verbatim(name, mark_after_begin)
{
variable indent = what_column() - 1;
if (indent > 0)
{
push_spot();
goto_user_mark(mark_after_begin);
insert("[gobble=$indent]"$);
pop_spot();
}
}
private define env_hook_star_label(name, mark_after_begin)
{
if (name[-1] != '*')
cmd_insert("label");
}
private define env_hook_array_format(name, mark_after_begin)
{
eoenv();
() = left(1);
array_edit_column_format();
}
private define env_hook_gmatrix(name, mark_after_begin)
{
variable type
= char(get_mini_response("Which type do you want? (p) {b} [B] |v| ||V|| "));
if ( is_substr("pbBvV", type) )
{
push_spot();
goto_user_mark(mark_after_begin);
insert("[$type]"$);
pop_spot();
}
}
env_register("abstract", 0, "", "", NULL);
env_register("align", 0, "Math environment with alignment", "amsmath", &env_hook_star_label());
env_register("array", 1, "", "", &env_hook_array_format());
env_register("bmatrix", 0, "", "amsmath", NULL);
env_register("Bmatrix", 0, "", "amsmath", NULL);
env_register("cases", 0, "", "amsmath", NULL);
env_register("center", 0, "", "", NULL);
env_register("compactdesc", 0, "", "paralist", NULL);
env_register("compactenum", 0, "", "paralist", NULL);
env_register("compactitem", 0, "", "paralist", NULL);
env_register("description", 0, "", "paralist", NULL); % fixme: deps as hook
% env_register("displaymath", 0, "", "", NULL);
env_register("enumerate", 0, "", "paralist", NULL); % fixme: deps as hook
env_register("figure", 0, "", "", NULL);
env_register("flushleft", 0, "", "", NULL);
env_register("flushright", 0, "", "", NULL);
env_register("gather", 0, "", "amsmath", &env_hook_star_label());
env_register("gmatrix", 0, "", "gauss", &env_hook_gmatrix());
env_register("itemize", 0, "", "paralist", NULL); % fixme: deps as hook
env_register("list", 0, "", "", NULL);
env_register("longtable", 1, "", "longtable", &env_hook_array_format());
env_register("matrix", 0, "", "amsmath", NULL);
env_register("minipage", 1, "", "", NULL);
env_register("picture", 0, "", "", NULL);
env_register("pmatrix", 0, "", "amsmath", NULL);
env_register("proof", 0, "", "", NULL);
env_register("pspicture", 0, "A PSTricks picture", "pstricks", NULL);
env_register("quotation", 0, "", "", NULL);
env_register("quote", 0, "", "", NULL);
env_register("smallmatrix", 0, "", "amsmath", NULL);
env_register("tabbing", 0, "", "", NULL);
env_register("table", 0, "", "", NULL);
env_register("tabular", 1, "", "", &env_hook_array_format());
env_register("tabularx", 2, "", "tabularx", NULL); % Fixme: hook = array_edit_column_format()
env_register("thebibliography", 1, "", "", NULL);
env_register("theorem", 0, "", "", NULL);
env_register("titlepage", 0, "", "", NULL);
env_register("verbatim", 0, "", "", NULL);
env_register("Verbatim", 0, "", "fancyvrb", &env_hook_Verbatim());
env_register("verse", 0, "", "", NULL);
env_register("vmatrix", 0, "", "amsmath", NULL);
env_register("Vmatrix", 0, "", "amsmath", NULL);
private define env_lookup()
{
variable default;
if (_NARGS >= 2)
default = ();
variable name = ();
if (strlen(name) > 0)
{
if ( assoc_key_exists(env_list, name) )
return env_list[name];
if (name[-1] == '*')
name = chop_star(name);
else
name = name + "*";
if ( assoc_key_exists(env_list, name) )
return env_list[name];
}
if (_NARGS >= 2)
return default;
else
throw InternalError, "Environment $name not found and no default given"$;
}
%!%+
%\function{boenv}
%\synopsis{Go to the beginning of the environment}
%\usage{Integer_Type boenv()}
%\description
% This function searches for the beginning of the environment the editing
% point is in. If it finds a "\begin{...}" it moves the editing point to the
% begin of "\begin{...}" and returns 1. If no environment beginning is
% found (maybe the editing point is before \begin{document}) the editing
% point isn't moved and 0 is returned.
%!%-
static define boenv()
{
if ( is_commented() )
throw UsageError, "Starting inside of a comment is not possible";
variable start_mark = create_user_mark(), open_ends = list_new();
while ( re_bsearch("\\[be][en][gd][i{]"R) ) %! Fixme: PCRE: \\(begin|end)\{
{
if ( bocomment() )
continue;
if ( looking_at("\\begin{" ) )
{
if (length(open_ends) == 0)
return;
list_delete(open_ends, -1);
}
else if ( looking_at("\\end{") )
list_append(open_ends, [what_line, what_column()], -1);
}
goto_user_mark(start_mark);
if (length(open_ends) > 0)
throw DataError, "No matching \\begin found for \\end in line " +
string(open_ends[-1][0]) + " column " + string(open_ends[-1][1]);
else
throw DataError, "No matching \\begin found";
}
%!%+
%\function{eoenv}
%\synopsis{Go to the end of the environment}
%\usage{Integer_Type eoenv()}
%\description
% This function searches for the end of the environment the editing
% point is in. If it finds a "\end{...}" it moves the editing point to the
% begin of "\end{...}" and returns 1. If no environment end is
% found (maybe the editing point is before \begin{document}) the editing
% point isn't moved and 0 is returned.
%!%-
static define eoenv()
{
if ( is_commented() )
throw UsageError, "Starting inside of a comment is not possible";
variable start_mark = create_user_mark(), open_begins = list_new();
if ( looking_at("\\begin{") )
() = right(1);
while ( re_fsearch("\\[be][en][gd][i{]"R) ) %! Fixme: PCRE: \\(begin|end)\{
{
if ( is_commented() )
{
eol();
continue;
}
if ( looking_at("\\end{" ) )
{
if (length(open_begins) == 0)
return;
list_delete(open_begins, -1);
}
else if ( looking_at("\\begin{") )
list_append(open_begins, [what_line, what_column], -1);
() = right(1);
}
goto_user_mark(start_mark);
if (length(open_begins) > 0)
throw DataError, "No matching \\end found for \\begin in line " +
string(open_begins[-1][0]) + " column " + string(open_begins[-1][1]);
else
throw DataError, "No matching \\end found";
}
%!%+
%\function{env_name}
%\synopsis{Gets the name of the current environment}
%\usage{String_Type env_name([Integer_Type])}
%\description
% This function returns the name of the environment the editing point is in.
% If it isn't within an environment, NULL is returned.
%
% If the optional parameter is unequal to zero the editing point is placed
% at the beginning.
%
%\seealso{boenv()}
%!%-
static define env_name()
{
variable stay_there = 0, spot = create_user_mark();
if (_NARGS)
stay_there = ();
try
boenv();
catch DataError:
% No \begin found
return NULL;
() = right(7); % skip \begin{
push_mark();
if ( ffind_char('}') )
{
variable name = bufsubstr();
() = left(strlen(name) + 7); % \begin{$name}
!if (stay_there)
goto_user_mark(spot);
return name;
}
else
{
pop_mark(1);
goto_user_mark(spot);
throw DataError, "malformed \\begin{}";
}
}
static define env_close ()
{
variable mark = create_user_mark();
bskip_white();
variable e_name;
if ( bolp() )
{
trim();
variable e_indent;
(e_name, e_indent) = env_name_indent();
whitespace(e_indent);
}
else
{
goto_user_mark(mark);
e_name = env_name();
}
if (e_name == NULL)
throw UsageError, "Not within an environment";
insert("\\end{$e_name}"$);
}
static define env_insert()
{
variable def_args;
if (_NARGS >= 2)
def_args = ();
else
def_args = String_Type[0];
variable name = ();
variable env_data = env_lookup(name, NULL);
if (env_data == NULL)
{
env_data = @Env_Type;
env_data.args = 0;
env_data.deps = "";
env_data.hook = NULL;
}
if (typeof(env_data.deps) == String_Type)
insert_pkgs(env_data.deps);
else
(@env_data.deps)(name);
variable body;
if ( dupmark() )
{
body = bufsubstr();
del_region();
}
variable mark = create_user_mark();
bskip_white();
variable in_one_line = not bolp();
if (in_one_line)
goto_user_mark(mark);
else
{
indent_line();
skip_white();
}
insert("\\begin{$name}"$);
variable point_after_begin = create_user_mark();
if (length(def_args) > 0)
insert("{" + strjoin(def_args, "}{") + "}");
variable point_after_insertion;
if (env_data.args - length(def_args) > 0)
{
insert_char('{');
point_after_insertion = create_user_mark();
loop (env_data.args - length(def_args) - 1)
insert("}{");
insert_char('}');
}
if (in_one_line)
{
if ( __is_initialized(&body) )
insert(body);
!if ( __is_initialized(&point_after_insertion) )
point_after_insertion = create_user_mark();
}
else
{
newline();
if ( __is_initialized(&body) )
{
push_mark();
insert(body);
!if ( __is_initialized(&point_after_insertion) )
point_after_insertion = create_user_mark();
!if ( bolp() )
newline();
indent_region();
}
else
{
variable compl;
if ( assoc_key_exists(nl_completion, chop_star(name)) )
{
compl = nl_completion[chop_star(name)].post_nl;
insert(compl);
}
indent_line();
!if ( __is_initialized(&point_after_insertion) )
{
if (andelse {__is_initialized(&compl)} {strlen(compl) != 0})
{
is_substr("]}", substr(compl, strlen(compl), 1));
dup();
if ( () )
() = left(1);
point_after_insertion = create_user_mark();
if ( () )
() = right(1);
}
else
point_after_insertion = create_user_mark();
}
newline();
}
}
env_close();
!if (in_one_line or eolp())
newline();
goto_user_mark(point_after_insertion);
if (env_data.hook != NULL)
(@env_data.hook)(name, point_after_begin);
}
private variable env_last_env = "";
static define env_prompt()
{
try
{
env_last_env = read_with_description("Select an environment:",
env_last_env, "",
make_sorted_desc_list(env_list));
if (env_last_env == "")
return;
variable env_data = env_lookup(env_last_env, NULL), desc;
if (env_data != NULL)
desc = env_data.desc;
else if (LaTeX_Register_New)
{
variable args, deps;
args = integer( read_mini("How much arguments this environment " +
"have?", "0", "") );
desc = read_mini("A description for the new environment:", "", "");
deps = read_mini("Colon separated list of packages needed for " +
"this environment:", "", "");
env_register(env_last_env, args, desc, deps, NULL);
if (andelse {LaTeX_File_New != NULL} {strlen(LaTeX_File_New) > 0})
{
variable fp = fopen(LaTeX_File_New, "a");
() = fprintf(fp, "latex->env_register(\"%- 21s %u, \"%s\"R, \"%s\", NULL);\n",
env_last_env + "\",", args, desc, deps);
() = fclose(fp);
}
}
env_insert(env_last_env);
message(desc);
}
catch UserBreakError;
}
static define env_rename()
{
variable spot = create_user_mark();
try
{
variable old_name = env_name(1);
if (old_name == NULL)
throw UsageError, "You aren't within an environment";
variable new_name = read_with_description("Rename environment:",
old_name, "",
make_sorted_desc_list(env_list));
if (new_name == old_name)
return;
variable env_data = env_lookup(new_name, NULL);
if (env_data == NULL and LaTeX_Register_New)
{
variable args, desc, deps;
args = integer( read_mini("How much arguments this environment " +
"have?", "0", "") );
desc = read_mini("A description for the new environment:", "", "");
deps = read_mini("Colon separated list of packages needed for " +
"this environment:", "", "");
env_register(new_name, args, desc, deps, NULL);
if (andelse {LaTeX_File_New != NULL} {strlen(LaTeX_File_New) > 0})
{
variable fp = fopen(LaTeX_File_New, "a");
() = fprintf(fp, "latex->env_register(\"%- 21s %u, \"%s\"R, \"%s\", NULL);\n",
new_name + "\",", args, desc, deps);
() = fclose(fp);
}
env_data = env_lookup(new_name);
}
if (env_data != NULL)
{
if (typeof(env_data.deps) == String_Type)
insert_pkgs(env_data.deps);
else
(@env_data.deps)(new_name);
}
() = right(7);
() = replace_chars(strlen(old_name), new_name);
goto_user_mark(spot);
eoenv();
() = right(5);
() = replace_chars(strlen(old_name), new_name);
}
catch UserBreakError;
finally
goto_user_mark(spot);
}
static define env_help()
{
try
{
variable env;
if (_NARGS)
env = ();
else
{
env = env_name();
if (env == NULL)
env = "";
env = read_with_description("Help for which environment:", env,
"", make_sorted_desc_list(env_list));
if (env == "")
return;
}
variable env_data = env_lookup(env, NULL), help;
if (env_data != NULL)
{
help = env_data.deps;
if (typeof(help) != String_Type)
__uninitialize(&help);
}
if (andelse {__is_initialized(&help)} {strlen(help) != 0})
pkg_help(help);
else
throw UsageError, "No information found about how to get help";
}
catch UserBreakError;
}
%%%%%%%%%%
%
% Command stuff, e.g. \foo[]{}
%
typedef struct {
args, desc, deps, hook, math, compl
} Cmd_Type;
private variable cmd_list = Assoc_Type[Cmd_Type];
% compl: the name of the command, e.g. the string after the backslash; the
% name compl makes it easier to pass the struct to read_with_description()
% args: how many arguments the command has?
% need_math: is it a command for a mathematical environment?
% desc: a description of the command
% deps: which packages the command depend on (colon separated list)
% hook: NULL or a reference to a function that gets called after inserting the
% command from inside the first brace or after the command if the
% command has no arguments
% Call the function with the name of the command and a mark of the
% point after the command.
static define cmd_register(name, args, need_math, desc, deps, hook)
{
try
{
% This is a tricky way to check if all variables are strings
() = _typeof([name, desc, deps, ""]);
}
catch TypeMismatchError:
{
throw InvalidParmError, "One of the given arguments has invalid type";
}
if (strlen(name) == 0)
throw InvalidParmError, "name can not be empty";
if (typeof(args) != Integer_Type or typeof(need_math) != Integer_Type)
throw InvalidParmError, "The arguments args and need_math must be integers";
if (hook != NULL and typeof(hook) != Ref_Type)
throw InvalidParmError, "The argument hook must be a reference or NULL";
variable tmp;
if ( assoc_key_exists(cmd_list, name) )
tmp = cmd_list[name];
else
{
tmp = @Cmd_Type;
cmd_list[name] = tmp;
}
tmp.compl = name;
tmp.args = args;
tmp.math = need_math;
tmp.deps = deps;
tmp.desc = desc;
tmp.hook = hook;
}
() = evalfile("latex_cmds", current_namespace());
private define cmd_lookup()
{
variable default;
if (_NARGS >= 2)
default = ();
variable name = ();
if (strlen(name) > 0)
{
if ( assoc_key_exists(cmd_list, name) )
return cmd_list[name];
if (name[-1] == '*')
name = chop_star(name);
else
name = name + "*";
if ( assoc_key_exists(cmd_list, name) )
return cmd_list[name];
}
if (_NARGS >= 2)
return default;
else
throw InternalError, "Command \\$name not found and no default given"$;
}
private define insert_space_after_cmd_hook(fun);
private define insert_space_after_cmd_hook(fun)
{
if (andelse {typeof(fun) == String_Type} {fun == "self_insert_cmd"}
{ ('A' <= LAST_CHAR and LAST_CHAR <= 'Z') or
('a' <= LAST_CHAR and LAST_CHAR <= 'z') })
insert_char(' ');
remove_from_hook("_jed_before_key_hooks", &insert_space_after_cmd_hook());
}
static define cmd_insert()
{
variable prefix = prefix_argument(0);
variable def_args, ins_pkg;
if (_NARGS >= 3)
def_args = ();
else
def_args = String_Type[0];
if (_NARGS >= 2)
ins_pkg = ();
else
ins_pkg = 1;
variable name = ();
variable cmd_data = cmd_lookup(name, NULL);
if (cmd_data == NULL)
{
insert_char('\\');
insert(name);
loop (prefix)
insert("[]");
if (prefix != 0)
() = left(2 * prefix - 1);
return;
}
if (ins_pkg)
insert_pkgs(cmd_data.deps);
else
!if ( orelse {cmd_data.deps == ""} {pkg_loaded(cmd_data.deps)} )
throw ApplicationError, "The depencies \"" + cmd_data.deps +
"\" for the command \"$name\" aren't satisfied"$;
if ( andelse {cmd_data.args != 0} {dupmark()} )
{
def_args = [def_args, bufsubstr()];
del_region();
}
variable behind_insertion;
if (andelse {cmd_data.math} {not is_math()} )
{
!if ( blooking_at("$") )
insert("$$");
behind_insertion = create_user_mark();
() = left(1);
}
insert_char('\\');
insert(name);
push_spot();
variable next_point;
if (prefix)
{
insert_char('[');
next_point = create_user_mark();
loop (prefix - 1)
insert("][");
insert_char(']');
}
if (length(def_args) > 0)
insert("{" + strjoin(def_args, "}{") + "}");
loop (cmd_data.args - length(def_args))
insert("{}");
!if ( __is_initialized(&behind_insertion) )
behind_insertion = create_user_mark();
!if ( __is_initialized(&next_point) )
{
if (cmd_data.args - length(def_args) > 0)
{
() = left(2 * (cmd_data.args - length(def_args)) - 1);
next_point = create_user_mark();
}
else
next_point = behind_insertion;
}
pop_spot();
if (cmd_data.hook == NULL)
goto_user_mark(next_point);
else
(@cmd_data.hook)(name, behind_insertion);
if (LaTeX_Auto_Space_After_Commands)
{
() = left(1);
variable ch = what_char();
() = right(1);
if ( ('A' <= ch and ch <= 'Z') or ('a' <= ch and ch <= 'z') )
add_to_hook("_jed_before_key_hooks", &insert_space_after_cmd_hook());
}
}
private variable cmd_last_cmd = "";
static define cmd_prompt()
{
try
{
cmd_last_cmd = read_with_description("Select a command:", cmd_last_cmd, "",
make_sorted_desc_list(cmd_list));
if (cmd_last_cmd == "")
return;
variable cmd_data = cmd_lookup(cmd_last_cmd, NULL), desc;
if (cmd_data != NULL)
desc = cmd_data.desc;
else if (LaTeX_Register_New)
{
variable args, math, deps;
args = integer( read_mini("How much arguments this command " +
"have?", "0", "") );
variable dflt;
math = int(is_math());
if (math)
dflt = "Y/n";
else
dflt = "y/N";
switch ( get_mini_response("Is this a mathematic command? (" +
dflt + ") ") )
{ case 7: throw UserBreakError; }
{ case 'Y' or case 'y': math = 1; }
{ case 'N' or case 'n': math = 0; }
% Fixme: This should be read_with_description() with the
% SYNOPSIS as description
variable hook_as_string =
read_string_with_completion("Name of a hook (leave if empty for none)",
"", strjoin("latex->" +
_apropos("latex",
"cmd_hook", 3),
","));
variable hook = __get_reference(hook_as_string);
if ( __is_callable(hook) )
hook_as_string = "&" + hook_as_string + "()";
else
{
hook = NULL;
hook_as_string = "NULL";
}
desc = read_mini("A description for the new command:", "", "");
deps = read_mini("Colon separated list of packages needed for " +
"this command:", "", "");
cmd_register(cmd_last_cmd, args, math, desc, deps, hook);
if (andelse {LaTeX_File_New != NULL} {strlen(LaTeX_File_New) > 0})
{
variable fp = fopen(LaTeX_File_New, "a");
() = fprintf(fp, "latex->cmd_register(\"%- 21s %u, %u, \"%s\"R, \"%s\", %s);\n",
cmd_last_cmd + "\",", args, math, desc, deps,
hook_as_string);
() = fclose(fp);
}
}
cmd_insert(cmd_last_cmd);
message(desc);
}
catch UserBreakError;
}
static define cmd_parse_args(opt_args, req_args)
{
skip_chars(" \n\t");
variable o_args = list_new();
while ( andelse {opt_args > 0} {looking_at_char('[')} )
{
push_mark();
try
{
forever
{
() = right(1);
skip_chars("^{]");
!if ( looking_at_char('{') or looking_at_char(']') )
throw DataError, "No matching ] found";
if ( is_escaped() )
continue;
if ( looking_at_char(']') )
{
list_append(o_args,
str_compress_tex( substr(bufsubstr(), 2, -1) ),
-1);
push_mark();
break;
}
else
fsearch_matching_brace();
}
}
finally
{
pop_mark(0);
}
() = right(1);
skip_chars(" \n\t");
--opt_args;
}
variable r_args = list_new();
while (req_args > 0)
{
switch ( what_char() )
{ case '{':
() = right(1);
push_mark();
try
{
fsearch_matching_brace();
list_append(r_args, str_compress_tex(bufsubstr()), -1);
--req_args;
push_mark();
}
finally
pop_mark(0);
() = right(1);
}
{ case '\\':
push_mark();
() = right(1);
skip_chars(TeX_Command_Chars);
list_append(r_args, bufsubstr(), -1);
--req_args;
}
{ case '%':
() = down(1);
skip_white();
}
{ case ' ' or case '\n' or case '\t':
skip_chars(" \n\t");
}
{
list_append(r_args, char( what_char() ), -1);
--req_args;
() = right(1);
}
}
return (o_args, r_args);
}
static define cmd_help()
{
try
{
variable cmd;
if (_NARGS)
cmd = ();
else
{
push_spot();
bskip_chars(TeX_Command_Chars);
push_mark();
skip_chars(TeX_Command_Chars);
cmd = bufsubstr();
pop_spot();
cmd = read_with_description("Help for which command:", cmd, "",
make_sorted_desc_list(cmd_list));
if (cmd == "")
return;
}
variable cmd_data = cmd_lookup(cmd, NULL), help;
if (cmd_data != NULL)
{
help = cmd_data.deps;
if (typeof(help) != String_Type)
__uninitialize(&help);
}
if (andelse {__is_initialized(&help)} {strlen(help) != 0})
pkg_help(help);
else
throw UsageError, "No information found about how to get help";
}
catch UserBreakError;
}
%!%+
% Check if the editing point stays on a command. In this case return the
% command, otherwise NULL
%!%-
static define is_command()
{
!if ( re_looking_at("\\[$TeX_Command_Chars]"R$) )
{
!if ( re_looking_at("[$TeX_Command_Chars]"$) )
return NULL;
variable mark = create_user_mark();
bskip_chars(TeX_Command_Chars);
!if ( andelse {left(1)} {looking_at_char('\\')} )
{
goto_user_mark(mark);
return NULL;
}
}
push_spot();
push_mark();
() = right(1);
skip_chars(TeX_Command_Chars);
bufsubstr();
pop_spot();
return ();
}
%%%%%%%%%%
%
% All about fonts
%
static define font_resize(decrease)
{
variable sizes="tiny,scriptsize,footnotesize,small,normalsize,large,Large,LARGE,huge,Huge";
variable start_mark = create_user_mark(), is_region = markp();
if (is_region) {
check_region(0);
exchange_point_and_mark();
} else if (orelse {looking_at_char('\\')} {bfind_char('\\')} )
()=right(1);
variable mark = create_user_mark();
push_mark();
skip_word_chars();
variable pos = is_list_element(sizes, bufsubstr(), ',');
if ( pos ) {
if (decrease)
pos -= 2;
if (pos == -1 or pos == 10) {
goto_user_mark(start_mark);
error("Font resizing not possible");
}
push_mark();
goto_user_mark(mark);
del_region();
}
else {
if (is_region)
insert_char('{');
else
% Maybe bfind_char doesn't find the correct \ - don't write there, it
% might be wrong
goto_user_mark(start_mark);
insert_char('\\');
if (decrease)
pos = 3; % small
else
pos = 5; % large
}
insert( string(extract_element(sizes, pos, ',')) );
mark = create_user_mark();
skip_non_word_chars();
if ( mark == create_user_mark() and not eolp() )
insert_char(' ');
goto_user_mark(start_mark);
if (is_region)
insert_char('}');
}
static define font_cmd()
{
try
#ifexists jmini_prompt_string
cmd_insert( jmini_prompt_string("Select a font command:", "", "",
["bfseries", "emph", "itshape", "mathbf", "mathcal", "mathit",
"mathnormal", "mathrm", "mathsf", "mathtt", "mdseries",
"normalfont", "rmfamily", "scshape", "sffamily", "slshape",
"textbf", "textit", "textmd", "textnormal", "textrm",
"textsc", "textsf", "textsl", "texttt", "textup", "ttfamily",
"upshape"]) );
#else
cmd_insert( read_with_completion("textrm,rmfamily,textit,"+
"itshape,emph,textmd,mdseries,textbf,bfseries,textup,"+
"upshape,textsl,slshape,textsf,sffamily,textsc,"+
"scshape,texttt,ttfamily,textnormal,normalfont,mathrm"+
"mathbf,mathsf,mathtt,mathit,mathnormal,mathcal",
"Select a font command:", "", "", 's') );
#endif
catch UserBreakError: {}
}
static define templ_insert(file)
{
push_mark();
narrow_to_region();
try
{
!if ( insert_file(file) )
return;
bob();
if ( fsearch("%:default:classopt:") )
{
push_mark();
() = right(19);
if ( looking_at(",%") )
{
() = right(2);
del_region();
if ( strlen(LaTeX_Default_Class_Options) )
insert("," + LaTeX_Default_Class_Options);
}
else
{
if ( looking_at("[%") )
{
() = right(2);
del_region();
if ( strlen(LaTeX_Default_Class_Options) )
insert("[" + LaTeX_Default_Class_Options + "]");
}
else
pop_mark(1);
}
}
if ( bol_fsearch("%:default:pkgs:%\n") )
{
% set a marker for insert_pkgs where it should place the packages
% if no other packages are present
() = replace_chars(16, "\\usepackage{JLM marker}");
bol();
insert_pkgs(LaTeX_Default_Packages);
deln(24); % delete the marker line (with \n)
}
bob();
if ( fsearch("%:start:%") )
deln(9);
}
finally
widen_region();
}
%%%%%%%%%%
%
% All about arrays like tabular or matrix
%
private define array_what_column()
{
variable start = create_user_mark(), num = 1;
forever
{
bskip_chars("^&}\\");
!if ( left(1) ) % == bobp()
break;
if ( looking_at_char('&') and not is_escaped() )
{
++num;
continue;
}
if ( looking_at_char('}') and not is_escaped() )
{
bsearch_matching_brace();
continue;
}
if ( looking_at("\\end") )
{
boenv();
continue;
}
if ( looking_at("\\multicolumn") )
{
push_spot();
() = right(13);
push_mark();
skip_chars("0-9");
num += integer( bufsubstr() );
pop_spot();
continue;
}
if ( orelse {looking_at("\\\\")} {looking_at("\\begin")} )
% This must be the begin of the array environment
break;
}
goto_user_mark(start);
return num;
}
private variable array_columns = Assoc_Type[Integer_Type, 0];
array_columns["align"] = 20;
array_columns["array"] = -1;
array_columns["bmatrix"] = 10; % [ matrix ]
array_columns["Bmatrix"] = 10; % \{ matrix \}
array_columns["cases"] = 2;
array_columns["longtable"] = -1;
array_columns["matrix"] = 10;
array_columns["pmatrix"] = 10; % ( matrix )
array_columns["smallmatrix"] = 10; % \footnotesize matrix
array_columns["tabular"] = -1;
array_columns["tabular*"] = -2;
array_columns["tabularx"] = -2;
array_columns["vmatrix"] = 10; % | matrix |
array_columns["Vmatrix"] = 10; % || matrix ||
static define array_new_cell()
{
variable start = create_user_mark();
variable e_name = env_name(1);
variable num_cols;
if ( assoc_key_exists(array_columns, e_name) )
num_cols = array_columns[e_name];
else
num_cols = array_columns[ chop_star(e_name) ];
if (num_cols < 0)
{
() = right(strlen(e_name) + 8); % \begin{$e_name}
(,) = cmd_parse_args(1, -num_cols - 1);
!if ( looking_at_char('{') )
{
goto_user_mark(start);
throw InternalError;
}
() = right(1);
num_cols = 0;
variable factor = 1, factors = {};
forever
{
variable point = _get_point();
skip_chars("a-zA-Z");
num_cols += factor * (_get_point() - point);
switch ( what_char() )
{ case '}':
if (length(factors) == 0)
break;
factor = list_pop(factors);
}
{ case '*':
list_append(factors, factor, -1);
() = right(2);
push_mark();
skip_chars("0-9");
factor *= integer( bufsubstr() );
() = right(1);
}
() = right(1);
if ( looking_at_char('{') )
{
fsearch_matching_brace();
() = right(1);
}
}
}
goto_user_mark(start);
if (array_what_column() < num_cols)
insert("& ");
else
{
insert("\\\\\n");
indent_line();
}
}
static define array_next_cell()
{
forever
{
skip_chars("^&{\\");
if ( eobp() )
% This is very curious, better we do nothing
return;
if ( andelse {looking_at_char('&')} {not is_escaped()} )
{
() = right(1);
return;
}
if ( looking_at("\\\\") )
{
() = right(2);
skip_chars(" \t\n");
if ( looking_at("\\hline") )
{
() = right(6);
skip_chars(" \t\n");
}
if ( looking_at("\\end") )
{
bskip_chars(" \t");
if ( bolp() )
() = left(1);
}
return;
}
if ( looking_at("\\end") )
{
bskip_chars(" \t");
if ( bolp() )
() = left(1);
array_new_cell();
return;
}
if ( looking_at("\\begin") )
{
eoenv();
() = ffind_char('}');
continue;
}
if ( andelse {looking_at_char('{')} {not is_escaped()} )
{
fsearch_matching_brace();
continue;
}
% this must be the begin of a command
() = right(1);
}
}
static define array_prev_cell()
{
forever
{
bskip_chars("^&}\\");
!if ( left(1) ) % == bobp()
break;
if ( andelse {looking_at_char('&')} {not is_escaped()} )
break;
if ( andelse {looking_at_char('}')} {not is_escaped()} )
{
bsearch_matching_brace();
continue;
}
if ( looking_at("\\end") )
{
boenv();
continue;
}
if ( looking_at("\\begin") )
{
% This must be the begin of the array environment
() = right(6);
do
{
fsearch_matching_brace();
() = right(1);
} while ( looking_at_char('{') );
break;
}
if ( looking_at("\\\\") )
break;
}
}
static define array_edit_column_format()
{
variable start = create_user_mark();
variable e_name = env_name(1);
variable num_cols;
if ( assoc_key_exists(array_columns, e_name) )
num_cols = array_columns[e_name];
else
num_cols = array_columns[ chop_star(e_name) ];
if (num_cols >= 0)
{
goto_user_mark(start);
throw UsageError, "environment has no column definition";
}
() = right(strlen(e_name) + 8); % \begin{$e_name}
variable col;
(,col) = cmd_parse_args(1, -num_cols);
col = col[-1];
try
{
variable col_len = strlen(col);
col = read_mini("Column format:", "", col);
if (col == "")
return;
() = left(col_len + 1); % $col}
() = replace_chars(col_len, col);
}
catch UserBreakError;
finally
{
goto_user_mark(start);
}
}
%%%%%%%%%%
%
% Label
%
private variable label_insert_mark = NULL;
static define label_insert_at_mark()
{
if (label_insert_mark == NULL) {
label_insert_mark = create_user_mark();
message("Now go to the point where you want to set the label and hit ^Clm again");
}
else {
cmd_insert("label");
if (andelse {left(1)} {looking_at_char('}')}) {
push_mark();
()=bfind_char('{');
()=right(1);
variable label = bufsubstr();
goto_user_mark(label_insert_mark);
if ( pkg_loaded("hyperref") )
"\\autoref{";
else if ( andelse {label[[0:1]] == "eq"} {pkg_loaded("amsmath")} )
"\\eqref{";
else
"\\ref{";
insert(() + label + "}");
}
label_insert_mark = NULL;
}
}
static define label_ref()
{
if ( pkg_loaded("hyperref") )
cmd_insert("autoref");
else
cmd_insert("ref");
}
%%%%%%%%%%
%
% Folding
%
static define fold(f_lvl);
static define fold(f_lvl)
{
variable start_mark = create_user_mark();
try
{
while (f_lvl < 0)
{
variable mark = create_user_mark();
switch ( env_name(1) )
{ case NULL:
throw UsageError, "There's no level below the file level";
}
{ case "document":
goto_user_mark(mark);
break;
}
++f_lvl;
}
if (f_lvl < 0)
{
throw NotImplementedError;
forever
{
!if ( search_not_commented(&re_bsearch,
"\\[cs][heu][acb][pts]"R, 0) ) % Fixme: PCRE
{
break;
}
if ( looking_at("\\chapter") )
f_lvl += 2;
else if ( looking_at("\\section") )
f_lvl += 3;
else if ( looking_at("\\subsection") )
f_lvl += 4;
else if ( looking_at("\\subsubsection") )
f_lvl += 5;
else
continue;
}
if (f_lvl < 0)
throw UsageError, "There's no level below the file level";
switch (f_lvl)
{ case 1: "\\begin{document}"; }
{ case 2: "\\chapter" or "\\section"; }
{ case 1: "\\begin{document}"; }
}
variable first_line, level;
switch ( env_name(1) )
{ case "document":
variable beg_doc_mark = create_user_mark(), start_level;
variable level_names = ["chapter", "section", "subsection", "subsubsection"];
while (length(level_names) > 0)
{
if ( fsearch("\\" + level_names[0]) )
break;
level_names = level_names[[1:]];
}
% add the file level (0) and the begin--end{document} level (1)
#if (_slang_version < 20007)
level_names = ["\\file-level", "\\doc-level", level_names];
#else
level_names = [NULL, NULL, level_names];
#endif
goto_user_mark(start_mark);
forever
{
if ( not search_not_commented(&re_bsearch,
"\\[cs][heu][acb][pts]"R, 0) or % Fixme: PCRE
create_user_mark() < beg_doc_mark)
{
goto_user_mark(beg_doc_mark);
start_level = 1;
() = right(1);
break;
}
() = right(1);
push_mark();
skip_chars(TeX_Command_Chars);
start_level = wherefirst(level_names == chop_star( bufsubstr() ));
if (start_level != NULL)
{
(,) = cmd_parse_args(1,1);
break;
}
}
f_lvl += start_level;
if (f_lvl == 1)
% folding level 1 is easy
{
() = down(1);
push_mark();
eoenv();
() = up(1);
set_region_hidden(1);
return;
}
if (start_level == f_lvl)
% if we start on the fold level, we must start with a mark
{
() = down(1);
push_mark();
first_line = what_line;
}
level = start_level;
forever
{
!if ( search_not_commented(&re_fsearch,
"\\[cseb][heun][acbdg][ptsi{]"R, 1) ) % Fixme: PCRE
eob();
variable last_level = level;
() = right(1);
if ( looking_at("begin{") )
++level;
else if ( looking_at("end{document}") or eobp() )
level = 0;
else if ( looking_at("end{") )
{
--level;
if (f_lvl == level)
% this is not a barrier like \section that stops
% and starts a folding region
continue;
}
else
{
push_mark();
skip_chars(TeX_Command_Chars);
level = wherefirst(level_names == chop_star( bufsubstr() ));
if (level == NULL)
{
level = last_level;
continue;
}
(,) = cmd_parse_args(1,1);
}
% f_lvl <= last_level: we come from a level where folding
% is active
% level <= f_lvl: level < f_lvl or level == f_lvl
% level < f_lvl: we jump to a level where folding is
% inactive
% level == f_lvl: we jumped across a barrier that is on
% f_lvl - 1---it must become visible
if (level <= f_lvl and f_lvl <= last_level)
{
push_spot();
() = up(1);
if (what_line <= first_line)
% there is nothing to fold
pop_mark(0);
else
set_region_hidden(1);
pop_spot();
}
if (level < start_level)
break;
% last_level < f_lvl and f_lvl <= level:
% we come from a level where folding is inactive and
% continue on a level where folding is active
% level == f_lvl and f_lvl <= last_level:
% we come from a level where folding is active and
% jumped across a barrier on f_lvl - 1 that must
% become visible
if ((last_level < f_lvl and f_lvl <= level) or
(level == f_lvl and f_lvl <= last_level))
{
() = down(1);
push_mark();
first_line = what_line;
}
}
}
{ case NULL:
doc_find();
variable in_preample = create_user_mark() < start_mark;
if (in_preample)
{
if (f_lvl != 0)
return;
}
else if (f_lvl == 0)
throw InvalidParmError,
"Folding the while file is not supported";
if (f_lvl <= 1)
{
(,) = cmd_parse_args(1,1);
() = down(1);
push_mark();
first_line = what_line;
!if ( search_not_commented(&fsearch, "\\begin{document}", 1) )
{
% fixme: throw
pop_mark(0);
return;
}
push_spot();
() = up(1);
if (what_line <= first_line)
pop_mark(0);
else
set_region_hidden(1);
pop_spot();
if (in_preample)
return;
}
else !if ( search_not_commented(&fsearch, "\\begin{document}", 1) )
{
% fixme: throw
return;
}
() = right(1);
fold(f_lvl - 1);
}
{
level = 0;
do
{
if ( looking_at("\\begin{") )
{
if (level < f_lvl)
++level;
else
{
() = down(1);
push_mark();
first_line = what_line;
eoenv();
push_spot();
() = up(1);
if (what_line <= first_line)
% there is nothing to fold
pop_mark(0);
else
set_region_hidden(1);
pop_spot();
}
}
else if ( looking_at("\\end{") )
--level;
() = right(1);
}
while ( andelse {level > 0} {re_fsearch("\\[be][en][gd]"R)} );
}
}
finally
{
goto_user_mark(start_mark);
if ( is_line_hidden() )
skip_hidden_lines_backward(1);
}
}
%%%%%%%%%%
%
% Helping stuff
%
%!%+
%\variable{User_Mark line_mark}
%\synopsis{holds the mark of the current line}
%\description
% we need this variable as buffer for the line mark.
% if the line mark isn't associated with a variable it isn't shown
%
%\seealso{update_log_hook()}
%!%-
private variable line_mark;
%!%+
%\function{update_log_hook}
%\synopsis{Marks the current line}
%\usage{update_log_hook()}
%\description
% This function marks the current line for highlighting.
%
% It is used in the buffers with the output of latex and other programms
% to show better the line the cursor is in.
%!%-
private define update_log_hook()
{
line_mark = create_line_mark(color_number("region"));
}
private variable TEXDOC_KEYMAP = "texdoc-help";
!if ( keymap_p(TEXDOC_KEYMAP) ) {
make_keymap(TEXDOC_KEYMAP);
definekey("latex->texdoc_show()", "g", TEXDOC_KEYMAP);
definekey("latex->texdoc_show()", "\n", TEXDOC_KEYMAP);
definekey("latex->texdoc_show()", "\r", TEXDOC_KEYMAP);
definekey("delbuf(whatbuf());call(\"delete_window\")", "q", TEXDOC_KEYMAP);
definekey("delbuf(whatbuf());call(\"delete_window\")", "c", TEXDOC_KEYMAP);
definekey("delbuf(whatbuf());call(\"delete_window\")", "^G", TEXDOC_KEYMAP);
}
static define texdoc_show()
{
variable file = line_as_string();
delbuf( whatbuf() );
call("delete_window");
variable file_bn = path_basename(file);
variable ext = path_extname(file_bn);
if ( is_list_element(".gz,.bz2", ext, ',') )
{
file_bn = path_sans_extname(file_bn);
ext = path_extname(file_bn);
}
if (file_bn == "README" or is_list_element(".tex,.txt", ext, ','))
{
() = find_file(file);
return;
}
() = system("texdoc '$file' &"$);
}
private define texdoc_run(td_arg)
{
try
{
variable pattern = read_mini("Search pattern:", "", "");
pop2buf("*Texdoc help*");
set_readonly(0);
erase_buffer();
() = run_shell_cmd("texdoc "+td_arg+" '"+pattern+"'");
use_keymap(TEXDOC_KEYMAP);
set_buffer_hook("update_hook", &update_log_hook);
set_buffer_modified_flag(0);
set_readonly(1);
bob();
}
catch UserBreakError:
{ }
}
static define texdoc_help()
{
texdoc_run("-l");
}
static define texdoc_search()
{
texdoc_run("-s");
}
static define texdoc(what)
{
() = system("texdoc '$what' &"$);
}
static define info_page()
{
info_reader();
if (_NARGS)
{
try
{
"(latex)";
exch;
info_find_node( () + () );
}
catch AnyError:
info_find_node("(latex)Top");
}
else
info_find_node("(latex)Top");
}
%%%%%%%%%%
%
% Keyboard stuff
%
static define insert_quote()
{
if ( orelse {is_escaped()} {is_verbatim()}
{andelse {LAST_CHAR != '"'} {LAST_CHAR != '`'}} )
{
call("self_insert_cmd");
return;
}
variable lang = NULL;
if ( pkg_loaded("babel") )
{
variable opt = pkg_options("babel");
if (opt != "")
lang = strchop(opt, ',', '\0')[-1];
else
{
(opt,) = doc_options_class();
if (opt != "")
{
variable array = strchop(opt, ',', '\0');
#ifexists array_reverse
array_reverse(array);
#endif
foreach opt (array)
if ( is_list_element("ngerman,german,french,francais,frenchb",
opt, ',') )
{
lang = opt;
#ifnexists array_reverse
break;
#endif
}
}
}
}
else if ( orelse {pkg_loaded("ngerman")} {pkg_loaded("german")} )
lang = "german";
variable lquote, rquote;
switch (lang)
{ case "french" or case "francais":
switch (LAST_CHAR)
{ case '"': lquote = "<<~"; rquote = "~>>"; }
{ case '`': lquote = "<~"; rquote = "~>"; }
}
{ case "frenchb":
switch (LAST_CHAR)
{ case '"': lquote = "\\og"; rquote = "\\fg"; }
{ case '`': lquote = "`"; rquote = "'"; }
}
{ case "german" or case "ngerman":
switch (LAST_CHAR)
{ case '"': lquote = "\"`"; rquote = "\"'"; }
{ case '`': lquote = "\\glq"; rquote = "\\grq"; }
}
{ case "russian":
switch (LAST_CHAR)
{ case '"': lquote = "\"`"; rquote = "\"'"; }
{ case '`': lquote = "`"; rquote = "'"; }
}
{ % case "english":
switch (LAST_CHAR)
{ case '"': lquote = "``"; rquote = "''"; }
{ case '`': lquote = "`"; rquote = "'"; }
}
variable start_mark = create_user_mark();
variable quote_sign = lquote, search = &bsearch();
forever
{
!if ( @search(quote_sign) )
break;
if ( is_commented() )
continue;
if (quote_sign == lquote)
{
() = left(1);
if ( looking_at( substr(quote_sign, 1, 1) ) ) % ` \subset ``, ' \subset ''
continue;
quote_sign = rquote;
search = &fsearch();
}
else
{
if ( looking_at( quote_sign + substr(quote_sign, strlen(quote_sign), 1) ) ) % ` \subset ``, ' \subset ''
() = right(1);
else
{
if (create_user_mark() < start_mark)
quote_sign = lquote;
break;
}
}
}
goto_user_mark(start_mark);
if (substr(quote_sign, 1, 1) == "\\")
cmd_insert( substr(quote_sign, 2, -1) );
else
insert(quote_sign);
}
static define insert_dollar()
{
if ( orelse {is_escaped()} {is_verbatim()} {not is_math()} )
{
call("self_insert_cmd");
return;
}
#ifexists abbrev_table_p
call("self_insert_cmd"); % expand abbreviations
() = left(1);
del();
#endif
push_spot();
variable close_stack = list_new(), open_stack = list_new();
forever
{
bskip_chars("^$(){}[]");
() = left(1);
variable ch = what_char(), counterpart, alt_counterpart = "";
switch (ch)
{ case ')' or case ']' or case '}':
if ( andelse {ch == '}'} {is_escaped()} )
ch = "\\}";
else
ch = char(ch);
list_append(close_stack, ch, -1);
continue;
}
{ case '$':
if ( is_escaped() )
continue;
else
break;
}
{ case '(': counterpart = ")"; alt_counterpart = "]"; }
{ case '[': counterpart = "]"; alt_counterpart = ")"; }
{ case '{':
if ( is_escaped() )
counterpart = "\\}";
else
counterpart = "}";
}
if (length(close_stack) == 0)
list_append(open_stack, counterpart, -1);
else
{
if (close_stack[-1] == counterpart or
close_stack[-1] == alt_counterpart)
list_delete(close_stack, -1);
else
list_append(open_stack, counterpart, -1);
}
}
if (BLINK)
{
update_sans_update_hook(0);
() = input_pending(5);
}
pop_spot();
while (length(open_stack) > 0)
{
variable looking_for = list_pop(open_stack, 0);
if ( looking_at(looking_for) )
() = right( strlen(looking_for) );
else
insert(looking_for);
}
if ( looking_at_char('$') )
() = right(1);
else
insert_char('$');
}
static define insert_without_spaces()
{
variable insert_backslash = is_escaped();
if (insert_backslash xor (LAST_CHAR == ',' or LAST_CHAR == ' '))
{
call("self_insert_cmd");
return;
}
if (insert_backslash)
{
() = left(1);
del();
}
trim();
if ( andelse {bolp()} {left(1)} )
{
del();
trim();
}
if (insert_backslash)
insert_char('\\');
call("self_insert_cmd");
update(1);
forever
{
variable ch = getkey();
if (ch != ' ' and ch != '\t' and ch != '\n')
{
ungetkey(ch);
break;
}
flush("Whitespaces around a special space make it meaningless");
}
}
#ifnexists isalpha
define isalpha(ch)
{
% Fixme! fails for ß
return orelse {ch != toupper(ch)} {ch != tolower(ch)};
}
#endif
static define math_arrow(); % declare it for recursion
static define math_arrow()
{
if ( orelse {is_escaped()} {is_verbatim()} )
{
call("self_insert_cmd");
return;
}
variable arrow_str;
switch (LAST_CHAR)
{ case '>':
() = left(1);
switch ( what_char() )
{ case '-':
() = left(1);
switch (what_char())
{ case '-':
() = left(1);
switch (what_char)
{ case '<':
deln(3);
arrow_str = "longleftrightarrow";
}
{ case '|':
deln(3);
arrow_str = "longmapsto";
}
{
() = right(1);
deln(2);
arrow_str = "longrightarrow";
}
}
{ case '|':
deln(2);
arrow_str = "mapsto";
}
{ case '<':
deln(2);
arrow_str = "leftrightarrow";
}
{ case '`':
deln(2);
arrow_str = "hookrightarrow";
}
{
() = right(1);
del();
arrow_str = "rightarrow";
}
}
{ case '=':
() = left(1);
switch (what_char())
{ case '=':
() = left(1);
if (what_char() == '<')
{
deln(3);
arrow_str = "Longleftrightarrow";
}
else
{
() = right(1);
deln(2);
arrow_str = "Longrightarrow";
}
}
{ case '<':
deln(2);
arrow_str = "Leftrightarrow";
}
{
() = right(1);
del();
arrow_str = "Rightarrow";
}
}
{ case '>':
del();
arrow_str = "gg";
}
{
() = right(1);
call("self_insert_cmd");
return;
}
}
{ case '-' or case '=':
() = left(1);
switch ( what_char() )
{ case LAST_CHAR:
() = left(1);
switch ( what_char() )
{ case '<':
() = right(2);
insert_char(LAST_CHAR);
update_sans_update_hook(1);
variable new_char = getkey();
if (new_char == '>')
{
LAST_CHAR = '>';
math_arrow();
return;
}
else
{
ungetkey(new_char);
() = left(3);
deln(3);
if (LAST_CHAR == '-')
arrow_str = "longleftarrow";
else
arrow_str = "Longleftarrow";
}
}
{
() = right(2);
call("self_insert_cmd");
return;
}
}
{ case '<':
() = right(1);
insert_char(LAST_CHAR);
update_sans_update_hook(1);
new_char = getkey();
switch (new_char)
{ case '>' or case '-' or case '=':
LAST_CHAR = new_char;
math_arrow();
return;
}
{
ungetkey(new_char);
() = left(2);
deln(2);
if ( LAST_CHAR == '-' )
arrow_str = "leftarrow";
else
arrow_str = "Leftarrow";
}
}
{
() = right(1);
if (LAST_CHAR == '-')
typo_hyphen();
else
call("self_insert_cmd");
return;
}
}
{
throw UsageError, "unknow character: $LAST_CHAR"$;
}
cmd_insert(arrow_str);
}
static define math_ll()
{
if ( left(1) ) {
if ( what_char() == '<' )
{
del();
cmd_insert("ll");
}
else {
()=right(1);
call("self_insert_cmd");
}
}
else
call("self_insert_cmd");
}
static define math_right_parenthesis()
{
if (what_char() == '}')
{
push_spot();
find_matching_delimiter(LAST_CHAR) != 1;
pop_spot();
if ( () )
() = right(1);
}
push_spot();
if (find_matching_delimiter(LAST_CHAR) == 1)
{
push_mark();
bskip_chars("leftbigB\\");
variable size = bufsubstr(), delim;
switch ( strlow(size) )
{ case "\\left": delim = "\\right"; }
{ case "\\big" or case "\\bigg": delim = size; }
{ case "\\bigl" or case "\\biggl": delim = size[[:-2]] + "r"; }
{ delim = ""; }
pop_spot();
insert(delim);
}
else
pop_spot();
call("self_insert_cmd");
}
static define insert_limits_char()
{
if ( orelse {is_escaped()} {is_verbatim()} )
{
call("self_insert_cmd");
return;
}
variable skip_dollar_after_compl = 0;
if ( blooking_at("$") )
{
skip_dollar_after_compl = 1;
() = left(1);
}
push_spot();
bskip_chars(TeX_Command_Chars + "0-9");
() = left(1);
!if ( looking_at_char('\\') )
() = right(1);
variable insert_dollar = 0;
!if ( is_math() )
{
insert_dollar = 1;
skip_dollar_after_compl = 1;
insert_char('$');
}
push_mark();
pop_spot();
variable last_cmd = bufsubstr();
if (insert_dollar)
{
insert_char('$');
if (last_cmd != "$")
% if no text was enclosed in $ $, the arrangement of spot and
% mark is difficult and leads to ^{}$$. This deals with this.
() = left(1);
}
switch (last_cmd)
{ case "\\rightarrow" or case "\\leftarrow":
() = left( strlen(last_cmd)-1 );
insert_char('x');
() = right( strlen(last_cmd)-1 );
if (LAST_CHAR == '_')
{
insert("[]{}");
() = left(3);
}
else
{
insert("{}");
() = left(1);
}
return;
}
{ case "\\cup" or case "\\cap" or case "\\vee" or case "\\wedge":
() = left( strlen(last_cmd)-1 );
insert("big");
() = right( strlen(last_cmd)-1 );
last_cmd = "\\big" + substr(last_cmd, 2, -1);
}
insert(char(LAST_CHAR) + "{}");
() = left(1);
if (last_cmd[0] != '\\')
% completion is only supported for TeX commands
return;
push_spot();
() = left(strlen(last_cmd) + 2); % $last_cmd$LAST_CHAR{
% the \ at the begin is the regexp quote of the \ in the command
!if ( re_bsearch("\\$last_cmd[_^]"$) )
{
pop_spot();
return;
}
() = right( strlen(last_cmd) );
variable counterpart_compl, compl;
!if ( looking_at_char(LAST_CHAR) )
{
() = right(1);
(,counterpart_compl) = cmd_parse_args(0,1);
}
if ( looking_at_char(LAST_CHAR) )
{
() = right(1);
(,compl) = cmd_parse_args(0,1);
}
if (not __is_initialized(&counterpart_compl) and
(looking_at_char('^') or looking_at_char('_')) )
{
() = right(1);
(,counterpart_compl) = cmd_parse_args(0,1);
}
pop_spot();
!if ( __is_initialized(&compl) )
return;
push_visible_mark();
insert( str_compress_tex(compl[0]) );
update(1);
variable k = getkey();
switch ( char(k) )
{ case Key_Return or case Key_Enter:
pop_mark(0);
() = right(1);
!if ( __is_initialized(&counterpart_compl) )
{
if (skip_dollar_after_compl)
() = right(1);
return;
}
}
{
del_region();
ungetkey(k);
return;
}
push_visible_mark();
if (LAST_CHAR == '_')
"^{";
else
"_{";
insert(() + str_compress_tex(counterpart_compl[0]) + "}");
update(1);
k = getkey();
switch ( char(k) )
{ case Key_Return or case Key_Enter:
pop_mark(0);
if (skip_dollar_after_compl)
() = right(1);
}
{
del_region();
ungetkey(k);
}
}
static define key_fold()
{
variable arg = prefix_argument();
try
{
switch (arg)
{ case NULL: arg = 0; } % default: fold this level
{ case 9: % Fixme: This should be 0 digit_arg doesn't support it
arg = integer( read_mini("Level to fold:", "9", "") );
}
fold(arg);
}
catch UserBreakError;
}
static define key_unfold()
{
try
{
variable arg = prefix_argument(0);
push_spot();
skip_hidden_lines_backward(1);
() = down(1);
push_mark();
skip_hidden_lines_forward(1);
() = up(1);
set_region_hidden(0);
pop_spot();
if (arg > 0)
fold(arg);
}
catch UserBreakError;
}
static define textormath(text, math)
{
variable cmd;
if ( is_math() )
cmd = math;
else
cmd = text;
if (cmd[0] == ' ')
insert( substr(cmd, 2, strlen(cmd)) );
else
{
if ( is_internal(cmd) )
call(cmd);
else
eval(cmd);
}
}
private define defkeyr_textormath_cmd(text, math, key, mode)
{
text = make_printable_string("latex->cmd_insert(\"$text\")"$);
math = make_printable_string("latex->cmd_insert(\"$math\")"$);
definekey_reserved("latex->textormath($text, $math)"$, key, mode);
}
private variable SIMPLE_KEYMAP = MODE + "-simple";
!if ( keymap_p(SIMPLE_KEYMAP) )
{
make_keymap(SIMPLE_KEYMAP);
% templates - ^CT or ^C^T
definekey_reserved("menu_select_menu(\"Global.M&ode.&Templates\")", "t", SIMPLE_KEYMAP);
definekey_reserved("menu_select_menu(\"Global.M&ode.&Templates\")", "^T", SIMPLE_KEYMAP);
% packages - ^CP
definekey_reserved("latex->pkg_prompt", "p", SIMPLE_KEYMAP);
% array - ^Ca
definekey_reserved("latex->array_edit_column_format", "ae", SIMPLE_KEYMAP);
definekey_reserved("latex->array_next_cell", "a\t", SIMPLE_KEYMAP);
definekey_reserved("latex->array_next_cell", "aa", SIMPLE_KEYMAP);
definekey_reserved("latex->array_new_cell", "an", SIMPLE_KEYMAP);
definekey_reserved("latex->array_prev_cell", "ap", SIMPLE_KEYMAP);
% environments - ^CE
definekey_reserved("latex->boenv", "e<", SIMPLE_KEYMAP);
definekey_reserved("latex->env_close", "ec", SIMPLE_KEYMAP);
definekey_reserved("latex->env_close", "}", SIMPLE_KEYMAP);
definekey_reserved("latex->env_prompt", "ee", SIMPLE_KEYMAP);
definekey_reserved("latex->env_prompt", "e\r", SIMPLE_KEYMAP);
definekey_reserved("latex->env_rename", "er", SIMPLE_KEYMAP);
definekey_reserved("latex->eoenv", "e>", SIMPLE_KEYMAP);
% sections - ^Cs
definekey_reserved("latex->cmd_insert(\"appendix\")", "sa", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"chapter\")", "sc", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"part\")", "sp", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"section\")", "ss", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"subsection\")", "su", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"subsubsection\")", "sb", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"paragraph\")", "sg", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"subparagraph\")", "sh", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"minisec\")", "sm", SIMPLE_KEYMAP);
% commands - ^Cd
definekey_reserved("latex->cmd_prompt", "d", SIMPLE_KEYMAP);
% fonts - ^CF
definekey_reserved("latex->font_resize(1)", "f-", SIMPLE_KEYMAP);
definekey_reserved("latex->font_resize(0)", "f+", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathcal\")", "fa", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("textbf", "mathbf", "fb", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathbf\")", "fB", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"textsc\")", "fc", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("underline", "underbar", "fd", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("underline", "underbar", "f_", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"underbar\")", "fD", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"emph\")", "fe", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("textsf", "mathsf", "ff", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathsf\")", "fF", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("textit", "mathit", "fi", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathit\")", "fI", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathfrak\")", "fk", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"textmd\")", "fm", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("textnormal", "mathnormal", "fn", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathnormal\")", "fN", SIMPLE_KEYMAP);
definekey_reserved("latex->font_cmd", "fp", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("textrm", "mathrm", "fr", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathrm\")", "fR", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"textsl\")", "fs", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"textup\")", "fu", SIMPLE_KEYMAP);
defkeyr_textormath_cmd("texttt", "mathtt", "ft", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mathtt\")", "fT", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"verb\")", "fv", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"text\")", "fx", SIMPLE_KEYMAP);
% definekey_reserved("latex_modify_font(\"\")", "fD", SIMPLE_KEYMAP);
% definekey_reserved("latex_rename_font", "fN", SIMPLE_KEYMAP);
% links - ^CL
definekey_reserved("latex->cmd_insert(\"label\")", "ll", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"label\")", "^L^L", SIMPLE_KEYMAP);
definekey_reserved("latex->label_insert_at_mark", "lm", SIMPLE_KEYMAP);
definekey_reserved("latex->label_insert_at_mark", "^L^M", SIMPLE_KEYMAP);
definekey_reserved("latex->label_ref", "lr", SIMPLE_KEYMAP);
definekey_reserved("latex->label_ref", "^L^R", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pageref\")", "lp", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pageref\")", "^L^P", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cite\")", "lb", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cite\")", "^l^b", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"url\")", "lu", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"url\")", "^L^U", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nocite\")", "ln", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nocite\")", "^L^N", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"index\")", "li", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"index\")", "^L^I", SIMPLE_KEYMAP);
% PSTricks - ^Ci
definekey_reserved("latex->pst_move_points", "im", SIMPLE_KEYMAP);
definekey_reserved("latex->pst_update_pic_size", "iu", SIMPLE_KEYMAP);
% math symbols - ^C m
definekey_reserved("latex->cmd_insert(\"alpha\")", "ma", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"beta\")", "mb", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"chi\")", "mc", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"delta\")", "md", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"epsilon\")", "me", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"phi\")", "mf", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"gamma\")", "mg", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"eta\")", "mh", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"kappa\")", "mk", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"lambda\")", "ml", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"mu\")", "mm", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nabla\")", "mN", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nu\")", "mn", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"omega\")", "mo", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pi\")", "mp", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"theta\")", "mq", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"rho\")", "mr", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"sigma\")", "ms", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"tau\")", "mt", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"upsilon\")", "mu", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Xi\")", "mX", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"xi\")", "mx", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"psi\")", "my", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"zeta\")", "mz", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Delta\")", "mD", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Gamma\")", "mG", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Theta\")", "mQ", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Lambda\")", "mL", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Phi\")", "mV", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Psi\")", "mY", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Pi\")", "mP", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Sigma\")", "mS", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Upsilon\")", "mU", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Omega\")", "mO", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"rightarrow\")", "m^f", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"leftarrow\")", "m^b", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"uparrow\")", "m^p", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"downarrow\")", "m^n", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"leq\")", "m<", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"geq\")", "m>", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"tilde\")", "m~", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"infty\")", "mI", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"forall\")", "mA", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"exists\")", "mE", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"neg\")", "m!", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"in\")", "mi", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"times\")", "m*", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cdot\")", "m.", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"subset\")", "m{", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"supset\")", "m}", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"subseteq\")", "m[", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"supseteq\")", "m]", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"not\")", "m/", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"setminus\")", "m\\", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cup\")", "m+", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cap\")", "m-", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"wedge\")", "m&", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"vee\")", "m|", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"langle\")", "m(", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"rangle\")", "m)", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"exp\")", "m^e", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"sin\")", "m^s", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cos\")", "m^c", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"sup\")", "m^^", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"inf\")", "m^_", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"det\")", "m^d", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"lim\")", "m^l", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"tan\")", "m^t", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"hat\")", "m^", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"vee\")", "mv", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"emptyset\")", "m0", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"colon\")", "m:", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"infty\")", "m8", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"ne\")", "m=", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"overline\")", "m_", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Phi\")", "mF", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"omega\")", "mw", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"Omega\")", "mW", SIMPLE_KEYMAP);
% not so common math stuff - ^C n
definekey_reserved("latex->cmd_insert(\"mathcal\")", "nc", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\")", "nf", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nicefrac\")", "nF", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"int\")", "ni", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"log\")", "nl", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pmod\")", "nm", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"oint\")", "no", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"prod\")", "np", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"sum\")", "ns", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"sqrt\")", "nq", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\"])", "n1", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"2\"])", "n2", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"3\"])", "n3", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"4\"])", "n4", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"5\"])", "n5", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"6\"])", "n6", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"7\"])", "n7", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"8\"])", "n8", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"frac\", 1, [\"1\", \"9\"])", "n9", SIMPLE_KEYMAP);
% breaks - ^CK
definekey_reserved("latex->cmd_insert(\"newline\");newline()", "kl", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"newline\");newline()", "^K^L", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"linebreak[1]\");newline()", "kb", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"linebreak[1]\");newline()", "^K^B", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"newpage\");newline()", "kp", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"newpage\");newline()", "^K^P", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"clearpage\");newline()", "kc", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"clearpage\");newline()", "^K^C", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cleardoublepage\");newline()", "kd", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"cleardoublepage\");newline()", "^K^D", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pagebreak\");newline()", "kr", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"pagebreak\");newline()", "^K^R", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nolinebreak[1]\");newline()", "kn", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nolinebreak[1]\");newline()", "^K^N", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nopagebreak\");newline()", "ko", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"nopagebreak\");newline()", "^K^O", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"enlargethispage\")", "ke", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"enlargethispage\")", "^K^E", SIMPLE_KEYMAP);
% math arrows - ^C + arrow
definekey_reserved("latex->cmd_insert(\"uparrow\")", Key_Up, SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"downarrow\")", Key_Down, SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"leftarrow\")", Key_Left, SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_insert(\"rightarrow\")", Key_Right, SIMPLE_KEYMAP);
definekey_reserved("latex->newline_with_completion", Key_Return, SIMPLE_KEYMAP);
% special characters
definekey_reserved(" \\$", "$", SIMPLE_KEYMAP);
definekey_reserved(" \\&", "&", SIMPLE_KEYMAP);
definekey_reserved(" \\%", "%", SIMPLE_KEYMAP);
definekey_reserved(" \\_", "_", SIMPLE_KEYMAP);
definekey_reserved(" \\#", "#", SIMPLE_KEYMAP);
definekey_reserved(" \\{", "(", SIMPLE_KEYMAP);
definekey_reserved(" \\}", ")", SIMPLE_KEYMAP);
definekey_reserved(" \\textless{}", "<", SIMPLE_KEYMAP);
definekey_reserved(" \\textgreater{}", ">", SIMPLE_KEYMAP);
definekey_reserved(" \\textbackslash{}", "\\", SIMPLE_KEYMAP);
definekey_reserved(" \\textbar{}", "|", SIMPLE_KEYMAP);
definekey_reserved(" \\textasciicircum{}", "^", SIMPLE_KEYMAP);
definekey_reserved(" \\textasciitilde{}", "~", SIMPLE_KEYMAP);
% stuff from latex_external - ^C r
definekey_reserved("latex_external->select_master_file", "ra", SIMPLE_KEYMAP);
definekey_reserved("latex_external->bibtex", "rb", SIMPLE_KEYMAP);
definekey_reserved("latex_external->show_bibtex_log", "rv", SIMPLE_KEYMAP);
definekey_reserved("latex_external->clearup", "rc", SIMPLE_KEYMAP);
definekey_reserved("latex_external->makeindex", "ri", SIMPLE_KEYMAP);
definekey_reserved("latex_external->show_mkidx_log", "ru", SIMPLE_KEYMAP);
definekey_reserved("latex_external->mrproper", "rm", SIMPLE_KEYMAP);
definekey_reserved("latex_external->cust_view", "ro", SIMPLE_KEYMAP);
definekey_reserved("latex_external->print", "rp", SIMPLE_KEYMAP);
% often used stuff from latex_external
definekey_reserved("latex_external->compose", "c", SIMPLE_KEYMAP);
definekey_reserved("latex_external->compose", "^C", SIMPLE_KEYMAP);
definekey_reserved("latex_external->view", "v", SIMPLE_KEYMAP);
definekey_reserved("latex_external->view", "^V", SIMPLE_KEYMAP);
definekey_reserved("latex_external->pop_log_file", "y", SIMPLE_KEYMAP);
definekey_reserved("latex_external->pop_log_file", "^y", SIMPLE_KEYMAP);
% help
definekey_reserved("latex->texdoc_help()", "ht", SIMPLE_KEYMAP);
definekey_reserved("latex->texdoc_search()", "hT", SIMPLE_KEYMAP);
definekey_reserved("latex->texdoc_search()", "^h^T", SIMPLE_KEYMAP);
definekey_reserved("latex->texdoc(\"symbols-a4\")", "hs", SIMPLE_KEYMAP);
definekey_reserved("latex->texdoc(\"symbols-a4\")", "^H^S", SIMPLE_KEYMAP);
definekey_reserved("latex->info_page", "hi", SIMPLE_KEYMAP);
definekey_reserved("latex->info_page", "^h^I", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_help", "hc", SIMPLE_KEYMAP);
definekey_reserved("latex->cmd_help", "^H^C", SIMPLE_KEYMAP);
definekey_reserved("latex->env_help", "he", SIMPLE_KEYMAP);
definekey_reserved("latex->env_help", "^H^E", SIMPLE_KEYMAP);
definekey_reserved("latex->pkg_help", "hp", SIMPLE_KEYMAP);
definekey_reserved("latex->pkg_help", "^H^P", SIMPLE_KEYMAP);
definekey_reserved("latex->indent_region", "q", SIMPLE_KEYMAP);
definekey_reserved("latex->key_fold", "oo", SIMPLE_KEYMAP);
definekey_reserved("latex->key_unfold", "ou", SIMPLE_KEYMAP);
}
private define definekey_textormath(text, math, key, mode)
{
text = make_printable_string(text);
math = make_printable_string(math);
definekey("latex->textormath($text, $math)"$, key, mode);
}
static define unfold_or_newline()
{
if (orelse {is_line_hidden()} {andelse {right(1)} {is_line_hidden()}})
key_unfold();
else
{
() = left(1);
call("newline_and_indent");
}
}
!if ( keymap_p(MODE) )
{
copy_keymap(MODE, SIMPLE_KEYMAP);
% misc
definekey("latex->insert_quote", "\"", MODE);
definekey("latex->insert_quote", "`", MODE);
definekey("latex->insert_dollar", "$", MODE);
definekey("latex->math_ll", "<", MODE);
definekey("latex->math_arrow", ">", MODE);
definekey("latex->math_arrow", "-", MODE);
definekey("latex->math_arrow", "=", MODE);
foreach $1 ([" ", "~"])
definekey_textormath("latex->insert_without_spaces", "self_insert_cmd",
$1, MODE);
% typo stuff
definekey_textormath("latex->typo_slash", "self_insert_cmd", "/", MODE);
definekey("latex->typo_percent", "%", MODE);
definekey_textormath("latex->insert_without_spaces",
"latex->typo_german_decimal_point", ",", MODE);
definekey("latex->typo_dots", ".", MODE);
% math stuff
definekey_textormath("self_insert_cmd", "latex->cmd_insert(\"colon\")",
":", MODE);
definekey_textormath("self_insert_cmd", "latex->math_right_parenthesis",
")", MODE);
definekey_textormath("self_insert_cmd", "latex->math_right_parenthesis",
"]", MODE);
definekey("latex->insert_limits_char()", "^", MODE);
definekey("latex->insert_limits_char()", "_", MODE);
definekey("latex->newline_with_completion", Key_Shift_Return, MODE);
definekey("latex->unfold_or_newline", Key_Return, MODE);
}
%%%%%%%%%%
%
% Menu stuff
%
private define menu_init_helper(menu, list, fun)
{
foreach (list)
{
variable entry = ();
if (typeof(entry) == Array_Type)
menu_append_item(menu, entry[0], fun, entry[1]);
else
menu_append_item(menu, entry,
"latex->" + string(fun)[[1:]] +
"(\"" + str_delete_chars(entry, "&\\"R) + "\")");
}
}
private define menu_init(menu)
{
% templates
menu_append_popup(menu, "&Templates");
$1 = menu+".&Templates";
if (LaTeX_Template_Dir != NULL)
{
variable templates = Assoc_Type[String_Type];
foreach ( strtok(LaTeX_Template_Dir, ",") )
{
variable tmp = ();
foreach ( listdir(tmp) )
{
variable file = ();
if (strlen( path_sans_extname(file) ) != 0)
templates[path_sans_extname(file)] = path_concat(tmp, file);
}
}
variable keys = assoc_get_keys(templates);
foreach ( keys[array_sort(keys)] )
{
variable templ = ();
menu_append_item($1, templ, &templ_insert(), templates[templ]);
}
}
% packages
menu_append_popup(menu, "&Packages");
menu_init_helper(menu+".&Packages",
["alltt", "amsmath", "babel", "booktabs", "calc",
"color", "eepic", "fancyhdr", "fancyvrb",
"geometry", "graphicx", "hyperref", "isolatin1",
"longtable", "makeidx", "moreverb",
"psfrag", "pslatex", "rotating", "url"],
&pkg_insert() );
% environments
menu_append_popup(menu, "&Environments");
$1 = menu+".&Environments";
menu_append_item($1, "&array", "latex->env_insert(\"array\", [\"ll\"])");
menu_init_helper($1,
{"¢er", "&description", "&enumerate", "&figure",
"flush&left", ["flush&Right", "flushright"], "&itemize",
["&List", "list"]},
&env_insert() );
menu_append_item($1, "&minipage",
"latex->env_insert(\"minipage\", [\"\\linewidth\"R])");
menu_init_helper($1,
["&picture", ""ation", "qu&ote", "ta&bbing", "&table",
"tab&ular"],
&env_insert() );
menu_append_item($1, "thebibliograph&y",
"latex->env_insert(\"thebibliography\", [\"99\"])");
menu_init_helper($1,
{["t&Heorem", "theorem"], "titlepa&ge", "&verbatim",
"ver&se"},
&env_insert() );
menu_append_separator($1);
menu_append_item($1, "&Custom...", "latex->env_prompt");
menu_append_item($1, "re&Name...", "latex->env_rename");
menu_append_item($1, "close...", "latex->env_close");
menu_append_item($1, "Goto begin...", "latex->boenv");
menu_append_item($1, "Goto end...", "latex->eoenv");
% font
menu_append_popup(menu, "&Font");
$1 = menu+".&Font";
menu_append_popup($1, "&Family");
menu_init_helper($1+".&Family",
{["&Roman", "textrm"], ["&Sans serif", "textsf"],
["&Typewriter", "texttt"]},
&cmd_insert());
menu_append_popup($1, "&Shape");
menu_init_helper($1+".&Shape",
{["&Italic", "textit"], ["&Slanted", "textsl"],
["Small &caps", "textsc"],
["&Upright (normal)", "textup"]},
&cmd_insert());
menu_append_popup($1, "S&eries");
$2 = $1+".S&eries";
menu_append_item($2, "&Boldface", "latex->cmd_insert(\"textbf\")");
menu_append_item($2, "&Medium weight (normal)", "latex->cmd_insert(\"textmd\")");
menu_append_popup($1, "Si&ze");
menu_init_helper($1+".Si&ze",
["&tiny", "s&criptsize", "&footnotesize", "&small",
"&normalsize", "&large", "&Large", "L&ARGE",
"&huge", "&Huge"],
&cmd_insert() );
menu_append_separator($2);
menu_append_item($2, "re&size", "latex_resize_font");
menu_init_helper($1,
{["&Emphasis", "emph"], ["&Underline", "underline"],
["&Normal font", "textnormal"], ["\\&verb", "verb"]},
&cmd_insert() );
menu_append_separator($1);
menu_append_item($1, "&Delete last setting", "latex_modify_font(\"\")");
menu_append_item($1, "Re&name", "latex_rename_font");
% font/environment
menu_append_popup($1, "As &Environment");
menu_init_helper($1+".As &Environment",
["&rmfamily", "&itshape", "&mdseries", "&bfseries",
"&upshape", "&slshape", "s&ffamily", "s&cshape",
"&ttfamily", "&normalfont"],
&env_insert() );
% font/math
menu_append_popup($1, "&Math");
menu_init_helper($1+".&Math",
["mathr&m", "math&bf", "math&sf", "math&tt",
"math&it", "math&normal"],
&cmd_insert() );
% sections
menu_append_popup(menu, "&Sections");
menu_init_helper(menu+".&Sections",
["\\p&art", "\\&chapter", "\\§ion", "\\s&ubsection",
"\\su&bsubsection", "\\¶graph", "\\subparagrap&h",
"\\&minisec"],
&cmd_insert() );
% paragraph
menu_append_popup(menu, "&Paragraph");
$1 = menu+".&Paragraph";
menu_append_item($1, "F&ramed Paragraph", "latex_par_frame");
menu_append_item($1, "&background Colour", "latex_par_bgcolour");
menu_append_item($1, "&foreground Colour", "latex_par_fgcolour");
menu_append_item($1, "\\par&indent",
"insert(\"\\\\setlength{\\\\parindent}{0pt}\\n\")");
menu_append_item($1, "\\par&skip",
"insert(\"\\\\setlength{\\\\parskip}{3pt}\\n\")");
menu_append_item($1, "\\&marginpar",
"latex_cmd(\"marginpar\", 1)");
menu_append_item($1, "\\foot¬e",
"latex_cmd(\"footnote\", 1)");
menu_append_item($1, "\\inc&ludegraphics", "latex_includegraphics");
% paragraph/margins
menu_append_popup($1, "&Margins");
$2 = $1+".&Margins";
menu_append_item($2, "\\&leftmargin",
"latex_cmd(\"setlength{\\\\leftmargin}\", 1)");
menu_append_item($2, "\\&rightmargin",
"latex_cmd(\"setlength{\\\\rightmargin}\", 1)");
menu_append_item($2, "\\&evensidemargin",
"latex_cmd(\"setlength{\\\\evensidemargin}\", 1)");
menu_append_item($2, "\\&oddsidemargin",
"latex_cmd(\"setlength{\\\\oddsidemargin}\", 1)");
menu_append_item($2, "\\&topmargin",
"latex_cmd(\"setlength{\\\\topmargin}\", 1)");
menu_append_item($2, "\\text&width",
"latex_cmd(\"setlength{\\\\textwidth}\", 1)");
menu_append_item($2, "\\text&height",
"latex_cmd(\"setlength{\\\\textheight}\", 1)");
menu_append_popup($1, "Brea&ks");
$2 = $1+".Brea&ks";
menu_append_item($2, "\\new&line", "insert(\"\\\\newline\\n\")");
menu_append_item($2, "\\\\&*[]", "latex_linebreak");
menu_append_item($2, "\\line&break", "insert(\"\\\\linebreak[1]\\n\")");
menu_append_item($2, "\\new&page", "insert(\"\\\\newpage\\n\")");
menu_append_item($2, "\\&clearpage", "insert(\"\\\\clearpage\\n\")");
menu_append_item($2, "\\clear&doublepage",
"insert(\"\\\\cleardoublepage\\n\")");
menu_append_item($2, "\\pageb&reak", "insert(\"\\\\pagebreak\\n\")");
menu_append_item($2, "\\&nolinebreak",
"insert(\"\\\\nolinebreak[1]\\n\")");
menu_append_item($2, "\\n&opagebreak", "insert(\"\\\\nopagebreak\\n\")");
menu_append_item($2, "\\&enlargethispage",
"insert(\"\\\\enlargethispage\\n\")");
% paragraph/spaces
menu_append_popup($1, "&Spaces");
$2 = $1+".&Spaces";
menu_append_item($2, "\\&frenchspacing",
"insert(\"\\\\frenchspacing\\n\")");
menu_append_item($2, "\\&@.", "insert(\"\\\\@.\\n\")");
menu_append_item($2, "\\&dotfill", "insert(\"\\\\dotfill\\n\")");
menu_append_item($2, "\\&hfill", "insert(\"\\\\hfill\\n\")");
menu_append_item($2, "\\h&rulefill", "insert(\"\\\\hrulefill\\n\")");
menu_append_item($2, "\\&smallskip", "insert(\"\\\\smallskip\\n\")");
menu_append_item($2, "\\&medskip", "insert(\"\\\\medskip\\n\")");
menu_append_item($2, "\\&bigskip", "insert(\"\\\\bigskip\\n\")");
menu_append_item($2, "\\&vfill", "insert(\"\\\\vfill\\n\")");
menu_append_item($2, "\\hspace", "insert(\"\\\\hspace\\n\")");
menu_append_item($2, "\\vs&pace", "insert(\"\\\\vspace\\n\")");
menu_append_item($2, "Set \\baselines&kip",
"insert(\"\\\\baselineskip 2\\\\baselineskip\\n\")");
% paragraph/boxes
menu_append_popup($1, "Bo&xes");
$2 = $1+".Bo&xes";
menu_append_item($2, "\\&fbox", "latex_cmd(\"fbox\", 1)");
menu_append_item($2, "\\f&ramebox",
"latex_cmd(\"framebox[\\\\width][c]\", 1)");
menu_append_item($2, "\\&mbox", "latex_cmd(\"mbox\", 1)");
menu_append_item($2, "\\ma&kebox",
"latex_cmd(\"makebox[\\\\width][c]\", 1)");
menu_append_item($2, "\\&newsavebox", "latex_cmd(\"newsavebox\", 1)");
menu_append_item($2, "\\ru&le",
"latex_cmd(\"rule{\\\\linewidth}\", 1)");
menu_append_item($2, "\\save&box",
"latex_cmd(\"savebox{}[\\\\linewidth][c]\", 1)");
menu_append_item($2, "\\&sbox",
"latex_cmd(\"sbox{}\", 1)");
menu_append_item($2, "\\&usebox",
"latex_cmd(\"usebox\", 1)");
% links
menu_append_popup(menu, "&Links");
menu_init_helper(menu+".&Links",
["\\&label", "\\&ref", "\\&cite", "\\&nocite", "\\&url",
"\\n&olinkurl", "\\&index"],
&cmd_insert() );
menu_append_popup(menu + ".&Links", "&More index commands");
$1 = menu + ".&Links.&More index commands";
menu_append_item($1, "\\&index{entry!subentry}",
"latex->cmd_insert(\"index\", 1, [\"entry!subentry\"])");
menu_append_item($1, "\\&index{entry|(} (begin range)",
"latex->cmd_insert(\"index\", 1, [\"entry|(\"])");
menu_append_item($1, "\\&index{entry|)} (end range)",
"latex->cmd_insert(\"index\", 1, [\"entry|)\"])");
menu_append_item($1, "\\&index{sortentry@textentry)}",
"latex->cmd_insert(\"index\", 1, [\"sortentry@textentry\"])");
menu_append_item($1, "\\&index{entry|format)}",
"latex->cmd_insert(\"index\", 1, [\"entry|format\"])");
% math
menu_append_popup(menu, "&Math");
$1 = menu+".&Math";
menu_append_item($1, "&Toggle Math Mode", "toggle_math_mode");
menu_append_item($1, "&Greek Letter...", "latex_greek_letter");
menu_append_item($1, "&_{} subscript",
"latex_insert_tags(\"_{\", \"}\", 1, 1)");
menu_append_item($1, "&^{} superscript",
"latex_insert_tags(\"^{\", \"}\", 1, 1)");
menu_append_item($1, "\\&frac",
"latex_insert_tags(\"\\\\frac{\", \"}{}\", 1, 1)");
menu_append_item($1, "\\&int",
"latex_insert_tags(\"\\\\int_{\", \"}^{}\", 1, 1)");
menu_append_item($1, "\\&lim",
"latex_insert_tags(\"\\\\lim_{\", \"}\", 1, 1)");
menu_append_item($1, "\\&oint",
"latex_insert_tags(\"\\\\oint_{\", \"}^{}\", 1, 1)");
menu_append_item($1, "\\&prod",
"latex_insert_tags(\"\\\\prod_{\", \"}^{}\", 1, 1)");
menu_append_item($1, "\\&sum",
"latex_insert_tags(\"\\\\sum_{\", \"}^{}\", 1, 1)");
menu_append_item($1, "\\s&qrt",
"latex_insert_tags(\"\\\\sqrt[]{\", \"}\", 1, 1)");
% math/accents
menu_append_popup($1, "&Accents");
menu_init_helper($1+".&Accents",
["hat", "acute", "bar", "dot", "breve", "check",
"grave", "vec", "ddot", "tilde", "widetilde",
"widehat", "overleftarrow", "overrightarrow",
"overline", "underline", "overbrace", "underbrace"],
&cmd_insert() );
menu_append_popup($1, "&Delimiters");
menu_append_item($2, "\\left(", "latex_insert(\"left(\")");
menu_append_item($2, "\\right)", "latex_insert(\"right)\")");
menu_append_item($2, "\\left[", "latex_insert(\"left[\")");
menu_append_item($2, "\\right]", "latex_insert(\"right[\")");
menu_append_item($2, "\\left{", "latex_insert(\"left\\\\{\")");
menu_append_item($2, "\\right}", "latex_insert(\"right\\\\}\")");
menu_init_helper($1+".&Delimiters",
["rmoustache", "lmoustache", "rgroup", "lgroup",
"arrowvert", "Arrowvert", "bracevert", "lfloor",
"rfloor", "lceil", "rceil", "langle", "rangle"],
&cmd_insert() );
menu_append_item($2, "\\|", "latex_insert(\"\\|\")");
menu_append_popup($1, "F&unctions");
menu_init_helper($1+".F&unctions",
["arccos", "arcsin", "arctan", "arg", "cos",
"cosh", "cot", "coth", "csc", "deg", "det",
"dim", "exp", "gcd", "hom", "inf", "ker",
"lg", "lim", "liminf", "limsup", "ln", "log",
"max", "min", "Pr", "sec", "sin", "sinh",
"sup", "tan", "tanh"],
&cmd_insert() );
menu_append_popup($1, "Binary &Relations");
menu_init_helper($1+".Binary &Relations",
["leq", "geq", "equiv", "models", "prec", "succ",
"sim", "perp", "preceq", "succeq", "simeq",
"mid", "ll", "gg", "asymp", "parallel", "subset",
"supset", "approx", "bowtie", "subseteq",
"supseteq", "cong", "Join", "sqsubset", "sqsupset",
"neq", "smile", "sqsubseteq", "sqsupseteq", "doteq",
"frown", "in", "ni", "propto", "vdash", "dashv",
"not"],
&cmd_insert() );
% math/binary operators
menu_append_popup($1, "&Binary Operators");
menu_init_helper($1+".&Binary Operators",
["pm", "cap", "diamond", "oplus", "mp", "cup",
"bigtriangleup", "ominus", "times", "uplus",
"bigtriangledown", "otimes", "div", "sqcap",
"triangleleft", "oslash", "ast", "sqcup",
"triangleright", "odot", "star", "vee", "bigcirc",
"circ", "wedge", "dagger", "bullet", "setminus",
"ddagger", "cdot", "wr", "analg"],
&cmd_insert() );
% math/spaces
menu_append_popup($1, "Spa&ces");
$2 = $1+".Spa&ces";
menu_append_item($2, "\\! -3/18 quad", "insert(\"\\\\! \")");
menu_append_item($2, "\\, 3/18 quad", "insert(\"\\\\, \")");
menu_append_item($2, "\\: 4/18 quad", "insert(\"\\\\: \")");
menu_append_item($2, "\\; 5/18 quad", "insert(\"\\\\; \")");
menu_append_item($2, "\\quad 1em", &cmd_insert(), "quad");
menu_append_item($2, "\\qquad 2em", &cmd_insert(), "qquad");
% math/arrows
menu_append_popup($1, "Arro&ws");
menu_init_helper($1+".Arro&ws",
{["<-", "leftarrow"], ["<--", "longleftarrow"],
["<=", "Leftarrow"], ["<==", "Longleftarrow"],
["->", "rightarrow"], ["-->", "longrightarrow"],
["=>", "Rightarrow"], ["==>", "Longrightarrow"],
"uparrow", "Uparrow", "downarrow", "Downarrow",
["<->", "leftrightarrow"],
["<-->", "longleftrightarrow"],
["<=>", "Leftrightarrow"],
["<==>", "Longleftrightarrow"],
"updownarrow", "Updownarrow",
["|->", "mapsto"], ["|-->", "longmapsto"],
"hookleftarrow", "hookrightarrow", "leftarpoonup",
"rightarpoonup", "leftarpoondown", "rightarpoondown",
"nearrow", "searrow", "swarrow", "nwarrow"},
&cmd_insert() );
% math/misc
menu_append_popup($1, "&Misc");
menu_init_helper($1+".&Misc",
["ldots", "cdots", "vdots", "ddots", "aleph",
"prime", "forall", "infty", "hbar", "emptyset",
"exists", "nabla", "surd", "triangle", "imath",
"jmath", "ell", "neg", "top", "flat", "natural",
"sharp", "wp", "bot", "clubsuit", "diamondsuit",
"heartsuit", "spadesuit", "Re", "Im", "angle",
"partial"],
&cmd_insert() );
% bibliography
menu_append_popup(menu, "Bibliograph&y");
$1 = menu+".Bibliograph&y";
menu_append_item($1, "&thebibliography",
"latex->env_insert(\"thebibliography\", [\"{99}\"])");
menu_init_helper(menu+".Bibliograph&y",
["\\bib&item", "\\&bibliography", "\\bibliography&style"],
&cmd_insert() );
% PSTricks
menu_append_popup(menu, "PSTr&icks");
$1 = menu + ".PSTr&icks";
menu_append_item($1, "&pspicture", "latex->env_insert(\"pspicture\")");
menu_init_helper($1,
["\\ps&circle", "\\ps&fram", "\\ps&line", "\\&rput"],
&cmd_insert() );
menu_append_separator($1);
menu_append_item($1, "Move points in region", "latex->pst_move_points");
menu_append_item($1, "Update pspicture size", "latex->pst_update_pic_size");
menu_append_separator(menu);
menu_append_item(menu, "Select M&aster File",
"latex_external->select_master_file");
menu_append_item(menu, "Customize Build", "latex_external->cust_view");
menu_append_item(menu, "Compose", "latex_external->compose");
menu_append_item(menu, "&View", "latex_external->view");
menu_append_item(menu, "Show LaTeX lo&g", "latex_external->pop_log_file");
menu_append_item(menu, "Pri&nt", "latex_external->print");
menu_append_item(menu, "&BibTeX", "latex_external->bibtex");
menu_append_item(menu, "Show BibTeX log", "latex_external->show_bibtex_log");
menu_append_item(menu, "Makeinde&x", "latex_external->makeindex");
menu_append_item(menu, "Show Makeindex log", "latex_external->show_mkidx_log");
% menu_append_item(menu, "&Document Outline", "latex_browse_tree");
menu_append_item(menu, "&Remove temp files", "latex_external->clearup");
menu_append_item(menu, "&Remove all files", "latex_external->mrproper");
% convert
menu_append_popup(menu, "&Convert");
$1 = menu+".&Convert";
menu_append_item($1, "$:$ -> $\\colon$", "latex_conv->colon");
menu_append_item($1, "\"a -> ä (Latin 1)", "latex_conv->german_lat1");
menu_append_item($1, "\"a -> ä (UTF-8)", "latex_conv->german_utf8");
menu_append_item($1, "\\\"a -> ä (Latin 1)", "latex_conv->native_lat1");
menu_append_item($1, "\\\"a -> ä (UTF-8)", "latex_conv->native_utf8");
menu_append_item($1, "2.0 (\\bf) -> 2e (\\textbf)", "latex_conv->ltx209_ltx2e");
% specials
menu_append_popup(menu, "Specials");
$1 = menu + ".Specials";
menu_append_item($1, "Simple keymap", "use_keymap(\"$SIMPLE_KEYMAP\")"$);
menu_append_item($1, "Default keymap", "use_keymap(\"$MODE\")"$);
menu_append_separator(menu);
menu_append_item(menu, "Latex info page", "latex->info_page");
menu_append_item(menu, "TeXdoxTk", "() = system(\"texdoctk &\")");
menu_append_item(menu, "LaTeX Mode &Help", "latex_mode_help");
menu_append_popup(menu, "Common &documentations");
$1 = menu + ".Common &documentations";
menu_init_helper($1, {"&amsldoc", "&de-tex-faq",
["&Hyperref manual", "hyperref/manual"], "&Mathmode",
"pst-quickref", "pstricks-doc",
"&scrguide", "s&ymbols-a4", "&visualFAQ"},
&texdoc());
}
mode_set_mode_info(MODE, "init_mode_menu", &menu_init);
create_syntax_table(MODE);
define_syntax("%", "", '%', MODE); % Comment Syntax
define_syntax('\\', '\\', MODE); % Quote character
define_syntax("~^_&#", '+', MODE); % operators
define_syntax("|&{}[]", ',', MODE); % delimiters
define_syntax(TeX_Command_Chars, 'w', MODE);
set_syntax_flags(MODE, 8);
#ifdef HAS_DFA_SYNTAX
private define setup_dfa_callback(name)
{
dfa_enable_highlight_cache("latex.dfa", name);
% comments:
dfa_define_highlight_rule("%(.*[^ \t])?", "comment", name);
dfa_define_highlight_rule("\\documentclass.*}"R, "Qpreprocess", name);
dfa_define_highlight_rule("\\begin{.*}({.*})*"R, "preprocess", name);
dfa_define_highlight_rule("\\end{.*}"R, "Qpreprocess", name);
% % known keywords in curly braces
% dfa_define_highlight_rule("{article}", "Qstring", name);
% dfa_define_highlight_rule("{book}", "Qstring", name);
% dfa_define_highlight_rule("{letter}", "Qstring", name);
% dfa_define_highlight_rule("{report}", "Qstring", name);
% dfa_define_highlight_rule("{slides}", "Qstring", name);
% dfa_define_highlight_rule("{document}", "Qstring", name);
% dfa_define_highlight_rule("{scrreport}", "Qstring", name);
% % environments
% dfa_define_highlight_rule("{abstract}", "Qstring", name);
% dfa_define_highlight_rule("{array}", "Qstring", name);
% dfa_define_highlight_rule("{center}", "Qstring", name);
% dfa_define_highlight_rule("{description}", "Qstring", name);
% dfa_define_highlight_rule("{displaymath}", "Qstring", name);
% dfa_define_highlight_rule("{enumerate}", "Qstring", name);
% dfa_define_highlight_rule("{eqnarray}", "Qstring", name);
% dfa_define_highlight_rule("{figure}", "Qstring", name);
% dfa_define_highlight_rule("{flushleft}", "Qstring", name);
% dfa_define_highlight_rule("{flushright}", "Qstring", name);
% dfa_define_highlight_rule("{itemize}", "Qstring", name);
% dfa_define_highlight_rule("{list}", "Qstring", name);
% dfa_define_highlight_rule("{minipage}", "Qstring", name);
% dfa_define_highlight_rule("{picture}", "Qstring", name);
% dfa_define_highlight_rule("{quotation}", "Qstring", name);
% dfa_define_highlight_rule("{quote}", "Qstring", name);
% dfa_define_highlight_rule("{tabbing}", "Qstring", name);
% dfa_define_highlight_rule("{table}", "Qstring", name);
% dfa_define_highlight_rule("{tabular}", "Qstring", name);
% dfa_define_highlight_rule("{thebibliography}", "Qstring", name);
% dfa_define_highlight_rule("{theorem}", "Qstring", name);
% dfa_define_highlight_rule("{titlepage}", "Qstring", name);
% dfa_define_highlight_rule("{verbatim}", "Qstring", name);
% dfa_define_highlight_rule("{verse}", "Qstring", name);
% % font family
% dfa_define_highlight_rule("{rmfamily}", "Qkeyword2", name);
% dfa_define_highlight_rule("{itshape}", "Qkeyword2", name);
% dfa_define_highlight_rule("{mdseries}", "Qkeyword2", name);
% dfa_define_highlight_rule("{bfseries}", "Qkeyword2", name);
% dfa_define_highlight_rule("{upshape}", "Qkeyword2", name);
% dfa_define_highlight_rule("{slshape}", "Qkeyword2", name);
% dfa_define_highlight_rule("{sffamily}", "Qkeyword2", name);
% dfa_define_highlight_rule("{scshape}", "Qkeyword2", name);
% dfa_define_highlight_rule("{ttfamily}", "Qkeyword2", name);
% dfa_define_highlight_rule("{normalfont}", "Qkeyword2", name);
% dfa_define_highlight_rule("\\text[^{][^{]"R, "keyword2", name);
% dfa_define_highlight_rule("{gather\*?}"R, "Qnumber", name);
% dfa_define_highlight_rule("{align\*?}"R, "Qnumber", name);
% % everithing else between curly braces
% % !!! doesn't span multiple lines !!!
% dfa_define_highlight_rule("{.*}", "Qkeyword1", name);
% dfa_define_highlight_rule("^([^{])*}", "Qkeyword1", name);
% dfa_define_highlight_rule("{.*", "keyword1", name);
% % short symbols that delimit math: $ \[ \] \( \)
% dfa_define_highlight_rule("\\\\\\[.*\\\\\\]", "Qstring", name);
% dfa_define_highlight_rule("\\\\\\(.*\\\\\\)", "Qstring", name);
% dfa_define_highlight_rule("^.*\\\\[\\)\\]]", "Qstring", name);
% dfa_define_highlight_rule("\\\\[\\(\\[].*", "string", name);
% dfa_define_highlight_rule("\\$.*\\$", "Qnumber", name);
% dfa_define_highlight_rule("\\$.*[^ ]", "number", name);
% % dfa_define_highlight_rule("^[^\\$]*\\$", "number", name);
% % Fundamental delimiters in the TeX language: {}[]
% dfa_define_highlight_rule("[{}\\[\\]]", "delimiter", name);
% % \leftX \rightY constructions where X and Y are
% % one of \| \{ \} [ ]( ) / | .
% dfa_define_highlight_rule("\\\\(left|right)(\\\\\\||\\\\{|\\\\}|" +
% "[\\[\\]\\(\\)/\\|\\.])",
% "delimiter", name);
% % type 2 keywords: font definitions
% dfa_define_highlight_rule("\\\\bfseries", "keyword2", name);
% dfa_define_highlight_rule("\\\\emph", "keyword2", name);
% dfa_define_highlight_rule("\\\\itshape", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathbf", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathcal", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathit", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathnormal", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathrm", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathsf", "keyword2", name);
% dfa_define_highlight_rule("\\\\mathtt", "keyword2", name);
% dfa_define_highlight_rule("\\\\mdseries", "keyword2", name);
% dfa_define_highlight_rule("\\\\normalfont", "keyword2", name);
% dfa_define_highlight_rule("\\\\rmfamily", "keyword2", name);
% dfa_define_highlight_rule("\\\\scshape", "keyword2", name);
% dfa_define_highlight_rule("\\\\sffamily", "keyword2", name);
% dfa_define_highlight_rule("\\\\slshape", "keyword2", name);
% dfa_define_highlight_rule("\\\\textbf", "keyword2", name);
% dfa_define_highlight_rule("\\\\textit", "keyword2", name);
% dfa_define_highlight_rule("\\\\textmd", "keyword2", name);
% dfa_define_highlight_rule("\\\\textnormal", "keyword2", name);
% dfa_define_highlight_rule("\\\\textrm", "keyword2", name);
% dfa_define_highlight_rule("\\\\textsc", "keyword2", name);
% dfa_define_highlight_rule("\\\\textsf", "keyword2", name);
% dfa_define_highlight_rule("\\\\textsl", "keyword2", name);
% dfa_define_highlight_rule("\\\\texttt", "keyword2", name);
% dfa_define_highlight_rule("\\\\textup", "keyword2", name);
% dfa_define_highlight_rule("\\\\ttfamily", "keyword2", name);
% dfa_define_highlight_rule("\\\\upshape", "keyword2", name);
% % size
% dfa_define_highlight_rule("\\tiny"R, "keyword2", name);
% dfa_define_highlight_rule("\\scriptsize"R, "keyword2", name);
% dfa_define_highlight_rule("\\footnotesize"R, "keyword2", name);
% dfa_define_highlight_rule("\\small"R, "keyword2", name);
% dfa_define_highlight_rule("\\normalsize"R, "keyword2", name);
% dfa_define_highlight_rule("\\large"R, "keyword2", name);
% dfa_define_highlight_rule("\\Large"R, "keyword2", name);
% dfa_define_highlight_rule("\\LARGE"R, "keyword2", name);
% dfa_define_highlight_rule("\\huge"R, "keyword2", name);
% dfa_define_highlight_rule("\\Huge"R, "keyword2", name);
% type 1 keywords: a backslash followed by
% one of -,:;!%$#&_ |\/{}~^´'``.=> :
dfa_define_highlight_rule("\\[\-,:;!%\$#&_ \|\\/{}~\^'`\.=>]"R,
"keyword1", name);
% type 0 keywords: a backslash followed by alpha characters
dfa_define_highlight_rule("\\["R +
str_quote_string(TeX_Command_Chars, "*", '\\')
+ "]+", "keyword", name);
% % a backslash followed by a single char not covered by one of the
% % previous rules is probably an error
% dfa_define_highlight_rule("\\.", "error", name);
% The symbols ~ ^ _
dfa_define_highlight_rule("[~\\^_]", "operator", name);
% numbers
dfa_define_highlight_rule("[0-9]([\.,0-9]*[0-9])?"R, "number", name);
dfa_define_highlight_rule("\$"R, "number", name);
% % macro parameters(#1 #2 etc)
% dfa_define_highlight_rule("#[1-9]", "operator", name);
% quoted strings
dfa_define_highlight_rule("\"`.*\"'", "Qstring", name); % german
dfa_define_highlight_rule("``.*''", "Qstring", name); % english
% signle quotes
dfa_define_highlight_rule("`[^']*'", "string", name); % english
% quoted strings accross lines; mark the three charaters after and
% before the quote characters
dfa_define_highlight_rule("[\"`]`.?.?.?", "string", name);
dfa_define_highlight_rule(".?.?.?\"'", "string", name);
dfa_define_highlight_rule(".?.?.?''", "string", name);
dfa_define_highlight_rule("[ \t]+$", "trailing_whitespace", name);
% Workaround to make UTF-8 characters are display correctly, not as
% <C3><nn> or <E2><nn><nn>
dfa_define_highlight_rule("\xC2.", "normal", name);
dfa_define_highlight_rule("\xC3.", "normal", name);
dfa_define_highlight_rule("\xE2..", "normal", name);
dfa_define_highlight_rule("\xE3..", "normal", name);
dfa_define_highlight_rule("\xE4..", "normal", name);
dfa_define_highlight_rule("\xE5..", "normal", name);
dfa_define_highlight_rule("\xE6..", "normal", name);
dfa_define_highlight_rule("\xE7..", "normal", name);
dfa_define_highlight_rule("\xE8..", "normal", name);
dfa_define_highlight_rule("\xE9..", "normal", name);
% all the rest
% Fixme: Why we need this rule?
dfa_define_highlight_rule(".", "normal", name);
dfa_build_highlight_table(name);
}
dfa_set_init_callback(&setup_dfa_callback, MODE);
#endif
%%%%%%%%%%
%
% Hooks
%
% Fix me!
% we should save the blocal vars on buffer close, but there isn't a hook for
% this
private define save_buf_before_hook(filename)
{
% variable buf = latex_external->find_buf_of_file(filename);
% if (buf == NULL)
% buf = whatbuf();
% setbuf(buf);
% push_spot();
% eob();
% variable old_buf_flags;
% (,,,old_buf_flags) = getbuf_info();
% setbuf_info( getbuf_info() & ~0x20 );
% % the buf should end with a newline
% !if(bolp()) newline();
% % Fix me!
% while ( andelse {up(1)} {bol(), looking_at_char('%')} ) {
% skip_chars("% ");
% if ( looking_at("LaTeX") ) {
% bol();
% push_mark();
% eol();
% ()=right(1);
% del_region();
% }
% }
% % ()=down(1);
% % !if (eobp()) { eol(); newline(); }
% eob();
% variable error_occured=0;
% ERROR_BLOCK {
% error_occured = 1;
% _clear_error();
% }
% foreach ( ["LaTeX_master_file", "LaTeX_output_format"] ) {
% if (error_occured)
% break;
% variable name = ();
% if ( latex_external->exists_master_file_var(name) )
% insert("% "+name+": "+latex_external->get_master_file_var(name)+"\n");
% }
% setbuf_info( getbuf_info() | (old_buf_flags&0x20) );
% pop_spot();
}
% Fixme: better define a own format_paragraph
private define paragraph_separator()
{
bol(); skip_white();
return orelse {looking_at_char('\\')} {is_commented()} {eolp()};
}
%!%+
%\function{latex_mode}
%\synopsis{latex_mode}
%\usage{Void latex_mode()}
%\description
% This mode is designed to facilitate the task of editing LaTeX files. It
% calls the function \var{latex_mode_hook} on startup if it is defined. In
% addition, if the abbreviation table \var{"TeX"} is defined, that table is
% used.
%
% There are way too many key-bindings for this mode.
% Please have a look at the menus!
%!%-
public define latex_mode()
{
set_mode(MODE, 0x21);
use_keymap(MODE);
use_syntax_table(MODE);
set_buffer_hook("indent_hook", &indent_hook);
set_buffer_hook("newline_indent_hook", &newline_indent_hook);
set_buffer_hook("wrap_hook", &wrap_hook);
set_buffer_hook("wrapok_hook", &wrapok_hook);
append_to_hook("_jed_save_buffer_before_hooks", &save_buf_before_hook);
set_buffer_hook("par_sep", ¶graph_separator);
WRAP_INDENTS = 1;
define_blocal_var("info_page", "latex");
if ( abbrev_table_p("TeX") )
{
set_abbrev_mode(1);
use_abbrev_table("TeX");
}
eob();
!if (bobp()) {
% file is not empty
% Fix me!
% Bad Hack: bol() doesn't take an argument, so 1 is left on stack for
% and
while ( andelse {up(1) and bol(1)} {looking_at_char('%')} ) {
skip_chars("% ");
push_mark();
skip_chars("^:\n");
variable name = bufsubstr();
switch (name)
{ case "LaTeX_master_file" or case "LaTeX_output_format":
create_blocal_var(name);
skip_chars(": ");
push_mark();
eol();
set_blocal_var(bufsubstr(), name);
}
}
bob();
while ( fsearch("\\begin{") )
{
() = right(7);
if ( is_commented() )
continue;
push_mark();
if ( ffind_char('}') )
{
variable env = chop_star( bufsubstr() );
if (orelse {env == "document"} {env_lookup(env, NULL) != NULL})
continue;
variable args = 0;
() = right(1);
while ( looking_at_char('{') )
{
++args;
fsearch_matching_brace();
() = right(1);
}
env_register(env, args,
"(auto-added on file load, found somewhere in document)",
"", NULL);
}
else
pop_mark(0);
}
bob();
if ( fsearch("\\documentclass") )
while ( re_fsearch("\\[nb]e[wg]"R) )
{
() = right(1);
if ( is_commented() )
continue;
if ( looking_at("begin{document}") )
break;
variable is_newcmd = 0, is_newtheorem = 0;
if ( looking_at("newcommand") )
{
is_newcmd = 1;
() = right(10);
}
else if ( looking_at("newenvironment") )
() = right(14);
else if ( looking_at("newtheorem") )
{
is_newtheorem = 1;
() = right(10);
}
else
continue;
if ( looking_at_char('*') )
() = right(1);
variable arg_cnt;
(,name) = cmd_parse_args(0, 1);
name = name[0];
(arg_cnt,) = cmd_parse_args(1, 0);
if (orelse {is_newtheorem} {length(arg_cnt) == 0})
arg_cnt = int(0);
else
{
arg_cnt = integer(arg_cnt[0]);
if (is_newcmd)
{ % \newcommand with default args
variable tmp;
(tmp,) = cmd_parse_args(arg_cnt, 0);
arg_cnt -= length(tmp);
}
}
if (is_newcmd)
{
variable def, is_math = 0;
(,def) = cmd_parse_args(0,1);
def = def[0];
if ( is_substr(def, "\\math") )
is_math = 1;
else if ( string_match(def, "[^\\][_^]"R, 1) >= 1 )
is_math = 1;
name = name[[1:]]; % remove the \
if (cmd_lookup(name, NULL) == NULL)
cmd_register(name, arg_cnt[0], int(is_math),
"(auto-added on file load, found in preample)",
"", NULL);
}
else
{ % environments and theorems
if (env_lookup(name, NULL) == NULL)
env_register(name, arg_cnt,
"(auto-added on file load, found in preample)",
"", NULL);
}
}
bob();
}
run_mode_hooks("latex_mode_hook");
}
% -----
provide("latex");
runhooks("after_latex_load_hook", MODE);
% --- End of file latex.sl