Verbatim-safe typography, ^-punctuation quoting, full-range ^UUUU^, polyglot html
Typographic transforms (---, quote pairs, ~) no longer touch verbatim text: @c/@code/@source_listing content and ^'...'^ spans show exactly the characters written. "^" before any punctuation character quotes it in every target (the apostrophe excepted: ^' opens a literal span), with the new :resolve option on @@@target declaring per-target renderings. The ^UUUU^ code-point form accepts 4-6 hex digits, the full Unicode range. The html output and transform spellings are polyglot (XML-valid), in preparation for an EPUB target. New suites: transform_test, character_test (engine), typography_test (SKS). (from dev 07ce5ea86a0a)
This commit is contained in:
@@ -36,10 +36,10 @@
|
||||
# * the Emacs defcustoms (klammertext-literal-klammers, -transparent-,
|
||||
# -code-, -align-klammers, -indent-offset, -align-cell-max, -align-row-max)
|
||||
# in doc/edit/emacs/klammertext-mode.el / -indent.el / -align.el
|
||||
# * the '@code' rule + literal_code context in
|
||||
# * the '@code'/'@c' rules + literal_code/literal_c contexts in
|
||||
# doc/edit/sublime/Klammertext.sublime-syntax
|
||||
# * the '@code' verbatim region in doc/edit/vim/syntax/klammertext.vim
|
||||
# * the '@code' rule in doc/edit/vscode/syntaxes/klammertext.tmLanguage.json
|
||||
# * the '@code'/'@c' verbatim regions in doc/edit/vim/syntax/klammertext.vim
|
||||
# * the '@code'/'@c' rules in doc/edit/vscode/syntaxes/klammertext.tmLanguage.json
|
||||
#
|
||||
# Installation note: editors locate this file either next to their own plugin
|
||||
# files (a vendored copy, placed there by doc/make_editing_zip.sh), as
|
||||
@@ -57,7 +57,7 @@ import sys
|
||||
|
||||
# Klammer names whose content is a literal argument (verbatim interior,
|
||||
# closed by a named NAME@ delimiter).
|
||||
LITERAL_KLAMMERS = set(["code"])
|
||||
LITERAL_KLAMMERS = set(["code", "c"])
|
||||
|
||||
# Klammers that contribute no indentation level (a @document's paragraphs
|
||||
# stay at the left margin).
|
||||
@@ -91,6 +91,19 @@ def name_char_p(ch):
|
||||
or ('0' <= ch <= '9') or ch == '_')
|
||||
|
||||
|
||||
def find_literal_close(s, name, start):
|
||||
"""Index of the exact close token NAME@ at or after START, or -1.
|
||||
The engine's close is a whole katom, so NAME@ preceded by a name
|
||||
character is content, not a close -- "basic@" does not close @c, and
|
||||
"barcode@" does not close @code. Single-letter literal names (@c) make
|
||||
this guard essential rather than theoretical."""
|
||||
close = name + '@'
|
||||
idx = s.find(close, start)
|
||||
while idx > 0 and name_char_p(s[idx - 1]):
|
||||
idx = s.find(close, idx + 1)
|
||||
return idx
|
||||
|
||||
|
||||
def escaped_p(s, pos):
|
||||
"""True if the char at POS is escaped by an odd run of ^ before it.
|
||||
In Klammertext ^# and ^@ are literal, so such a char is not a delimiter."""
|
||||
@@ -188,9 +201,8 @@ def next_app_delim(s, i, limit):
|
||||
name = s[hit + 1:k]
|
||||
after = s[k] if k < n else None
|
||||
if name in LITERAL_KLAMMERS: # literal span: skip to its close
|
||||
close = name + '@'
|
||||
idx = s.find(close, k)
|
||||
i = n if idx == -1 else idx + len(close)
|
||||
idx = find_literal_close(s, name, k)
|
||||
i = n if idx == -1 else idx + len(name) + 1
|
||||
continue
|
||||
elif after == '-': # @name-arg : opens no span
|
||||
i = k
|
||||
@@ -318,7 +330,7 @@ def literal_match_forward(s, open_pos, name):
|
||||
"""Index of the @ of the NAME@ that closes the literal @NAME at OPEN_POS, or
|
||||
None. The content is opaque, so search for the literal close string."""
|
||||
start = open_pos + 1 + len(name)
|
||||
idx = s.find(name + '@', start)
|
||||
idx = find_literal_close(s, name, start)
|
||||
return idx + len(name) if idx != -1 else None
|
||||
|
||||
|
||||
@@ -333,7 +345,10 @@ def literal_match_backward(s, close_pos, name):
|
||||
if idx == -1:
|
||||
return None
|
||||
before = s[idx - 1] if idx > 0 else None
|
||||
if before != '@' and not escaped_p(s, idx):
|
||||
# The name must end where the token ends: "@c" found inside
|
||||
# "@caption" is not an opener of @c.
|
||||
follower = s[idx + len(open_str)] if idx + len(open_str) < len(s) else None
|
||||
if before != '@' and not name_char_p(follower) and not escaped_p(s, idx):
|
||||
return idx
|
||||
end = idx
|
||||
|
||||
@@ -446,7 +461,7 @@ def state_at(s, pos):
|
||||
i = k
|
||||
if run_len == 1 and name in LITERAL_KLAMMERS:
|
||||
# Verbatim interior: find the closing NAME@ by name.
|
||||
idx = s.find(name + '@', k)
|
||||
idx = find_literal_close(s, name, k)
|
||||
if idx == -1: # never closed
|
||||
return (stack, True)
|
||||
close_end = idx + len(name) + 1
|
||||
@@ -584,7 +599,7 @@ def enclosing_span(s, pos, names):
|
||||
name = s[run_end:k]
|
||||
i = k
|
||||
if run_len == 1 and name in LITERAL_KLAMMERS:
|
||||
idx = s.find(name + '@', k)
|
||||
idx = find_literal_close(s, name, k)
|
||||
if idx == -1:
|
||||
break
|
||||
i = idx + len(name) + 1
|
||||
@@ -692,7 +707,7 @@ def scan_lines(content):
|
||||
name = content[run_end:k]
|
||||
i = k
|
||||
if run_len == 1 and name in LITERAL_KLAMMERS:
|
||||
idx = content.find(name + '@', k)
|
||||
idx = find_literal_close(content, name, k)
|
||||
e = n if idx == -1 else idx + len(name) + 1
|
||||
if line_index(max(hit, e - 1)) != line_index(hit):
|
||||
block_range(hit, e)
|
||||
@@ -886,7 +901,7 @@ def diagnostics(s):
|
||||
name = s[run_end:k]
|
||||
i = k
|
||||
if run_len == 1 and name in LITERAL_KLAMMERS:
|
||||
idx = s.find(name + '@', k)
|
||||
idx = find_literal_close(s, name, k)
|
||||
if idx == -1:
|
||||
probs.append({'start': hit, 'end': k,
|
||||
'message': ("literal klammer @%s has no "
|
||||
|
||||
Reference in New Issue
Block a user