# XML-style type-in macros # ------------------------------------------------------------------------------ # xml_typein_init(reset): initialises the macro set's $XML_typein[] global # settings array. If reset is present and true, causes reinitialisation. # ------------------------------------------------------------------------------ define xml_typein_init { $XML_typein[""] = "" if ("init" in $XML_typein) if ($n_args == 0 || !$1) return if ($em_tab_dist > 0) { $XML_typein.indent = $em_tab_dist sp = " " while (length(sp) < $em_tab_dist) sp = sp sp if (length(sp) > $em_tab_dist) sp = substring(sp, 0, $em_tab_dist) $XML_typein.indentSp = sp } else if ($tab_dist > 0) { $XML_typein.indent = $tab_dist $XML_typein.indentSp = "\t" } else $XML_typein.indent = 1 nameChar = '[-._:\l\d\xb7]' name = '(?:[\l_:]' nameChar '*)' # \xB7 is an extender entityRef = '&' name ';' charRef = '&#(?:\d+|[0-9a-fA-f]+);' reference = entityRef '|' charRef attvalue = '"(?:[^<&"]|' reference ')*"' \ '|' "'(?:[^<&']|" reference ")*'" \ '|' '(?:[^\s<&/>]*)' # allow lazy quoting (for old HTML): # remove this last for full conformance attribute = name '\s*=\s*(?:' attvalue ')' tagNameAttrs = name '(?:\s+' attribute ')*' STag = '\<' tagNameAttrs '\s*' '\>' EmptyElemTag = '\<' tagNameAttrs '\s*' '/\>' ETag = '\' AnyTag = '(?:' STag '|' EmptyElemTag '|' ETag ')' REs = { .nameChar = nameChar, .name = name, .entityRef = entityRef, .charRef = charRef, .reference = reference, .attvalue = attvalue, .attribute = attribute, .tagNameAttrs = tagNameAttrs, .STag = STag, .EmptyElemTag = EmptyElemTag, .ETag = ETag, .AnyTag = AnyTag } $XML_typein.REs = REs $XML_typein.RSName = "XML type-in" $XML_typein.init = "done" } xml_typein_init(1) # ------------------------------------------------------------------------------ # xml_typein_makeclose(pos, inchar): if the inchar is ">", this function # assumes it is the closing angle-bracket of a tag; it builds a # corresponding close tag, and returns that, WITHOUT the ">" ending # the open tag. If the open-tag sequence starts a line, spaces are added # to indent the close tag built here. For use in a type-in macro. # ------------------------------------------------------------------------------ define xml_typein_makeclose { xml_typein_init() tagRE = '(?n' $XML_typein.REs.AnyTag ')' isSingleTagRE = '(?n' $XML_typein.REs.EmptyElemTag ')' isCloseTagRE = '(?n' $XML_typein.REs.ETag ')' isOpenTagRE = '(?n' $XML_typein.REs.STag ')' name = $XML_typein.REs.name pos = $1 inchar = $2 if (inchar != ">") return "" # find preceding "<" for a tag definition opn = search("<", pos - 1, "case", "backward") if (opn < 0) { beep() return "" } # pick up tag text tag = get_range(opn, pos) ">" # does the tag look valid? if (search_string(tag, "^" tagRE "$", 0, "regex") != 0) { beep() tst = search_string(tag, "^" tagRE "$", 0, "regex") return "" } # generate a closing tag if this one is not self-closed clo = "" if (search_string(tag, "^" isOpenTagRE "$", 0, "regex") == 0) clo = replace_in_string(tag, "\\<(" name ")(?:\\s.*)?\\>", \ "", "regex") if (clo == "") # replace failed: maybe tag is self-closing return "" # right: clo closes tag; should it be a block tag? # heuristic: if opening tag has only spaces before it, this is a block-level # tag sol = search("^", opn, "regex", "backward") firstch = search("\\S", sol, "regex") if (firstch == opn) { # this is a block-level tag spaces = get_range(sol, opn) clo = "\n" spaces $XML_typein.indentSp "\n" spaces clo } return clo }