% A reasonable XML mode. Might be usable for SGML. Is certainly not % usable for ordinary HTML, but XHTML should be fine. % % % What it does: % * Robust indenting. None of the XML / XSL files i've worked with % have suffered from bad indentation (not only simple stuff). % The result is approximately: % % % % text % % % * IMHO more usable syntax highlighting than the DocBook/HTML modes % have. I'm not totally happy with the result, but I suspect it's % the best that can be done until the DFA engine supports zero- % width assertions. :-) % % Problems: % * Finding the indent level is O(n) in the number of lines in the % document. That's pretty much the price that has to be paid for % reliability :-/ % * Lack of multi-line DFA really kills highlighting of PI's, CDATA, and % comments. % * " starts a string (i.e attribute value) also when not inside a tag. % This can lead to funny indentation effects in cases like below: % blah" % The solution is to split the ending tag to another line: % blah" % % * The automatic tag closing has problems, when there are multiple % closing tags on the same line. I.e: % % % X % Closing the tag at 'X' will produce another '' instead of % ''. The workaround is obvious ;-) % % 2001-10-18 / Juho Snellman % * First public release % % 2001-10-22 / Juho Snellman % * Fixed the following problem: % % "" % blah % * Added a make_keymap(). (Why did it work without one?) % % 2001-10-31 / Juho Snellman % * Removed the requirement that the file should start with the % pseudo-PI. % % 2001-12-05 / Juho Snellman % * Better regexp for highlighting element names. Gets numbers and % capital letters too. % % 2001-12-07 / Juho Snellman % * Fixed problem with '<>'. % * Added automatic closing of tags. % * Added comment strings for comments.sl % % 2002-04-17 / Juho Snellman % * '< foo' has no effect on the indent, while ' % * Made most functions/variables static. create_syntax_table ("xml"); define_syntax ("<", ">", '(', "xml"); define_syntax ('"', '"', "xml"); % define_syntax ('\'', '\'', "xml"); define_syntax ('\\', '\\', "xml"); define_syntax ("=/", '+', "xml"); define_syntax ("", '%', "xml"); % define_syntax ("", '%', "xml"); set_syntax_flags ("xml", 0x04|0x80); #ifdef HAS_DFA_SYNTAX %%% DFA_CACHE_BEGIN %%% static define setup_dfa_callback (name) { % dfa_enable_highlight_cache ("xml.dfa", name); dfa_define_highlight_rule ("", "comment", name); dfa_define_highlight_rule ("=", "operator", name); dfa_define_highlight_rule ("<|>|", "keyword", name); dfa_define_highlight_rule ("", "preprocess", name); % Slightly flawed, the '>' could be inside an attribute dfa_define_highlight_rule ("", "preprocess", name); dfa_define_highlight_rule ("<\\?.*\\?>", "preprocess", name); dfa_define_highlight_rule ("\&.*;", "preprocess", name); dfa_define_highlight_rule ("\"([^\\\\\"]|\\\\.)*\"", "string", name); % dfa_define_highlight_rule ("'([^\\\\\']|\\\\.)*'", "string", name); dfa_build_highlight_table (name); } dfa_set_init_callback (&setup_dfa_callback, "xml"); %%% DFA_CACHE_END %%% #endif variable XML_INDENT = 2; variable XML_TAG_CONTENT_INDENT = 4; static variable names = Assoc_Type [ String_Type ]; % Sets the name of the last tag on an indent level. static define xml_set_name(ind) { push_spot(); push_mark_eol(); variable name = bufsubstr(); if (string_match(name, "\\([A-Za-z0-9_\\-]+:?[A-Za-z0-9_\\-]*\\)", 1)) { variable pos; variable len; (pos, len) = string_match_nth(1); name = substr(name, pos+1, len); names[sprintf("%d", ind)] = name; } pop_spot(); } static define xml_get_name(ind) { variable sind = sprintf("%d", ind); names[sind]; } static define xml_looking_at(s) { return looking_at(s) and not looking_at(strcat(s," ")); } % Returns the level of nested elements that the start of this line is % inside of. (A negative number is returned if the start of the line % is inside a tag.) static define xml_calculate_indent () { push_spot(); variable row = what_line(); variable ind = 0; EXIT_BLOCK { pop_spot(); } bob(); % 0 : Inside a % 1 : Inside a % 2 : Inside a < ... >, , or < ... /> % 3 : Other variable state = 3; variable closing_tag = 0; % The line on which the current tag started on. variable start_row = 0; variable i = 0; while (1) { % Just in case of bugs involving infinite loops. i++; if (i > 100000) { error(sprintf("Gave up after 100000 tries. Document too large? State: %d Ind: %d Pos: %d/%d", state, ind, what_column(), what_line() )); } switch (0) { state == 0: switch (0) { what_line() >= row : return 0; } { not fsearch(">") : error("Unterminated processing instruction"); } { if (parse_to_point() == 0) state = 3; () = right(2); } } { state == 1: switch (0) { not fsearch("?>") : error("Unterminated processing instruction"); } { what_line() >= row : return 0; } { % Oops, make sure that the "?>" wasn't just an attribute % value. if (parse_to_point() == 0) state = 3; () = right(2); } } { state == 2: switch (0) { looking_at("<") and what_line() == row : % error(sprintf("%d", ind-(1-closing_tag))); return ind-(1-closing_tag);; } { not fsearch(">") : error("Unterminated element"); } { () = right(1); % If the '>' wasn't inside a string, we end the % element if (parse_to_point() == 0) { state = 3; if (what_line() == row) { ind = ind-(1-closing_tag); % Multi-line tag if (what_line() != start_row) { return -1; } return ind; } if (what_line() > row) { return -1; } % If the element was immediately ended, decrement % the indent level () = left(2); if (looking_at("/>")) { ind--; } } } } { state == 3: switch (0) % We passed the point we were supposed to investigate. % Just return what we have now. { what_line() > row : return ind; } % Inside a comment (probably at the start). Move a little % bit forward, and search for a tag start. { parse_to_point() == -2 : () = right(1); () = fsearch("<"); } % Oops, do the same thing for strings too. { parse_to_point() == -1 : () = right(1); () = fsearch("<"); } % Comments are handled magically by Jed, so we don't need to % search for the end manually. Move the point to the right of % the ", 0); run_mode_hooks ("xml_mode_hook"); }