This page documents the patches made in SzSzI to JOE 3.5 (http://joe-editor.sourceforge.net/). The patches were made by Péter Szabó.
Download i386 binary package for Debian Sarge starting from http://www.szszi.hu/~pts/joe/
$ wget http://www.szszi.hu/~pts/joe/joe-3.5.tar.gz $ wget http://www.szszi.hu/~pts/joe/pts-joe-3.5-01-misc.patch $ wget http://www.szszi.hu/~pts/joe/pts-joe-3.5-02-preprocessor.patch $ tar xzvf joe-3.5.tar.gz $ (cd joe-3.5 && patch -p1 <../pts-joe-3.5-01-misc.patch) $ (cd joe-3.5 && patch -p1 <../pts-joe-3.5-02-preprocessor.patch) $ (cd joe-3.5 && ./configure) $ (cd joe-3.5 && make) $ su -c 'cd joe-3.5 && make install'
Download from http://www.szszi.hu/~pts/joe/pts-joe-3.5-01-misc.patch
This patch fixes a few bugs and quirks, and also adds a few small features. If necessary, we can split this patch to several smaller patches.
Bugfixes:
New or improved features:
stat command) now displays the number of bytes the current UTF-8 character occupies.NO_JOERC is present, system configuration files (such es /etc/joe/joerc) are not parsed. (Many functions affected.) The reason for this improvement is that on some systems JOE configuration files are completely bogus, so the user should be able to tell JOE to ignore those files and read configuration from the user's home directory instead.fwrdhist (ufwrdhist()) and bkwdhist (ubkwdhist()) are provided. These commands are useful in history buffers. They jump to the next or previous line, respectively, which starts with the same string as the current line up to the cursor. This is equivalent to bash's history-search-backward and history-search-forward commands, which are bound to the PageUp and PageDown keys in /etc/inputrc on modern Linux distributions. Keyboard bindings added to builtins.c.$HOME/.joe/rc (in main.c). This is so all relevant configuration files can be put by the user into $HOME/.joe and added to a personal CVS.quote command) so that now it can insert bytes (not only characters). Byte insertion is activated by pressing y first. Byte insertion works in hex and non-hex mode, too.Implementation improvements:
.joe folder name is not hard-wired into the .c files anymore. Now it is specified in Makefile.in, and passed to the C code as #define DOTJOEDIR ".joe" .tc=)Download from http://www.szszi.hu/~pts/joe/pts-joe-3.5-02-preprocessor.patch
This patch adds a preprocessor to the .joerc configuration files. Preprocessing is done separately on one each line read from configuration files. Only lines starting with $ are affected (others are left unchanged). The affected lines are replaced by the string returned by the preprocessor, and the replaced line is parsed by JOE as a regular configuration file line.
The rationale for a preprocessor is to allow JOE's configuration depend on the environment variables. For example, the following configuration lines turns off syntax highlighting for the terminal types xterm and rxvt, and turn it on for all other terminals:
-highlight
$()$(if(iseq(getenv("TERM"),"rxvt"),"--highlight"))
$()$(if(iseq(getenv("TERM"),"xterm"),"--highlight"))
The first line (-highlight) turns on syntax highlighting, and the other two lines conditionally turn it off (with --highlight) if the value of the TERM environment variable is rxvt or xterm, respectively.
Here is a more compact solution:
$(if(or(iseq(getenv("TERM"),"xterm"),iseq(getenv("TERM"),"rxvt")),"-"))-highlight
Both solutions demonstrate that the preprocessor syntax is quite ugly. A nicer syntax would be:
joe.options.highlight=
((t=joe.getenv("TERM"))=="xterm" || t=="rxvt") ? false : true
Adding scripting support (e.g. lua) for both the configuration file and runtime macros would be a proper solution to avoid this ugliness. This patch focuses on easy-to-implement and yet powerful-enough configuration file preprocessing.
Definition of the preprocessor syntax:
$ are not preprocessed.$(INSTR), where INSTR is the preprocessor instruction. All other parts of the line are kept intact.[_A-Za-z0-9]{2,}), the replacement is the value of the environment variable.,s, and the replacement is the concatenation of the evaluated values of the expressions.Definition of the preprocessor expression syntax:
", ends with ", and all \ and " inside it must be escaped by preceding it with a \.( and )) properly nested. Parens preceded by an odd number of \s are not considered. Proper strings constants inside the expression are also not considered.Evaluation of expressions:
"s and escaping \<code>s). There is no magic, i.e. <code>\t doesn't get converted to a tabulator.! is evaluated and then negated. The negation of the empty string is the string 1. The negation of any other string is the empty string.qq(STRING) is evaluated as the string constant "STRING" (but the parens of the former must be nested properly).(EXPR1,...) evaluates to the concatenation of the evaluation of its arguments.FUNCTIONNAME(ARGUMENT1,ARGUMENT2,...) . Whitespace is significant.answer() evaluates to 42.getenv(VARNAME) evaluates its argument, and evaluates to the value of the environment variable named VARNAME, or an empty string, if the variable is not defined.concat(STRING1,...) evaluates its aguments, and evaluates to the concatenation of the restults.iseq(STRING1,STRING2) evaluates its arguments, and evaluates to 1 if the results are equal strings. Otherwise it evaluates to the empty string.isglob(STRING,GLOB) evaluates its arguments, and evaluates to 1 if the string matches the glob. Otherwise it evaluates to the empty string. All characters in glob match only themselves, except for ?, which matches any single character; and *, which matches any string (empty or not).if(CONDITION) evaluates its CONDITION argument, ignores the result, and evaluates to the empty string.if(CONDITION,TRUEBRANCH) evaluates its CONDITION argument, and if the results nonempty, it evaluates to the evaluation of its TRUEBRANCH argument. Otherwise, it evaluates to the empty string.if(CONDITION,TRUEBRANCH,FALSEBRANCH) evaluates its CONDITION argument, and if the results nonempty, it evaluates to the evaluation of its TRUEBRANCH argument. Otherwise, it evaluates to the evaluation of its FALSEBRANCH argument.or(EXPR1,...) evaluates its arguments left-to-right up to the first non-empty result, and evaluates to that result. If all results are empty, it evaluates to the empty string. Because of the up to above, this is called lazy evaluation.and(EXPR1,...) evaluates its arguments left-to-right up to the first empty result, and evaluates to that result (empty string). If all results are non-empty, it evaluates to the last result. Because of the up to above, this is called lazy evaluation.