mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-25 05:55:34 +00:00
Add lyx2lyx tools from 2.4.x
This commit is contained in:
parent
ee25620931
commit
a5c328b304
@ -1,6 +1,6 @@
|
||||
# This file is part of lyx2lyx
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2002-2015 The LyX Team
|
||||
# Copyright (C) 2002-2018 The LyX Team
|
||||
# Copyright (C) 2002-2004 Dekel Tsur <dekel@lyx.org>
|
||||
# Copyright (C) 2002-2006 José Matos <jamatos@lyx.org>
|
||||
#
|
||||
@ -20,8 +20,8 @@
|
||||
|
||||
" The LyX module has all the rules related with different lyx file formats."
|
||||
|
||||
from parser_tools import get_value, check_token, find_token, \
|
||||
find_tokens, find_end_of
|
||||
from parser_tools import (get_value, check_token, find_token, find_tokens,
|
||||
find_end_of, find_complete_lines)
|
||||
import os.path
|
||||
import gzip
|
||||
import locale
|
||||
@ -34,8 +34,10 @@ import codecs
|
||||
try:
|
||||
import lyx2lyx_version
|
||||
version__ = lyx2lyx_version.version
|
||||
stable_version = True
|
||||
except: # we are running from build directory so assume the last version
|
||||
version__ = '2.3'
|
||||
version__ = '2.4'
|
||||
stable_version = False
|
||||
|
||||
default_debug__ = 2
|
||||
|
||||
@ -69,8 +71,8 @@ def minor_versions(major, last_minor_version):
|
||||
# Regular expressions used
|
||||
format_re = re.compile(r"(\d)[\.,]?(\d\d)")
|
||||
fileformat = re.compile(r"\\lyxformat\s*(\S*)")
|
||||
original_version = re.compile(r".*?LyX ([\d.]*)")
|
||||
original_tex2lyx_version = re.compile(r".*?tex2lyx ([\d.]*)")
|
||||
original_version = re.compile(b".*?LyX ([\\d.]*)")
|
||||
original_tex2lyx_version = re.compile(b".*?tex2lyx ([\\d.]*)")
|
||||
|
||||
##
|
||||
# file format information:
|
||||
@ -92,8 +94,9 @@ format_relation = [("0_06", [200], minor_versions("0.6" , 4)),
|
||||
("1_6", list(range(277,346)), minor_versions("1.6" , 10)),
|
||||
("2_0", list(range(346,414)), minor_versions("2.0" , 8)),
|
||||
("2_1", list(range(414,475)), minor_versions("2.1" , 5)),
|
||||
("2_2", list(range(475,509)), minor_versions("2.2" , 0)),
|
||||
("2_3", (), minor_versions("2.3" , 0))
|
||||
("2_2", list(range(475,509)), minor_versions("2.2" , 4)),
|
||||
("2_3", list(range(509,545)), minor_versions("2.3" , 0)),
|
||||
("2_4", (), minor_versions("2.4" , 0))
|
||||
]
|
||||
|
||||
####################################################################
|
||||
@ -119,19 +122,29 @@ def formats_list():
|
||||
|
||||
|
||||
def format_info():
|
||||
" Returns a list with supported file formats."
|
||||
out = """Major version:
|
||||
minor versions
|
||||
formats
|
||||
" Returns a list with the supported file formats."
|
||||
template = """
|
||||
%s\tstable format: %s
|
||||
\tstable versions: %s
|
||||
\tdevelopment formats: %s
|
||||
"""
|
||||
|
||||
out = "version: formats and versions"
|
||||
for version in format_relation:
|
||||
major = str(version[2][0])
|
||||
versions = str(version[2][1:])
|
||||
if len(version[1]) == 1:
|
||||
formats = str(version[1][0])
|
||||
stable_format = str(version[1][0])
|
||||
elif not stable_version and major == version__:
|
||||
stable_format = "-- not yet --"
|
||||
versions = "-- not yet --"
|
||||
formats = "%s - %s" % (version[1][0], version[1][-1])
|
||||
else:
|
||||
formats = "%s - %s" % (version[1][-1], version[1][0])
|
||||
out += "%s\n\t%s\n\t%s\n\n" % (major, versions, formats)
|
||||
formats = "%s - %s" % (version[1][0], version[1][-2])
|
||||
stable_format = str(version[1][-1])
|
||||
|
||||
out += template % (major, stable_format, versions, formats)
|
||||
return out + '\n'
|
||||
|
||||
|
||||
@ -281,7 +294,7 @@ class LyX_base:
|
||||
""" Emits warning to self.error, if the debug_level is less
|
||||
than the self.debug."""
|
||||
if debug_level <= self.debug:
|
||||
self.err.write("Warning: " + message + "\n")
|
||||
self.err.write("lyx2lyx warning: " + message + "\n")
|
||||
|
||||
|
||||
def error(self, message):
|
||||
@ -434,8 +447,8 @@ class LyX_base:
|
||||
else:
|
||||
header = self.header
|
||||
|
||||
for line in header + [''] + self.body:
|
||||
self.output.write(line+u"\n")
|
||||
for line in header + [u''] + self.body:
|
||||
self.output.write(line+u'\n')
|
||||
|
||||
|
||||
def choose_output(self, output):
|
||||
@ -506,10 +519,10 @@ class LyX_base:
|
||||
file, returns the most likely value, or None otherwise."""
|
||||
|
||||
for line in self.header:
|
||||
if line[0] != "#":
|
||||
if line[0:1] != b"#":
|
||||
return None
|
||||
|
||||
line = line.replace("fix",".")
|
||||
line = line.replace(b"fix",b".")
|
||||
# need to test original_tex2lyx_version first because tex2lyx
|
||||
# writes "#LyX file created by tex2lyx 2.2"
|
||||
result = original_tex2lyx_version.match(line)
|
||||
@ -517,14 +530,14 @@ class LyX_base:
|
||||
result = original_version.match(line)
|
||||
if result:
|
||||
# Special know cases: reLyX and KLyX
|
||||
if line.find("reLyX") != -1 or line.find("KLyX") != -1:
|
||||
if line.find(b"reLyX") != -1 or line.find(b"KLyX") != -1:
|
||||
return "0.12"
|
||||
if result:
|
||||
res = result.group(1)
|
||||
if not res:
|
||||
self.warning(line)
|
||||
#self.warning("Version %s" % result.group(1))
|
||||
return res
|
||||
return res.decode('ascii') if not PY2 else res
|
||||
self.warning(str(self.header[:2]))
|
||||
return None
|
||||
|
||||
@ -533,7 +546,7 @@ class LyX_base:
|
||||
" Set the header with the version used."
|
||||
|
||||
initial_comment = " ".join(["#LyX %s created this file." % version__,
|
||||
"For more info see http://www.lyx.org/"])
|
||||
"For more info see https://www.lyx.org/"])
|
||||
|
||||
# Simple heuristic to determine the comment that always starts
|
||||
# a lyx file
|
||||
@ -582,6 +595,7 @@ class LyX_base:
|
||||
|
||||
#Note that the module will be added at the END of the extant ones
|
||||
def add_module(self, module):
|
||||
" Append module to the modules list."
|
||||
i = find_token(self.header, "\\begin_modules", 0)
|
||||
if i == -1:
|
||||
#No modules yet included
|
||||
@ -602,7 +616,16 @@ class LyX_base:
|
||||
self.header.insert(j, module)
|
||||
|
||||
|
||||
def del_module(self, module):
|
||||
" Delete `module` from module list, return success."
|
||||
modlist = self.get_module_list()
|
||||
if module not in modlist:
|
||||
return False
|
||||
self.set_module_list([line for line in modlist if line != module])
|
||||
return True
|
||||
|
||||
def get_module_list(self):
|
||||
" Return list of modules."
|
||||
i = find_token(self.header, "\\begin_modules", 0)
|
||||
if (i == -1):
|
||||
return []
|
||||
@ -611,23 +634,23 @@ class LyX_base:
|
||||
|
||||
|
||||
def set_module_list(self, mlist):
|
||||
modbegin = find_token(self.header, "\\begin_modules", 0)
|
||||
newmodlist = ['\\begin_modules'] + mlist + ['\\end_modules']
|
||||
if (modbegin == -1):
|
||||
i = find_token(self.header, "\\begin_modules", 0)
|
||||
if (i == -1):
|
||||
#No modules yet included
|
||||
tclass = find_token(self.header, "\\textclass", 0)
|
||||
if tclass == -1:
|
||||
self.warning("Malformed LyX document: No \\textclass!!")
|
||||
return
|
||||
modbegin = tclass + 1
|
||||
self.header[modbegin:modbegin] = newmodlist
|
||||
return
|
||||
modend = find_token(self.header, "\\end_modules", modbegin)
|
||||
if modend == -1:
|
||||
self.warning("(set_module_list)Malformed LyX document: No \\end_modules.")
|
||||
return
|
||||
newmodlist = ['\\begin_modules'] + mlist + ['\\end_modules']
|
||||
self.header[modbegin:modend + 1] = newmodlist
|
||||
i = j = tclass + 1
|
||||
else:
|
||||
j = find_token(self.header, "\\end_modules", i)
|
||||
if j == -1:
|
||||
self.warning("(set_module_list) Malformed LyX document: No \\end_modules.")
|
||||
return
|
||||
j += 1
|
||||
if mlist:
|
||||
mlist = ['\\begin_modules'] + mlist + ['\\end_modules']
|
||||
self.header[i:j] = mlist
|
||||
|
||||
|
||||
def set_parameter(self, param, value):
|
||||
@ -678,7 +701,7 @@ class LyX_base:
|
||||
try:
|
||||
conv(self)
|
||||
except:
|
||||
self.warning("An error ocurred in %s, %s" %
|
||||
self.warning("An error occurred in %s, %s" %
|
||||
(version, str(conv)),
|
||||
default_debug__)
|
||||
if not self.try_hard:
|
||||
@ -760,6 +783,53 @@ class LyX_base:
|
||||
return mode, steps
|
||||
|
||||
|
||||
def append_local_layout(self, new_layout):
|
||||
" Append `new_layout` to the local layouts."
|
||||
# new_layout may be a string or a list of strings (lines)
|
||||
try:
|
||||
new_layout = new_layout.splitlines()
|
||||
except AttributeError:
|
||||
pass
|
||||
i = find_token(self.header, "\\begin_local_layout", 0)
|
||||
if i == -1:
|
||||
k = find_token(self.header, "\\language", 0)
|
||||
if k == -1:
|
||||
# this should not happen
|
||||
self.warning("Malformed LyX document! No \\language header found!")
|
||||
return
|
||||
self.header[k : k] = ["\\begin_local_layout", "\\end_local_layout"]
|
||||
i = k
|
||||
|
||||
j = find_end_of(self.header, i, "\\begin_local_layout", "\\end_local_layout")
|
||||
if j == -1:
|
||||
# this should not happen
|
||||
self.warning("Malformed LyX document: Can't find end of local layout!")
|
||||
return
|
||||
|
||||
self.header[i+1 : i+1] = new_layout
|
||||
|
||||
def del_local_layout(self, layout_def):
|
||||
" Delete `layout_def` from local layouts, return success."
|
||||
i = find_complete_lines(self.header, layout_def)
|
||||
if i == -1:
|
||||
return False
|
||||
j = i+len(layout_def)
|
||||
if (self.header[i-1] == "\\begin_local_layout" and
|
||||
self.header[j] == "\\end_local_layout"):
|
||||
i -=1
|
||||
j +=1
|
||||
self.header[i:j] = []
|
||||
return True
|
||||
|
||||
def del_from_header(self, lines):
|
||||
" Delete `lines` from the document header, return success."
|
||||
i = find_complete_lines(self.header, lines)
|
||||
if i == -1:
|
||||
return False
|
||||
j = i + len(lines)
|
||||
self.header[i:j] = []
|
||||
return True
|
||||
|
||||
# Part of an unfinished attempt to make lyx2lyx gave a more
|
||||
# structured view of the document.
|
||||
# def get_toc(self, depth = 4):
|
||||
|
@ -34,6 +34,7 @@ dist_lyx2lyx_PYTHON = \
|
||||
lyx_2_1.py \
|
||||
lyx_2_2.py \
|
||||
lyx_2_3.py \
|
||||
lyx_2_4.py \
|
||||
profiling.py \
|
||||
test_parser_tools.py
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#! /usr/bin/env python
|
||||
#! /usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2002-2011 The LyX Team
|
||||
# Copyright (C) 2002-2007 José Matos <jamatos@lyx.org>
|
||||
@ -56,26 +56,27 @@ def main():
|
||||
parser.add_argument("--noisy",
|
||||
action="store_const", const=10, dest="debug")
|
||||
parser.add_argument("-c", "--encoding", type=cmd_arg, dest="cjk_encoding",
|
||||
help="files in format 413 and lower are read and"
|
||||
help="Files in format 413 and lower are read and"
|
||||
" written in the format of CJK-LyX."
|
||||
"If encoding is not given or 'auto' the encoding"
|
||||
"is determined from the locale.")
|
||||
" If encoding is not given or 'auto' the encoding"
|
||||
" is determined from the locale.")
|
||||
parser.add_argument("-e", "--err", type=cmd_arg, dest="error",
|
||||
help= "file name of the error file else goes to stderr")
|
||||
help= "File name of the error file else goes to stderr.")
|
||||
parser.add_argument("-o", "--output", type=cmd_arg, dest="output",
|
||||
help= "name of the output file else goes to stdout")
|
||||
help= "Name of the output file else goes to stdout.")
|
||||
parser.add_argument("-t", "--to", type=cmd_arg, dest= "end_format",
|
||||
help= "destination file format, default (latest)")
|
||||
help= "Destination file format, default <latest>.")
|
||||
parser.add_argument("-V", "--final_version", type=cmd_arg, dest= "final_version",
|
||||
help= "destination version, default (latest)")
|
||||
help= "Destination version, default <latest>.")
|
||||
parser.add_argument("-l", "--list", action="store_true",
|
||||
help = "list all available formats and supported versions")
|
||||
help = "List all available formats and supported versions.")
|
||||
parser.add_argument("-n", "--try-hard", action="store_true",
|
||||
help = "try hard (ignore any convertion errors)")
|
||||
help = "Try hard (ignore any conversion errors).")
|
||||
parser.add_argument("-s", "--systemlyxdir", type=cmd_arg, dest= "systemlyxdir",
|
||||
help= "LyX system directory for conversion from version 489 or older")
|
||||
help= "LyX system directory for conversion from"
|
||||
" version 489 or older.")
|
||||
parser.add_argument('--version', action='version', version="""lyx2lyx, version %s
|
||||
Copyright (C) 2011 The LyX Team, José Matos and Dekel Tsur""" % LyX.version__)
|
||||
Copyright (C) 2011 The LyX Team, José Matos and Dekel Tsur""" % LyX.version__)
|
||||
parser.add_argument("input", nargs='?', type=cmd_arg, default=None)
|
||||
|
||||
options = parser.parse_args()
|
||||
|
@ -17,8 +17,8 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
'''
|
||||
This module offers several free functions to help with lyx2lyx'ing.
|
||||
More documentaton is below, but here is a quick guide to what
|
||||
This module offers several free functions to help with lyx2lyx'ing.
|
||||
More documentaton is below, but here is a quick guide to what
|
||||
they do. Optional arguments are marked by brackets.
|
||||
|
||||
add_to_preamble(document, text):
|
||||
@ -37,8 +37,8 @@ insert_to_preamble(document, text[, index]):
|
||||
default index is 0, so the material is inserted at the beginning.
|
||||
Prepends a comment "% Added by lyx2lyx" to text.
|
||||
|
||||
put_cmd_in_ert(arg):
|
||||
Here arg should be a list of strings (lines), which we want to
|
||||
put_cmd_in_ert(cmd):
|
||||
Here cmd should be a list of strings (lines), which we want to
|
||||
wrap in ERT. Returns a list of strings so wrapped.
|
||||
A call to this routine will often go something like this:
|
||||
i = find_token('\\begin_inset FunkyInset', ...)
|
||||
@ -65,23 +65,38 @@ lyx2verbatim(document, lines):
|
||||
can and return a string containing the translated material.
|
||||
|
||||
latex_length(slen):
|
||||
Convert lengths (in LyX form) to their LaTeX representation. Returns
|
||||
(bool, length), where the bool tells us if it was a percentage, and
|
||||
the length is the LaTeX representation.
|
||||
Convert lengths (in LyX form) to their LaTeX representation. Returns
|
||||
(bool, length), where the bool tells us if it was a percentage, and
|
||||
the length is the LaTeX representation.
|
||||
|
||||
convert_info_insets(document, type, func):
|
||||
Applies func to the argument of all info insets matching certain types
|
||||
type : the type to match. This can be a regular expression.
|
||||
func : function from string to string to apply to the "arg" field of
|
||||
the info insets.
|
||||
Applies func to the argument of all info insets matching certain types
|
||||
type : the type to match. This can be a regular expression.
|
||||
func : function from string to string to apply to the "arg" field of
|
||||
the info insets.
|
||||
|
||||
is_document_option(document, option):
|
||||
Find if _option_ is a document option (\\options in the header).
|
||||
|
||||
insert_document_option(document, option):
|
||||
Insert _option_ as a document option.
|
||||
|
||||
remove_document_option(document, option):
|
||||
Remove _option_ as a document option.
|
||||
|
||||
revert_language(document, lyxname, babelname="", polyglossianame=""):
|
||||
Reverts native language support to ERT
|
||||
If babelname or polyglossianame is empty, it is assumed
|
||||
this language package is not supported for the given language.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import string
|
||||
from parser_tools import find_token, find_end_of_inset
|
||||
import sys
|
||||
from parser_tools import (find_token, find_end_of_inset, get_containing_layout,
|
||||
get_containing_inset, get_value, get_bool_value)
|
||||
from unicode_symbols import unicode_reps
|
||||
|
||||
|
||||
# This will accept either a list of lines or a single line.
|
||||
# It is bad practice to pass something with embedded newlines,
|
||||
# though we will handle that.
|
||||
@ -118,36 +133,53 @@ def add_to_preamble(document, text):
|
||||
# It should really be a list.
|
||||
def insert_to_preamble(document, text, index = 0):
|
||||
""" Insert text to the preamble at a given line"""
|
||||
|
||||
|
||||
if not type(text) is list:
|
||||
# split on \n just in case
|
||||
# it'll give us the one element list we want
|
||||
# if there's no \n, too
|
||||
text = text.split('\n')
|
||||
|
||||
|
||||
text.insert(0, "% Added by lyx2lyx")
|
||||
document.preamble[index:index] = text
|
||||
|
||||
|
||||
def put_cmd_in_ert(arg):
|
||||
'''
|
||||
arg should be a list of lines we want to wrap in ERT.
|
||||
Returns a list of strings, with the lines so wrapped.
|
||||
'''
|
||||
|
||||
ret = ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Plain Layout", ""]
|
||||
# It will be faster for us to work with a single string internally.
|
||||
# That way, we only go through the unicode_reps loop once.
|
||||
if type(arg) is list:
|
||||
s = "\n".join(arg)
|
||||
else:
|
||||
s = arg
|
||||
for rep in unicode_reps:
|
||||
s = s.replace(rep[1], rep[0])
|
||||
s = s.replace('\\', "\\backslash\n")
|
||||
ret += s.splitlines()
|
||||
ret += ["\\end_layout", "", "\\end_inset"]
|
||||
return ret
|
||||
# A dictionary of Unicode->LICR mappings for use in a Unicode string's translate() method
|
||||
# Created from the reversed list to keep the first of alternative definitions.
|
||||
licr_table = {ord(ch): cmd for cmd, ch in unicode_reps[::-1]}
|
||||
|
||||
def put_cmd_in_ert(cmd, is_open=False, as_paragraph=False):
|
||||
"""
|
||||
Return ERT inset wrapping `cmd` as a list of strings.
|
||||
|
||||
`cmd` can be a string or list of lines. Non-ASCII characters are converted
|
||||
to the respective LICR macros if defined in unicodesymbols,
|
||||
`is_open` is a boolean setting the inset status to "open",
|
||||
`as_paragraph` wraps the ERT inset in a Standard paragraph.
|
||||
"""
|
||||
|
||||
status = {False:"collapsed", True:"open"}
|
||||
ert_inset = ["\\begin_inset ERT", "status %s"%status[is_open], "",
|
||||
"\\begin_layout Plain Layout", "",
|
||||
# content here ([5:5])
|
||||
"\\end_layout", "", "\\end_inset"]
|
||||
|
||||
paragraph = ["\\begin_layout Standard",
|
||||
# content here ([1:1])
|
||||
"", "", "\\end_layout", ""]
|
||||
# ensure cmd is an unicode instance and make it "LyX safe".
|
||||
if isinstance(cmd, list):
|
||||
cmd = u"\n".join(cmd)
|
||||
elif sys.version_info[0] == 2 and isinstance(cmd, str):
|
||||
cmd = cmd.decode('utf8')
|
||||
cmd = cmd.translate(licr_table)
|
||||
cmd = cmd.replace("\\", "\n\\backslash\n")
|
||||
|
||||
ert_inset[5:5] = cmd.splitlines()
|
||||
if not as_paragraph:
|
||||
return ert_inset
|
||||
paragraph[1:1] = ert_inset
|
||||
return paragraph
|
||||
|
||||
|
||||
def get_ert(lines, i, verbatim = False):
|
||||
@ -300,7 +332,7 @@ def lyx2verbatim(document, lines):
|
||||
|
||||
|
||||
def latex_length(slen):
|
||||
'''
|
||||
'''
|
||||
Convert lengths to their LaTeX representation. Returns (bool, length),
|
||||
where the bool tells us if it was a percentage, and the length is the
|
||||
LaTeX representation.
|
||||
@ -314,9 +346,14 @@ def latex_length(slen):
|
||||
# the + always precedes the -
|
||||
|
||||
# Convert relative lengths to LaTeX units
|
||||
units = {"text%":"\\textwidth", "col%":"\\columnwidth",
|
||||
"page%":"\\paperwidth", "line%":"\\linewidth",
|
||||
"theight%":"\\textheight", "pheight%":"\\paperheight"}
|
||||
units = {"col%": "\\columnwidth",
|
||||
"text%": "\\textwidth",
|
||||
"page%": "\\paperwidth",
|
||||
"line%": "\\linewidth",
|
||||
"theight%": "\\textheight",
|
||||
"pheight%": "\\paperheight",
|
||||
"baselineskip%": "\\baselineskip"
|
||||
}
|
||||
for unit in list(units.keys()):
|
||||
i = slen.find(unit)
|
||||
if i == -1:
|
||||
@ -536,3 +573,220 @@ def convert_info_insets(document, type, func):
|
||||
new_arg = func(arg.group(1))
|
||||
document.body[i + 2] = 'arg "%s"' % new_arg
|
||||
i += 3
|
||||
|
||||
|
||||
def insert_document_option(document, option):
|
||||
"Insert _option_ as a document option."
|
||||
|
||||
# Find \options in the header
|
||||
i = find_token(document.header, "\\options", 0)
|
||||
# if the options does not exists add it after the textclass
|
||||
if i == -1:
|
||||
i = find_token(document.header, "\\textclass", 0) + 1
|
||||
document.header.insert(i, r"\options %s" % option)
|
||||
return
|
||||
# otherwise append to options
|
||||
if not is_document_option(document, option):
|
||||
document.header[i] += ",%s" % option
|
||||
|
||||
|
||||
def remove_document_option(document, option):
|
||||
""" Remove _option_ as a document option."""
|
||||
|
||||
i = find_token(document.header, "\\options")
|
||||
options = get_value(document.header, "\\options", i)
|
||||
options = [op.strip() for op in options.split(',')]
|
||||
|
||||
# Remove `option` from \options
|
||||
options = [op for op in options if op != option]
|
||||
|
||||
if options:
|
||||
document.header[i] = "\\options " + ','.join(options)
|
||||
else:
|
||||
del document.header[i]
|
||||
|
||||
|
||||
def is_document_option(document, option):
|
||||
"Find if _option_ is a document option"
|
||||
|
||||
options = get_value(document.header, "\\options")
|
||||
options = [op.strip() for op in options.split(',')]
|
||||
return option in options
|
||||
|
||||
|
||||
singlepar_insets = [s.strip() for s in
|
||||
u"Argument, Caption Above, Caption Below, Caption Bicaption,"
|
||||
u"Caption Centered, Caption FigCaption, Caption Standard, Caption Table,"
|
||||
u"Flex Chemistry, Flex Fixme_Note, Flex Latin, Flex ListOfSlides,"
|
||||
u"Flex Missing_Figure, Flex PDF-Annotation, Flex PDF-Comment-Setup,"
|
||||
u"Flex Reflectbox, Flex S/R expression, Flex Sweave Input File,"
|
||||
u"Flex Sweave Options, Flex Thanks_Reference, Flex URL, Foot InTitle,"
|
||||
u"IPADeco, Index, Info, Phantom, Script".split(',')]
|
||||
# print(singlepar_insets)
|
||||
|
||||
def revert_language(document, lyxname, babelname="", polyglossianame=""):
|
||||
" Revert native language support "
|
||||
|
||||
# Does the document use polyglossia?
|
||||
use_polyglossia = False
|
||||
if get_bool_value(document.header, "\\use_non_tex_fonts"):
|
||||
i = find_token(document.header, "\\language_package")
|
||||
if i == -1:
|
||||
document.warning("Malformed document! Missing \\language_package")
|
||||
else:
|
||||
pack = get_value(document.header, "\\language_package", i)
|
||||
if pack in ("default", "auto"):
|
||||
use_polyglossia = True
|
||||
|
||||
# Do we use this language with polyglossia?
|
||||
with_polyglossia = use_polyglossia and polyglossianame != ""
|
||||
# Do we use this language with babel?
|
||||
with_babel = with_polyglossia == False and babelname != ""
|
||||
|
||||
# Are we dealing with a primary or secondary language?
|
||||
primary = document.language == lyxname
|
||||
secondary = False
|
||||
|
||||
# Main language first
|
||||
orig_doc_language = document.language
|
||||
if primary:
|
||||
# Change LyX document language to English (we will tell LaTeX
|
||||
# to use the original language at the end of this function):
|
||||
document.language = "english"
|
||||
i = find_token(document.header, "\\language %s" % lyxname, 0)
|
||||
if i != -1:
|
||||
document.header[i] = "\\language english"
|
||||
|
||||
# Now look for occurences in the body
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, "\\lang", i+1)
|
||||
if i == -1:
|
||||
break
|
||||
if document.body[i].startswith("\\lang %s" % lyxname):
|
||||
secondary = True
|
||||
texname = use_polyglossia and polyglossianame or babelname
|
||||
elif primary and document.body[i].startswith("\\lang english"):
|
||||
# Since we switched the main language manually, English parts need to be marked
|
||||
texname = "english"
|
||||
else:
|
||||
continue
|
||||
|
||||
parent = get_containing_layout(document.body, i)
|
||||
i_e = parent[2] # end line no,
|
||||
# print(i, texname, parent, document.body[i+1], file=sys.stderr)
|
||||
|
||||
# Move leading space to the previous line:
|
||||
if document.body[i+1].startswith(" "):
|
||||
document.body[i+1] = document.body[i+1][1:]
|
||||
document.body.insert(i, " ")
|
||||
continue
|
||||
|
||||
# TODO: handle nesting issues with font attributes, e.g.
|
||||
# \begin_layout Standard
|
||||
#
|
||||
# \emph on
|
||||
# \lang macedonian
|
||||
# Македонски јазик
|
||||
# \emph default
|
||||
# — јужнословенски јазик, дел од групата на словенски јазици од јазичното
|
||||
# семејство на индоевропски јазици.
|
||||
# Македонскиот е службен и национален јазик во Македонија.
|
||||
# \end_layout
|
||||
|
||||
# Ensure correct handling of list labels
|
||||
if (parent[0] in ["Labeling", "Description"]
|
||||
and not " " in "\n".join(document.body[parent[3]:i])):
|
||||
# line `i+1` is first line of a list item,
|
||||
# part before a space character is the label
|
||||
# TODO: insets or language change before first space character
|
||||
labelline = document.body[i+1].split(' ', 1)
|
||||
if len(labelline) > 1:
|
||||
# Insert a space in the (original) document language
|
||||
# between label and remainder.
|
||||
# print(" Label:", labelline, file=sys.stderr)
|
||||
lines = [labelline[0],
|
||||
"\\lang %s" % orig_doc_language,
|
||||
" ",
|
||||
"\\lang %s" % (primary and "english" or lyxname),
|
||||
labelline[1]]
|
||||
document.body[i+1:i+2] = lines
|
||||
i_e += 4
|
||||
|
||||
# Find out where to end the language change.
|
||||
langswitch = i
|
||||
while True:
|
||||
langswitch = find_token(document.body, "\\lang", langswitch+1, i_e)
|
||||
if langswitch == -1:
|
||||
break
|
||||
# print(" ", langswitch, document.body[langswitch], file=sys.stderr)
|
||||
# skip insets
|
||||
i_a = parent[3] # paragraph start line
|
||||
container = get_containing_inset(document.body[i_a:i_e], langswitch-i_a)
|
||||
if container and container[1] < langswitch-i_a and container[2] > langswitch-i_a:
|
||||
# print(" inset", container, file=sys.stderr)
|
||||
continue
|
||||
i_e = langswitch
|
||||
break
|
||||
|
||||
# use function or environment?
|
||||
singlepar = i_e - i < 3
|
||||
if not singlepar and parent[0] == "Plain Layout":
|
||||
# environment not allowed in some insets
|
||||
container = get_containing_inset(document.body, i)
|
||||
singlepar = container[0] in singlepar_insets
|
||||
|
||||
# Delete empty language switches:
|
||||
if not "".join(document.body[i+1:i_e]):
|
||||
del document.body[i:i_e]
|
||||
i -= 1
|
||||
continue
|
||||
|
||||
if singlepar:
|
||||
if with_polyglossia:
|
||||
begin_cmd = "\\text%s{"%texname
|
||||
elif with_babel:
|
||||
begin_cmd = "\\foreignlanguage{%s}{" % texname
|
||||
end_cmd = "}"
|
||||
else:
|
||||
if with_polyglossia:
|
||||
begin_cmd = "\\begin{%s}"%texname
|
||||
end_cmd = "\\end{%s}"%texname
|
||||
elif with_babel:
|
||||
begin_cmd = "\\begin{otherlanguage}{%s}" % texname
|
||||
end_cmd = "\\end{otherlanguage}"
|
||||
|
||||
if (not primary or texname == "english"):
|
||||
try:
|
||||
document.body[i_e:i_e] = put_cmd_in_ert(end_cmd)
|
||||
document.body[i+1:i+1] = put_cmd_in_ert(begin_cmd)
|
||||
except UnboundLocalError:
|
||||
pass
|
||||
del document.body[i]
|
||||
|
||||
if not (primary or secondary):
|
||||
return
|
||||
|
||||
# Make the language known to Babel/Polyglossia and ensure the correct
|
||||
# document language:
|
||||
doc_lang_switch = ""
|
||||
if with_babel:
|
||||
# add as global option
|
||||
insert_document_option(document, babelname)
|
||||
# Since user options are appended to the document options,
|
||||
# Babel will treat `babelname` as primary language.
|
||||
if not primary:
|
||||
doc_lang_switch = "\\selectlanguage{%s}" % orig_doc_language
|
||||
if with_polyglossia:
|
||||
# Define language in the user preamble
|
||||
# (don't use \AtBeginDocument, this fails with some languages).
|
||||
add_to_preamble(document, ["\\usepackage{polyglossia}",
|
||||
"\\setotherlanguage{%s}" % polyglossianame])
|
||||
if primary:
|
||||
# Changing the main language must be done in the document body.
|
||||
doc_lang_switch = "\\resetdefaultlanguage{%s}" % polyglossianame
|
||||
|
||||
# Reset LaTeX main language if required and not already done
|
||||
if doc_lang_switch and doc_lang_switch[1:] not in document.body[8:20]:
|
||||
document.body[2:2] = put_cmd_in_ert(doc_lang_switch,
|
||||
is_open=True, as_paragraph=True)
|
||||
|
@ -32,18 +32,17 @@ def regularise_header(document):
|
||||
|
||||
def find_next_space(line, j):
|
||||
""" Return position of next space or backslash, which one comes
|
||||
first, starting from position k, if not existing return last
|
||||
position in line."""
|
||||
l = line.find(' ', j)
|
||||
if l == -1:
|
||||
l = len(line)
|
||||
k = line.find('\\', j)
|
||||
if k == -1:
|
||||
k = len(line)
|
||||
first, starting from position j, if none exists returns last
|
||||
position in line (+1)."""
|
||||
space_pos = line.find(' ', j)
|
||||
if space_pos == -1:
|
||||
space_pos = len(line)
|
||||
|
||||
if k < l:
|
||||
return k
|
||||
return l
|
||||
bksl_pos = line.find('\\', j)
|
||||
if bksl_pos == -1:
|
||||
bksl_pos = len(line)
|
||||
|
||||
return min(space_pos, bksl_pos)
|
||||
|
||||
|
||||
def regularise_body(document):
|
||||
@ -65,36 +64,38 @@ def regularise_body(document):
|
||||
while i < len(document.body):
|
||||
line = document.body[i]
|
||||
j = 0
|
||||
tmp = []
|
||||
new_block = []
|
||||
while j < len(line):
|
||||
k = line.find('\\', j)
|
||||
|
||||
if k == -1:
|
||||
tmp += [line[j:]]
|
||||
new_block += [line[j:]]
|
||||
break
|
||||
|
||||
if k != j:
|
||||
tmp += [line[j: k]]
|
||||
#document.warning("j=%d\tk=%d\t#%s#%s#" % (j,k,line,line[j: k]))
|
||||
new_block += [line[j: k]]
|
||||
j = k
|
||||
|
||||
k = find_next_space(line, j+1)
|
||||
|
||||
# These tokens take the rest of the line
|
||||
token = line[j+1:k]
|
||||
# These tokens take the rest of the line
|
||||
if token in getline_tokens:
|
||||
tmp += [line[j:]]
|
||||
#document.warning("getline_token:%s\tj=%d\t\t#%s#%s#" % (token,j,line,line[j:]))
|
||||
new_block += [line[j:]]
|
||||
break
|
||||
|
||||
# These tokens take no arguments
|
||||
if token in noargs_tokens:
|
||||
tmp += [line[j:k]]
|
||||
new_block += [line[j:k]]
|
||||
j = k
|
||||
continue
|
||||
|
||||
# These tokens take one argument
|
||||
if token in onearg_tokens:
|
||||
k = find_next_space(line, k + 1)
|
||||
tmp += [line[j:k]]
|
||||
new_block += [line[j:k]]
|
||||
j = k
|
||||
continue
|
||||
|
||||
@ -104,29 +105,30 @@ def regularise_body(document):
|
||||
inset = line[k+1: l]
|
||||
|
||||
if inset == "Latex":
|
||||
tmp += [line[j:l]]
|
||||
new_block += [line[j:l]]
|
||||
j = l
|
||||
continue
|
||||
|
||||
if inset in ["LatexCommand", "LatexDel"]:
|
||||
tmp += [line[j:]]
|
||||
if inset in ["LatexCommand", "LatexDel", "Label", "Figure",
|
||||
"Formula"]:
|
||||
new_block += [line[j:]]
|
||||
break
|
||||
|
||||
if inset == "Quotes":
|
||||
l = find_next_space(line, l + 1)
|
||||
tmp += [line[j:l]]
|
||||
new_block += [line[j:l]]
|
||||
j = l
|
||||
continue
|
||||
|
||||
document.warning("unkown inset %s" % line)
|
||||
document.warning("unkown inset %s" % inset)
|
||||
assert(False)
|
||||
|
||||
# We are inside a latex inset, pass the text verbatim
|
||||
tmp += [line[j:]]
|
||||
new_block += [line[j:]]
|
||||
break
|
||||
|
||||
document.body[i: i+1] = tmp
|
||||
i += len(tmp)
|
||||
document.body[i: i+1] = new_block
|
||||
i += len(new_block)
|
||||
|
||||
|
||||
supported_versions = ["0.10.%d" % i for i in range(8)] + ["0.10"]
|
||||
|
@ -112,7 +112,7 @@ def update_inset_label(document):
|
||||
i = find_token(lines, '\\begin_inset Label', i)
|
||||
if i == -1:
|
||||
return
|
||||
lines[i] = '\\begin_inset LatexCommand \label{' + lines[i][19:] + '}'
|
||||
lines[i] = '\\begin_inset LatexCommand \\label{' + lines[i][19:] + '}'
|
||||
i = i + 1
|
||||
|
||||
|
||||
|
@ -69,7 +69,7 @@ def find_beginning_of_inset(lines, i):
|
||||
|
||||
|
||||
def find_end_of_inset(lines, i):
|
||||
" Finds the matching \end_inset"
|
||||
r" Finds the matching \end_inset"
|
||||
return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ def get_width(mo):
|
||||
|
||||
|
||||
def remove_oldfloat(document):
|
||||
" Change \begin_float .. \end_float into \begin_inset Float .. \end_inset"
|
||||
r" Change \begin_float .. \end_float into \begin_inset Float .. \end_inset"
|
||||
lines = document.body
|
||||
i = 0
|
||||
while True:
|
||||
@ -250,7 +250,7 @@ def remove_pextra(document):
|
||||
if flag:
|
||||
flag = 0
|
||||
if hfill:
|
||||
start = ["","\hfill",""]+start
|
||||
start = ["",r"\hfill",""]+start
|
||||
else:
|
||||
start = ['\\layout %s' % document.default_layout,''] + start
|
||||
|
||||
@ -324,7 +324,7 @@ def remove_oldert(document):
|
||||
new = []
|
||||
new2 = []
|
||||
if check_token(lines[i], "\\layout LaTeX"):
|
||||
new = ['\layout %s' % document.default_layout, "", ""]
|
||||
new = [r'\layout %s' % document.default_layout, "", ""]
|
||||
|
||||
k = i+1
|
||||
while True:
|
||||
@ -745,8 +745,8 @@ def update_longtables(document):
|
||||
for j in range(rows):
|
||||
i = find_token(body, '<row', i)
|
||||
|
||||
self.endfoot = false # footer row
|
||||
self.endlastfoot = false # last footer row
|
||||
row_info[i].endfoot = false # footer row
|
||||
row_info[i].endlastfoot = false # last footer row
|
||||
if row_info[j].endhead:
|
||||
insert_attribute(body, i, 'endhead="true"')
|
||||
|
||||
@ -808,7 +808,7 @@ def change_infoinset(document):
|
||||
note_lines = [txt]+note_lines
|
||||
|
||||
for line in note_lines:
|
||||
new = new + ['\layout %s' % document.default_layout, ""]
|
||||
new = new + [r'\layout %s' % document.default_layout, ""]
|
||||
tmp = line.split('\\')
|
||||
new = new + [tmp[0]]
|
||||
for x in tmp[1:]:
|
||||
|
@ -27,7 +27,7 @@ from parser_tools import find_token, find_end_of, get_value,\
|
||||
# Private helper functions
|
||||
|
||||
def find_end_of_inset(lines, i):
|
||||
"Finds the matching \end_inset"
|
||||
r"Finds the matching \end_inset"
|
||||
return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
|
||||
|
||||
|
||||
|
@ -81,7 +81,7 @@ def get_next_paragraph(lines, i, format):
|
||||
|
||||
|
||||
def find_end_of_inset(lines, i):
|
||||
"Finds the matching \end_inset"
|
||||
r"Finds the matching \end_inset"
|
||||
return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
|
||||
|
||||
def del_token(lines, token, start, end):
|
||||
@ -103,7 +103,7 @@ def del_token(lines, token, start, end):
|
||||
####################################################################
|
||||
|
||||
def remove_color_default(document):
|
||||
" Remove \color default"
|
||||
r" Remove \color default"
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, "\\color default", i)
|
||||
@ -114,12 +114,12 @@ def remove_color_default(document):
|
||||
|
||||
|
||||
def add_end_header(document):
|
||||
" Add \end_header"
|
||||
r" Add \end_header"
|
||||
document.header.append("\\end_header");
|
||||
|
||||
|
||||
def rm_end_header(document):
|
||||
" Remove \end_header"
|
||||
r" Remove \end_header"
|
||||
i = find_token(document.header, "\\end_header", 0)
|
||||
if i == -1:
|
||||
return
|
||||
@ -169,14 +169,14 @@ def revert_amsmath(document):
|
||||
|
||||
|
||||
def convert_spaces(document):
|
||||
" \SpecialChar ~ -> \InsetSpace ~"
|
||||
r" \SpecialChar ~ -> \InsetSpace ~"
|
||||
for i in range(len(document.body)):
|
||||
document.body[i] = document.body[i].replace("\\SpecialChar ~",
|
||||
"\\InsetSpace ~")
|
||||
|
||||
|
||||
def revert_spaces(document):
|
||||
" \InsetSpace ~ -> \SpecialChar ~"
|
||||
r" \InsetSpace ~ -> \SpecialChar ~"
|
||||
regexp = re.compile(r'(.*)(\\InsetSpace\s+)(\S+)')
|
||||
i = 0
|
||||
while True:
|
||||
@ -197,18 +197,18 @@ def revert_spaces(document):
|
||||
|
||||
|
||||
def rename_spaces(document):
|
||||
""" \InsetSpace \, -> \InsetSpace \thinspace{}
|
||||
\InsetSpace \space -> \InsetSpace \space{}"""
|
||||
""" \\InsetSpace \\, -> \\InsetSpace \thinspace{}
|
||||
\\InsetSpace \\space -> \\InsetSpace \\space{}"""
|
||||
for i in range(len(document.body)):
|
||||
document.body[i] = document.body[i].replace("\\InsetSpace \\space",
|
||||
"\\InsetSpace \\space{}")
|
||||
document.body[i] = document.body[i].replace("\\InsetSpace \,",
|
||||
document.body[i] = document.body[i].replace("\\InsetSpace \\,",
|
||||
"\\InsetSpace \\thinspace{}")
|
||||
|
||||
|
||||
def revert_space_names(document):
|
||||
""" \InsetSpace \thinspace{} -> \InsetSpace \,
|
||||
\InsetSpace \space{} -> \InsetSpace \space"""
|
||||
""" \\InsetSpace \thinspace{} -> \\InsetSpace \\,
|
||||
\\InsetSpace \\space{} -> \\InsetSpace \\space"""
|
||||
for i in range(len(document.body)):
|
||||
document.body[i] = document.body[i].replace("\\InsetSpace \\space{}",
|
||||
"\\InsetSpace \\space")
|
||||
@ -262,7 +262,7 @@ def revert_bibtex(document):
|
||||
|
||||
|
||||
def remove_insetparent(document):
|
||||
" Remove \lyxparent"
|
||||
r" Remove \lyxparent"
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, "\\begin_inset LatexCommand \\lyxparent", i)
|
||||
@ -428,7 +428,7 @@ def revert_comment(document):
|
||||
|
||||
|
||||
def add_end_layout(document):
|
||||
" Add \end_layout"
|
||||
r" Add \end_layout"
|
||||
i = find_token(document.body, '\\layout', 0)
|
||||
|
||||
if i == -1:
|
||||
@ -502,7 +502,7 @@ def add_end_layout(document):
|
||||
|
||||
|
||||
def rm_end_layout(document):
|
||||
" Remove \end_layout"
|
||||
r" Remove \end_layout"
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, '\\end_layout', i)
|
||||
@ -544,7 +544,7 @@ def rm_body_changes(document):
|
||||
|
||||
|
||||
def layout2begin_layout(document):
|
||||
" \layout -> \begin_layout "
|
||||
r" \layout -> \begin_layout "
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, '\\layout', i)
|
||||
@ -556,7 +556,7 @@ def layout2begin_layout(document):
|
||||
|
||||
|
||||
def begin_layout2layout(document):
|
||||
" \begin_layout -> \layout "
|
||||
r" \begin_layout -> \layout "
|
||||
i = 0
|
||||
while True:
|
||||
i = find_token(document.body, '\\begin_layout', i)
|
||||
@ -1051,7 +1051,7 @@ def convert_minipage(document):
|
||||
# convert the inner_position
|
||||
if document.body[i][:14] == "inner_position":
|
||||
innerpos = inner_pos[int(document.body[i][15])]
|
||||
del document.body[i]
|
||||
del document.body[i]
|
||||
else:
|
||||
innerpos = inner_pos[0]
|
||||
|
||||
@ -1972,9 +1972,9 @@ def convert_names(document):
|
||||
'\\begin_layout %s' % document.default_layout,
|
||||
"",
|
||||
"%s" % firstname,
|
||||
"\end_layout",
|
||||
r"\end_layout",
|
||||
"",
|
||||
"\end_inset",
|
||||
r"\end_inset",
|
||||
"",
|
||||
"",
|
||||
"\\begin_inset CharStyle Surname",
|
||||
@ -2229,7 +2229,7 @@ def use_x_binary(document):
|
||||
def normalize_paragraph_params(document):
|
||||
" Place all the paragraph parameters in their own line. "
|
||||
body = document.body
|
||||
|
||||
|
||||
allowed_parameters = '\\paragraph_spacing', '\\noindent', \
|
||||
'\\align', '\\labelwidthstring', "\\start_of_appendix", \
|
||||
"\\leftindent"
|
||||
|
@ -24,6 +24,7 @@ import unicodedata
|
||||
import sys, os
|
||||
|
||||
from parser_tools import find_re, find_token, find_token_backwards, find_token_exact, find_tokens, find_end_of, get_value, find_beginning_of, find_nonempty_line
|
||||
from lyx2lyx_tools import insert_document_option
|
||||
from LyX import get_encoding
|
||||
|
||||
# Provide support for both python 2 and 3
|
||||
@ -420,7 +421,7 @@ def revert_unicode_line(document, i, insets, spec_chars, replacement_character =
|
||||
else:
|
||||
if insets and insets[-1] == "Formula":
|
||||
# avoid putting an ERT in a math; instead put command as text
|
||||
command = command.replace('\\\\', '\mathrm{')
|
||||
command = command.replace('\\\\', r'\mathrm{')
|
||||
command = command + '}'
|
||||
elif not insets or insets[-1] != "ERT":
|
||||
# add an ERT inset with the replacement character
|
||||
@ -490,7 +491,7 @@ def revert_cs_label(document):
|
||||
|
||||
|
||||
def convert_bibitem(document):
|
||||
""" Convert
|
||||
r""" Convert
|
||||
\bibitem [option]{argument}
|
||||
|
||||
to
|
||||
@ -575,16 +576,16 @@ commandparams_info = {
|
||||
def convert_commandparams(document):
|
||||
""" Convert
|
||||
|
||||
\begin_inset LatexCommand \cmdname[opt1][opt2]{arg}
|
||||
\end_inset
|
||||
\\begin_inset LatexCommand \\cmdname[opt1][opt2]{arg}
|
||||
\\end_inset
|
||||
|
||||
to
|
||||
|
||||
\begin_inset LatexCommand cmdname
|
||||
\\begin_inset LatexCommand cmdname
|
||||
name1 "opt1"
|
||||
name2 "opt2"
|
||||
name3 "arg"
|
||||
\end_inset
|
||||
\\end_inset
|
||||
|
||||
name1, name2 and name3 can be different for each command.
|
||||
"""
|
||||
@ -895,7 +896,7 @@ def revert_cleardoublepage(document):
|
||||
|
||||
|
||||
def convert_lyxline(document):
|
||||
" remove fontsize commands for \lyxline "
|
||||
r" remove fontsize commands for \lyxline "
|
||||
# The problematic is: The old \lyxline definition doesn't handle the fontsize
|
||||
# to change the line thickness. The new definiton does this so that imported
|
||||
# \lyxlines would have a different line thickness. The eventual fontsize command
|
||||
@ -1686,7 +1687,7 @@ def revert_CJK(document):
|
||||
|
||||
|
||||
def revert_preamble_listings_params(document):
|
||||
" Revert preamble option \listings_params "
|
||||
r" Revert preamble option \listings_params "
|
||||
i = find_token(document.header, "\\listings_params", 0)
|
||||
if i != -1:
|
||||
document.preamble.append('\\usepackage{listings}')
|
||||
@ -1907,13 +1908,7 @@ def revert_ext_font_sizes(document):
|
||||
|
||||
i = find_token(document.header, '\\paperfontsize', 0)
|
||||
document.header[i] = '\\paperfontsize default'
|
||||
|
||||
i = find_token(document.header, '\\options', 0)
|
||||
if i == -1:
|
||||
i = find_token(document.header, '\\textclass', 0) + 1
|
||||
document.header[i:i] = ['\\options %s' % fontsize]
|
||||
else:
|
||||
document.header[i] += ',%s' % fontsize
|
||||
insert_document_option(document, fontsize)
|
||||
|
||||
|
||||
def convert_ext_font_sizes(document):
|
||||
@ -2010,10 +2005,10 @@ def convert_arabic (document):
|
||||
document.header[i] = "\\language arabic_arabtex"
|
||||
i = 0
|
||||
while i < len(document.body):
|
||||
h = document.body[i].find("\lang arabic", 0, len(document.body[i]))
|
||||
h = document.body[i].find(r"\lang arabic", 0, len(document.body[i]))
|
||||
if (h != -1):
|
||||
# change the language name
|
||||
document.body[i] = '\lang arabic_arabtex'
|
||||
document.body[i] = r'\lang arabic_arabtex'
|
||||
i = i + 1
|
||||
|
||||
|
||||
@ -2025,10 +2020,10 @@ def revert_arabic (document):
|
||||
document.header[i] = "\\language arabic"
|
||||
i = 0
|
||||
while i < len(document.body):
|
||||
h = document.body[i].find("\lang arabic_arabtex", 0, len(document.body[i]))
|
||||
h = document.body[i].find(r"\lang arabic_arabtex", 0, len(document.body[i]))
|
||||
if (h != -1):
|
||||
# change the language name
|
||||
document.body[i] = '\lang arabic'
|
||||
document.body[i] = r'\lang arabic'
|
||||
i = i + 1
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ import unicodedata
|
||||
import sys, os
|
||||
|
||||
from parser_tools import find_token, find_end_of, find_tokens, get_value
|
||||
from unicode_symbols import read_unicodesymbols
|
||||
from unicode_symbols import unicode_reps
|
||||
|
||||
####################################################################
|
||||
# Private helper functions
|
||||
@ -146,61 +146,13 @@ def set_option(document, m, option, value):
|
||||
return l
|
||||
|
||||
|
||||
# FIXME: Remove this function if the version imported from unicode_symbols works.
|
||||
# This function was the predecessor from that function, that in the meanwhile got
|
||||
# new fixes.
|
||||
def read_unicodesymbols2():
|
||||
" Read the unicodesymbols list of unicode characters and corresponding commands."
|
||||
|
||||
# Provide support for both python 2 and 3
|
||||
PY2 = sys.version_info[0] == 2
|
||||
if not PY2:
|
||||
unichr = chr
|
||||
# End of code to support for both python 2 and 3
|
||||
|
||||
pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
|
||||
spec_chars = []
|
||||
# Two backslashes, followed by some non-word character, and then a character
|
||||
# in brackets. The idea is to check for constructs like: \"{u}, which is how
|
||||
# they are written in the unicodesymbols file; but they can also be written
|
||||
# as: \"u or even \" u.
|
||||
r = re.compile(r'\\\\(\W)\{(\w)\}')
|
||||
for line in fp.readlines():
|
||||
if line[0] != '#' and line.strip() != "":
|
||||
line=line.replace(' "',' ') # remove all quotation marks with spaces before
|
||||
line=line.replace('" ',' ') # remove all quotation marks with spaces after
|
||||
line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
|
||||
try:
|
||||
[ucs4,command,dead] = line.split(None,2)
|
||||
if command[0:1] != "\\":
|
||||
continue
|
||||
spec_chars.append([command, unichr(eval(ucs4))])
|
||||
except:
|
||||
continue
|
||||
m = r.match(command)
|
||||
if m != None:
|
||||
command = "\\\\"
|
||||
# If the character is a double-quote, then we need to escape it, too,
|
||||
# since it is done that way in the LyX file.
|
||||
if m.group(1) == "\"":
|
||||
command += "\\"
|
||||
commandbl = command
|
||||
command += m.group(1) + m.group(2)
|
||||
commandbl += m.group(1) + ' ' + m.group(2)
|
||||
spec_chars.append([command, unichr(eval(ucs4))])
|
||||
spec_chars.append([commandbl, unichr(eval(ucs4))])
|
||||
fp.close()
|
||||
return spec_chars
|
||||
|
||||
|
||||
def extract_argument(line):
|
||||
'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
|
||||
|
||||
if not line:
|
||||
return (None, "")
|
||||
|
||||
bracere = re.compile("(\s*)(.*)")
|
||||
bracere = re.compile(r"(\s*)(.*)")
|
||||
n = bracere.match(line)
|
||||
whitespace = n.group(1)
|
||||
stuff = n.group(2)
|
||||
@ -280,8 +232,6 @@ def latex2ert(line, isindex):
|
||||
return retval
|
||||
|
||||
|
||||
unicode_reps = read_unicodesymbols()
|
||||
|
||||
#Bug 5022....
|
||||
#Might should do latex2ert first, then deal with stuff that DOESN'T
|
||||
#end up inside ERT. That routine could be modified so that it returned
|
||||
@ -327,7 +277,7 @@ def latex2lyx(data, isindex):
|
||||
data = data.replace('\\\\', '\\')
|
||||
|
||||
# Math:
|
||||
mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
|
||||
mathre = re.compile(r'^(.*?)(\$.*?\$)(.*)')
|
||||
lines = data.split('\n')
|
||||
for line in lines:
|
||||
#document.warning("LINE: " + line)
|
||||
@ -996,7 +946,7 @@ def remove_inzip_options(document):
|
||||
|
||||
|
||||
def convert_inset_command(document):
|
||||
"""
|
||||
r"""
|
||||
Convert:
|
||||
\begin_inset LatexCommand cmd
|
||||
to
|
||||
@ -1033,7 +983,7 @@ def convert_inset_command(document):
|
||||
|
||||
|
||||
def revert_inset_command(document):
|
||||
"""
|
||||
r"""
|
||||
Convert:
|
||||
\begin_inset CommandInset InsetType
|
||||
LatexCommand cmd
|
||||
@ -1608,7 +1558,7 @@ def convert_usorbian(document):
|
||||
|
||||
|
||||
def convert_macro_global(document):
|
||||
"Remove TeX code command \global when it is in front of a macro"
|
||||
r"Remove TeX code command \global when it is in front of a macro"
|
||||
# math macros are nowadays already defined \global, so that an additional
|
||||
# \global would make the document uncompilable, see
|
||||
# http://www.lyx.org/trac/ticket/5371
|
||||
@ -2389,7 +2339,7 @@ def revert_wrapplacement(document):
|
||||
|
||||
|
||||
def remove_extra_embedded_files(document):
|
||||
" Remove \extra_embedded_files from buffer params "
|
||||
r" Remove \extra_embedded_files from buffer params "
|
||||
i = find_token(document.header, '\\extra_embedded_files', 0)
|
||||
if i == -1:
|
||||
return
|
||||
|
@ -22,14 +22,15 @@ import re, string
|
||||
import unicodedata
|
||||
import sys, os
|
||||
|
||||
from parser_tools import find_token, find_end_of, find_tokens, \
|
||||
from parser_tools import del_complete_lines, \
|
||||
find_token, find_end_of, find_tokens, \
|
||||
find_token_exact, find_end_of_inset, find_end_of_layout, \
|
||||
find_token_backwards, is_in_inset, get_value, get_quoted_value, \
|
||||
del_token, check_token, get_option_value
|
||||
|
||||
from lyx2lyx_tools import add_to_preamble, insert_to_preamble, \
|
||||
put_cmd_in_ert, lyx2latex, latex_length, revert_flex_inset, \
|
||||
revert_font_attrs, hex2ratio, str2bool
|
||||
revert_font_attrs, hex2ratio, str2bool, revert_language
|
||||
|
||||
####################################################################
|
||||
# Private helper functions
|
||||
@ -377,7 +378,7 @@ def revert_splitindex(document):
|
||||
l = re.compile(r'\\begin_inset Index (.*)$')
|
||||
m = l.match(line)
|
||||
itype = m.group(1)
|
||||
if itype == "idx" or indices == "false":
|
||||
if itype == "idx" or useindices == "false":
|
||||
document.body[i] = "\\begin_inset Index"
|
||||
else:
|
||||
k = find_end_of_inset(document.body, i)
|
||||
@ -484,6 +485,15 @@ def revert_printindexall(document):
|
||||
document.body[i:k + 1] = subst
|
||||
i = i + 1
|
||||
|
||||
strikeout_preamble = ['% for proper underlining',
|
||||
r'\PassOptionsToPackage{normalem}{ulem}',
|
||||
r'\usepackage{ulem}']
|
||||
|
||||
def convert_strikeout(document):
|
||||
" Remove preamble code loading 'ulem' package. "
|
||||
del_complete_lines(document.preamble,
|
||||
['% Added by lyx2lyx']+strikeout_preamble)
|
||||
|
||||
|
||||
def revert_strikeout(document):
|
||||
" Reverts \\strikeout font attribute "
|
||||
@ -491,25 +501,30 @@ def revert_strikeout(document):
|
||||
changed = revert_font_attrs(document.body, "\\uwave", "\\uwave") or changed
|
||||
changed = revert_font_attrs(document.body, "\\strikeout", "\\sout") or changed
|
||||
if changed == True:
|
||||
insert_to_preamble(document, \
|
||||
['% for proper underlining',
|
||||
'\\PassOptionsToPackage{normalem}{ulem}',
|
||||
'\\usepackage{ulem}'])
|
||||
insert_to_preamble(document, strikeout_preamble)
|
||||
|
||||
|
||||
ulinelatex_preamble = ['% fix underbar in citations',
|
||||
r'\let\cite@rig\cite',
|
||||
r'\newcommand{\b@xcite}[2][\%]{\def\def@pt{\%}\def\pas@pt{#1}',
|
||||
r' \mbox{\ifx\def@pt\pas@pt\cite@rig{#2}\else\cite@rig[#1]{#2}\fi}}',
|
||||
r'\renewcommand{\underbar}[1]{{\let\cite\b@xcite\uline{#1}}}']
|
||||
|
||||
def convert_ulinelatex(document):
|
||||
" Remove preamble code for \\uline font attribute. "
|
||||
del_complete_lines(document.preamble,
|
||||
['% Added by lyx2lyx']+ulinelatex_preamble)
|
||||
|
||||
def revert_ulinelatex(document):
|
||||
" Reverts \\uline font attribute "
|
||||
" Add preamble code for \\uline font attribute in citations. "
|
||||
i = find_token(document.body, '\\bar under', 0)
|
||||
if i == -1:
|
||||
return
|
||||
insert_to_preamble(document,\
|
||||
['% for proper underlining',
|
||||
'\\PassOptionsToPackage{normalem}{ulem}',
|
||||
'\\usepackage{ulem}',
|
||||
'\\let\\cite@rig\\cite',
|
||||
'\\newcommand{\\b@xcite}[2][\\%]{\\def\\def@pt{\\%}\\def\\pas@pt{#1}',
|
||||
' \\mbox{\\ifx\\def@pt\\pas@pt\\cite@rig{#2}\\else\\cite@rig[#1]{#2}\\fi}}',
|
||||
'\\renewcommand{\\underbar}[1]{{\\let\\cite\\b@xcite\\uline{#1}}}'])
|
||||
try:
|
||||
document.preamble.index(r'\usepackage{ulem}')
|
||||
except ValueError:
|
||||
insert_to_preamble(document, strikeout_preamble)
|
||||
insert_to_preamble(document, ulinelatex_preamble)
|
||||
|
||||
|
||||
def revert_custom_processors(document):
|
||||
@ -818,6 +833,9 @@ def revert_suppress_date(document):
|
||||
del document.header[i]
|
||||
|
||||
|
||||
mhchem_preamble = [r"\PassOptionsToPackage{version=3}{mhchem}",
|
||||
r"\usepackage{mhchem}"]
|
||||
|
||||
def convert_mhchem(document):
|
||||
"Set mhchem to off for versions older than 1.6.x"
|
||||
if document.initial_format < 277:
|
||||
@ -835,47 +853,44 @@ def convert_mhchem(document):
|
||||
# pre-1.5.x document
|
||||
i = find_token(document.header, "\\use_amsmath", 0)
|
||||
if i == -1:
|
||||
document.warning("Malformed LyX document: Could not find amsmath os esint setting.")
|
||||
document.warning("Malformed LyX document: "
|
||||
"Could not find amsmath or esint setting.")
|
||||
return
|
||||
document.header.insert(i + 1, "\\use_mhchem %d" % mhchem)
|
||||
# remove LyX-inserted preamble
|
||||
if mhchem != 0:
|
||||
del_complete_lines(document.preamble,
|
||||
['% Added by lyx2lyx']+mhchem_preamble)
|
||||
|
||||
|
||||
def revert_mhchem(document):
|
||||
"Revert mhchem loading to preamble code"
|
||||
"Revert mhchem loading to preamble code."
|
||||
|
||||
mhchem = "off"
|
||||
i = find_token(document.header, "\\use_mhchem", 0)
|
||||
if i == -1:
|
||||
document.warning("Malformed LyX document: Could not find mhchem setting.")
|
||||
mhchem = "auto"
|
||||
else:
|
||||
val = get_value(document.header, "\\use_mhchem", i)
|
||||
if val == "1":
|
||||
mhchem = "auto"
|
||||
elif val == "2":
|
||||
mhchem = "on"
|
||||
del document.header[i]
|
||||
mhchem = get_value(document.header, "\\use_mhchem", delete=True)
|
||||
try:
|
||||
mhchem = int(mhchem)
|
||||
except ValueError:
|
||||
document.warning("Malformed LyX document: "
|
||||
"Could not find mhchem setting.")
|
||||
mhchem = 1 # "auto"
|
||||
# mhchem in {0: "off", 1: "auto", 2: "on"}
|
||||
|
||||
if mhchem == "off":
|
||||
# don't load case
|
||||
return
|
||||
|
||||
if mhchem == "auto":
|
||||
if mhchem == 1: # "auto"
|
||||
i = 0
|
||||
while True:
|
||||
while i != 1 and mhchem == 1:
|
||||
i = find_token(document.body, "\\begin_inset Formula", i)
|
||||
if i == -1:
|
||||
break
|
||||
line = document.body[i]
|
||||
if line.find("\\ce{") != -1 or line.find("\\cf{") != -1:
|
||||
mhchem = "on"
|
||||
break
|
||||
j = find_end_of_inset(document.body, i)
|
||||
if j == -1:
|
||||
break
|
||||
if (True for line in document.body[i:j]
|
||||
if r"\ce{" in line or r"\cf{" in line):
|
||||
mhchem = 2
|
||||
break
|
||||
i += 1
|
||||
|
||||
if mhchem == "on":
|
||||
pre = ["\\PassOptionsToPackage{version=3}{mhchem}",
|
||||
"\\usepackage{mhchem}"]
|
||||
insert_to_preamble(document, pre)
|
||||
if (mhchem == 2 # on
|
||||
and find_token(document.preamble, r"\usepackage{mhchem}") == -1):
|
||||
insert_to_preamble(document, mhchem_preamble)
|
||||
|
||||
|
||||
def revert_fontenc(document):
|
||||
@ -956,6 +971,20 @@ def revert_includeonly(document):
|
||||
document.header[i : j + 1] = []
|
||||
|
||||
|
||||
def convert_includeall(document):
|
||||
" Add maintain_unincluded_children param "
|
||||
|
||||
i = 0
|
||||
i = find_token(document.header, "\\maintain_unincluded_children", 0)
|
||||
if i == -1:
|
||||
i = find_token(document.header, "\\textclass", 0)
|
||||
if i == -1:
|
||||
document.warning("Malformed LyX document! Missing \\textclass header.")
|
||||
return
|
||||
document.header.insert(i, "\\maintain_unincluded_children false")
|
||||
return
|
||||
|
||||
|
||||
def revert_includeall(document):
|
||||
" Remove maintain_unincluded_children param "
|
||||
del_token(document.header, '\\maintain_unincluded_children', 0)
|
||||
@ -1090,7 +1119,7 @@ def revert_multirow(document):
|
||||
|
||||
|
||||
def convert_math_output(document):
|
||||
" Convert \html_use_mathml to \html_math_output "
|
||||
r" Convert \html_use_mathml to \html_math_output "
|
||||
i = find_token(document.header, "\\html_use_mathml", 0)
|
||||
if i == -1:
|
||||
return
|
||||
@ -1107,7 +1136,7 @@ def convert_math_output(document):
|
||||
|
||||
|
||||
def revert_math_output(document):
|
||||
" Revert \html_math_output to \html_use_mathml "
|
||||
r" Revert \html_math_output to \html_use_mathml "
|
||||
i = find_token(document.header, "\\html_math_output", 0)
|
||||
if i == -1:
|
||||
return
|
||||
@ -1266,19 +1295,7 @@ def revert_notefontcolor(document):
|
||||
def revert_turkmen(document):
|
||||
"Set language Turkmen to English"
|
||||
|
||||
if document.language == "turkmen":
|
||||
document.language = "english"
|
||||
i = find_token(document.header, "\\language", 0)
|
||||
if i != -1:
|
||||
document.header[i] = "\\language english"
|
||||
|
||||
j = 0
|
||||
while True:
|
||||
j = find_token(document.body, "\\lang turkmen", j)
|
||||
if j == -1:
|
||||
return
|
||||
document.body[j] = document.body[j].replace("\\lang turkmen", "\\lang english")
|
||||
j += 1
|
||||
revert_language(document, "turkmen", "turkmen", "turkmen")
|
||||
|
||||
|
||||
def revert_fontcolor(document):
|
||||
@ -1602,8 +1619,8 @@ def revert_IEEEtran(document):
|
||||
|
||||
def convert_prettyref(document):
|
||||
" Converts prettyref references to neutral formatted refs "
|
||||
re_ref = re.compile("^\s*reference\s+\"(\w+):(\S+)\"")
|
||||
nm_ref = re.compile("^\s*name\s+\"(\w+):(\S+)\"")
|
||||
re_ref = re.compile("^\\s*reference\\s+\"(\\w+):(\\S+)\"")
|
||||
nm_ref = re.compile("^\\s*name\\s+\"(\\w+):(\\S+)\"")
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
@ -1624,8 +1641,8 @@ def convert_prettyref(document):
|
||||
|
||||
def revert_refstyle(document):
|
||||
" Reverts neutral formatted refs to prettyref "
|
||||
re_ref = re.compile("^reference\s+\"(\w+):(\S+)\"")
|
||||
nm_ref = re.compile("^\s*name\s+\"(\w+):(\S+)\"")
|
||||
re_ref = re.compile("^reference\\s+\"(\\w+):(\\S+)\"")
|
||||
nm_ref = re.compile("^\\s*name\\s+\"(\\w+):(\\S+)\"")
|
||||
|
||||
i = 0
|
||||
while True:
|
||||
@ -1664,12 +1681,10 @@ def revert_nameref(document):
|
||||
i += 1
|
||||
# Make sure it is actually in an inset!
|
||||
# A normal line could begin with "LatexCommand nameref"!
|
||||
val = is_in_inset(document.body, cmdloc, \
|
||||
"\\begin_inset CommandInset ref")
|
||||
if not val:
|
||||
stins, endins = is_in_inset(document.body, cmdloc,
|
||||
"\\begin_inset CommandInset ref")
|
||||
if endins == -1:
|
||||
continue
|
||||
stins, endins = val
|
||||
|
||||
# ok, so it is in an InsetRef
|
||||
refline = find_token(document.body, "reference", stins, endins)
|
||||
if refline == -1:
|
||||
@ -1699,17 +1714,16 @@ def remove_Nameref(document):
|
||||
break
|
||||
cmdloc = i
|
||||
i += 1
|
||||
|
||||
# Make sure it is actually in an inset!
|
||||
val = is_in_inset(document.body, cmdloc, \
|
||||
"\\begin_inset CommandInset ref")
|
||||
val = is_in_inset(document.body, cmdloc,
|
||||
"\\begin_inset CommandInset ref", default=False)
|
||||
if not val:
|
||||
continue
|
||||
document.body[cmdloc] = "LatexCommand nameref"
|
||||
|
||||
|
||||
def revert_mathrsfs(document):
|
||||
" Load mathrsfs if \mathrsfs us use in the document "
|
||||
r" Load mathrsfs if \mathrsfs us use in the document "
|
||||
i = 0
|
||||
for line in document.body:
|
||||
if line.find("\\mathscr{") != -1:
|
||||
@ -2145,7 +2159,7 @@ def convert_passthru(document):
|
||||
if not check_passthru:
|
||||
return
|
||||
|
||||
rx = re.compile("\\\\begin_layout \s*(\w+)")
|
||||
rx = re.compile("\\\\begin_layout \\s*(\\w+)")
|
||||
beg = 0
|
||||
for lay in ["Chunk", "Scrap"]:
|
||||
while True:
|
||||
@ -2175,7 +2189,7 @@ def convert_passthru(document):
|
||||
break
|
||||
ne = find_end_of_inset(document.body, ns)
|
||||
if ne == -1 or ne > end:
|
||||
document.warning("Can't find end of inset at line " + str(nb))
|
||||
document.warning("Can't find end of inset at line " + str(ne))
|
||||
ns += 1
|
||||
continue
|
||||
if document.body[ne + 1] == "":
|
||||
@ -2209,7 +2223,7 @@ def revert_passthru(document):
|
||||
" http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg161298.html "
|
||||
if not check_passthru:
|
||||
return
|
||||
rx = re.compile("\\\\begin_layout \s*(\w+)")
|
||||
rx = re.compile("\\\\begin_layout \\s*(\\w+)")
|
||||
beg = 0
|
||||
for lay in ["Chunk", "Scrap"]:
|
||||
while True:
|
||||
@ -2501,7 +2515,7 @@ def revert_langpack(document):
|
||||
|
||||
def convert_langpack(document):
|
||||
" Add \\language_package parameter "
|
||||
i = find_token(document.header, "\language" , 0)
|
||||
i = find_token(document.header, r"\language" , 0)
|
||||
if i == -1:
|
||||
document.warning("Malformed document. No \\language defined!")
|
||||
return
|
||||
@ -2548,9 +2562,9 @@ convert = [[346, []],
|
||||
[352, [convert_splitindex]],
|
||||
[353, []],
|
||||
[354, []],
|
||||
[355, []],
|
||||
[355, [convert_strikeout]],
|
||||
[356, []],
|
||||
[357, []],
|
||||
[357, [convert_ulinelatex]],
|
||||
[358, []],
|
||||
[359, [convert_nomencl_width]],
|
||||
[360, []],
|
||||
@ -2569,7 +2583,7 @@ convert = [[346, []],
|
||||
[373, [merge_gbrief]],
|
||||
[374, []],
|
||||
[375, []],
|
||||
[376, []],
|
||||
[376, [convert_includeall]],
|
||||
[377, []],
|
||||
[378, []],
|
||||
[379, [convert_math_output]],
|
||||
|
@ -24,7 +24,8 @@ import sys, os
|
||||
|
||||
# Uncomment only what you need to import, please.
|
||||
|
||||
from parser_tools import count_pars_in_inset, del_token, find_token, find_token_exact, \
|
||||
from parser_tools import count_pars_in_inset, del_complete_lines, del_token, \
|
||||
find_token, find_token_exact, \
|
||||
find_token_backwards, find_end_of, find_end_of_inset, find_end_of_layout, \
|
||||
find_end_of_sequence, find_re, get_option_value, get_containing_layout, \
|
||||
get_containing_inset, get_value, get_quoted_value, set_option_value
|
||||
@ -33,7 +34,7 @@ from parser_tools import count_pars_in_inset, del_token, find_token, find_token_
|
||||
#find_end_of_inset, find_end_of_layout, \
|
||||
#is_in_inset, del_token, check_token
|
||||
|
||||
from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert
|
||||
from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert, revert_language
|
||||
|
||||
#from lyx2lyx_tools import insert_to_preamble, \
|
||||
# lyx2latex, latex_length, revert_flex_inset, \
|
||||
@ -58,7 +59,7 @@ def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment,
|
||||
usage:
|
||||
revert_Argument_to_TeX_brace(document, LineOfBegin, LineOfEnd, StartArgument, EndArgument, isEnvironment, isOpt)
|
||||
LineOfBegin is the line of the \\begin_layout or \\begin_inset statement
|
||||
LineOfEnd is the line of the \end_layout or \end_inset statement, if "0" is given, the end of the file is used instead
|
||||
LineOfEnd is the line of the \\end_layout or \\end_inset statement, if "0" is given, the end of the file is used instead
|
||||
StartArgument is the number of the first argument that needs to be converted
|
||||
EndArgument is the number of the last argument that needs to be converted or the last defined one
|
||||
isEnvironment must be true, if the layout is for a LaTeX environment
|
||||
@ -352,7 +353,7 @@ def revert_undertilde(document):
|
||||
|
||||
|
||||
def revert_negative_space(document):
|
||||
"Revert InsetSpace negmedspace and negthickspace into its TeX-code counterpart"
|
||||
"Revert InsetSpace negmedspace and negthickspace into their TeX-code counterparts"
|
||||
i = 0
|
||||
j = 0
|
||||
reverted = False
|
||||
@ -365,7 +366,7 @@ def revert_negative_space(document):
|
||||
if reverted == True:
|
||||
i = find_token(document.header, "\\use_amsmath 2", 0)
|
||||
if i == -1:
|
||||
add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}"])
|
||||
add_to_preamble(document, ["\\@ifundefined{negthickspace}{\\usepackage{amsmath}}{}"])
|
||||
return
|
||||
if i == -1:
|
||||
return
|
||||
@ -555,8 +556,6 @@ def handle_longtable_captions(document, forward):
|
||||
get_option_value(document.body[begin_row], 'endlastfoot') != 'true'):
|
||||
document.body[begin_row] = set_option_value(document.body[begin_row], 'caption', 'true", endfirsthead="true')
|
||||
elif get_option_value(document.body[begin_row], 'caption') == 'true':
|
||||
if get_option_value(document.body[begin_row], 'endfirsthead') == 'true':
|
||||
document.body[begin_row] = set_option_value(document.body[begin_row], 'endfirsthead', 'false')
|
||||
if get_option_value(document.body[begin_row], 'endhead') == 'true':
|
||||
document.body[begin_row] = set_option_value(document.body[begin_row], 'endhead', 'false')
|
||||
if get_option_value(document.body[begin_row], 'endfoot') == 'true':
|
||||
@ -618,15 +617,16 @@ def convert_use_package(document, pkg, commands, oldauto):
|
||||
# oldauto defines how the version we are converting from behaves:
|
||||
# if it is true, the old version uses the package automatically.
|
||||
# if it is false, the old version never uses the package.
|
||||
i = find_token(document.header, "\\use_package", 0)
|
||||
i = find_token(document.header, "\\use_package")
|
||||
if i == -1:
|
||||
document.warning("Malformed LyX document: Can't find \\use_package.")
|
||||
return;
|
||||
j = find_token(document.preamble, "\\usepackage{" + pkg + "}", 0)
|
||||
if j != -1:
|
||||
# package was loaded in the preamble, convert this to header setting for round trip
|
||||
packageline = "\\usepackage{%s}" % pkg
|
||||
if (del_complete_lines(document.preamble,
|
||||
['% Added by lyx2lyx', packageline]) or
|
||||
del_complete_lines(document.preamble, [packageline])):
|
||||
# package was loaded in the preamble, convert this to header setting
|
||||
document.header.insert(i + 1, "\\use_package " + pkg + " 2") # on
|
||||
del document.preamble[j]
|
||||
# If oldauto is true we have two options:
|
||||
# We can either set the package to auto - this is correct for files in
|
||||
# format 425 to 463, and may create a conflict for older files which use
|
||||
@ -1060,7 +1060,7 @@ def convert_table_rotation(document):
|
||||
|
||||
|
||||
def convert_listoflistings(document):
|
||||
'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
|
||||
r'Convert ERT \lstlistoflistings to TOC lstlistoflistings inset'
|
||||
# We can support roundtrip because the command is so simple
|
||||
i = 0
|
||||
while True:
|
||||
@ -1169,24 +1169,16 @@ def revert_ancientgreek(document):
|
||||
def revert_languages(document):
|
||||
"Set the document language for new supported languages to English"
|
||||
|
||||
languages = [
|
||||
"coptic", "divehi", "hindi", "kurmanji", "lao", "marathi", "occitan", "sanskrit",
|
||||
"syriac", "tamil", "telugu", "urdu"
|
||||
]
|
||||
for n in range(len(languages)):
|
||||
if document.language == languages[n]:
|
||||
document.language = "english"
|
||||
i = find_token(document.header, "\\language", 0)
|
||||
if i != -1:
|
||||
document.header[i] = "\\language english"
|
||||
j = 0
|
||||
while j < len(document.body):
|
||||
j = find_token(document.body, "\\lang " + languages[n], j)
|
||||
if j != -1:
|
||||
document.body[j] = document.body[j].replace("\\lang " + languages[n], "\\lang english")
|
||||
j += 1
|
||||
else:
|
||||
j = len(document.body)
|
||||
# polyglossia-only
|
||||
polyglossia_languages = ["coptic", "divehi", "hindi", "lao", "marathi",
|
||||
"occitan", "sanskrit", "syriac", "tamil",
|
||||
"telugu", "urdu"]
|
||||
# babel-only
|
||||
babel_languages = ["kurmanji"]
|
||||
for lang in polyglossia_languages:
|
||||
revert_language(document, lang, "", lang)
|
||||
for lang in babel_languages:
|
||||
revert_language(document, lang, lang, "")
|
||||
|
||||
|
||||
def convert_armenian(document):
|
||||
@ -1555,10 +1547,11 @@ def convert_latexargs(document):
|
||||
"theorems-chap-bytype", "theorems-chap", "theorems-named", "theorems-sec-bytype",
|
||||
"theorems-sec", "theorems-starred", "theorems-std", "todonotes"]
|
||||
# Modules we need to take care of
|
||||
caveat_modules = ["initials"]
|
||||
caveat_modules = ["initials"] # TODO: , "graphicboxes", "bicaption"]
|
||||
# information about the relevant styles in caveat_modules (number of opt and req args)
|
||||
# use this if we get more caveat_modules. For now, use hard coding (see below).
|
||||
# initials = [{'Layout' : 'Initial', 'opt' : 1, 'req' : 1}]
|
||||
# graphicboxes = { ... }
|
||||
|
||||
# Is this a known safe layout?
|
||||
safe_layout = document.textclass in safe_layouts
|
||||
@ -4560,19 +4553,7 @@ def revert_aa2(document):
|
||||
def revert_tibetan(document):
|
||||
"Set the document language for Tibetan to English"
|
||||
|
||||
if document.language == "tibetan":
|
||||
document.language = "english"
|
||||
i = find_token(document.header, "\\language", 0)
|
||||
if i != -1:
|
||||
document.header[i] = "\\language english"
|
||||
j = 0
|
||||
while j < len(document.body):
|
||||
j = find_token(document.body, "\\lang tibetan", j)
|
||||
if j != -1:
|
||||
document.body[j] = document.body[j].replace("\\lang tibetan", "\\lang english")
|
||||
j += 1
|
||||
else:
|
||||
j = len(document.body)
|
||||
revert_language(document, "tibetan", "", "tibetan")
|
||||
|
||||
|
||||
#############
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5848
lib/lyx2lyx/lyx_2_4.py
Normal file
5848
lib/lyx2lyx/lyx_2_4.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
# This file is part of lyx2lyx
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2002-2011 Dekel Tsur <dekel@lyx.org>,
|
||||
# José Matos <jamatos@lyx.org>, Richard Heck <rgheck@comcast.net>
|
||||
# Copyright (C) 2002-2011 Dekel Tsur <dekel@lyx.org>,
|
||||
# José Matos <jamatos@lyx.org>, Richard Kimberly Heck <rikiheck@lyx.org>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@ -18,53 +18,57 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
'''
|
||||
"""
|
||||
This module offers several free functions to help parse lines.
|
||||
More documentaton is below, but here is a quick guide to what
|
||||
More documentaton is below, but here is a quick guide to what
|
||||
they do. Optional arguments are marked by brackets.
|
||||
|
||||
find_token(lines, token, start[, end[, ignorews]]):
|
||||
find_token(lines, token[, start[, end[, ignorews]]]):
|
||||
Returns the first line i, start <= i < end, on which
|
||||
token is found at the beginning. Returns -1 if not
|
||||
found.
|
||||
token is found at the beginning. Returns -1 if not
|
||||
found.
|
||||
If ignorews is (given and) True, then differences
|
||||
in whitespace do not count, except that there must be no
|
||||
in whitespace do not count, except that there must be no
|
||||
extra whitespace following token itself.
|
||||
|
||||
find_token_exact(lines, token, start[, end]):
|
||||
find_token_exact(lines, token[, start[, end]]]):
|
||||
As find_token, but with ignorews set to True.
|
||||
|
||||
find_tokens(lines, tokens, start[, end[, ignorews]]):
|
||||
find_tokens(lines, tokens[, start[, end[, ignorews]]]):
|
||||
Returns the first line i, start <= i < end, on which
|
||||
one of the tokens in tokens is found at the beginning.
|
||||
Returns -1 if not found.
|
||||
one of the tokens in tokens is found at the beginning.
|
||||
Returns -1 if not found.
|
||||
If ignorews is (given and) True, then differences
|
||||
in whitespace do not count, except that there must be no
|
||||
in whitespace do not count, except that there must be no
|
||||
extra whitespace following token itself.
|
||||
|
||||
find_tokens_exact(lines, token, start[, end]):
|
||||
find_tokens_exact(lines, token[, start[, end]]):
|
||||
As find_tokens, but with ignorews True.
|
||||
|
||||
|
||||
find_token_backwards(lines, token, start):
|
||||
find_tokens_backwards(lines, tokens, start):
|
||||
As before, but look backwards.
|
||||
|
||||
find_substring(lines, sub[, start[, end]]) -> int
|
||||
As find_token, but sub may be anywhere in the line.
|
||||
|
||||
find_re(lines, rexp, start[, end]):
|
||||
As find_token, but rexp is a regular expression object,
|
||||
so it has to be passed as e.g.: re.compile(r'...').
|
||||
|
||||
get_value(lines, token, start[, end[, default]):
|
||||
Similar to find_token, but it returns what follows the
|
||||
get_value(lines, token[, start[, end[, default[, delete]]]]):
|
||||
Similar to find_token, but it returns what follows the
|
||||
token on the found line. Example:
|
||||
get_value(document.header, "\\use_xetex", 0)
|
||||
will find a line like:
|
||||
\\use_xetex true
|
||||
and, in that case, return "true". (Note that whitespace
|
||||
is stripped.) The final argument, default, defaults to "",
|
||||
is stripped.) The final argument, default, defaults to "",
|
||||
and is what is returned if we do not find anything. So you
|
||||
can use that to set a default.
|
||||
|
||||
get_quoted_value(lines, token, start[, end[, default]]):
|
||||
If delete is True, then delete the line if found.
|
||||
|
||||
get_quoted_value(lines, token[, start[, end[, default[, delete]]]]):
|
||||
Similar to get_value, but it will strip quotes off the
|
||||
value, if they are present. So use this one for cases
|
||||
where the value is normally quoted.
|
||||
@ -74,20 +78,27 @@ get_option_value(line, option):
|
||||
option="value"
|
||||
and returns value. Returns "" if not found.
|
||||
|
||||
get_bool_value(lines, token, start[, end[, default]]):
|
||||
get_bool_value(lines, token[, start[, end[, default, delete]]]]):
|
||||
Like get_value, but returns a boolean.
|
||||
|
||||
del_token(lines, token, start[, end]):
|
||||
set_bool_value(lines, token, value[, start[, end]]):
|
||||
Find `token` in `lines[start:end]` and set to boolean value bool(`value`).
|
||||
Return old value. Raise ValueError if token is not in lines.
|
||||
|
||||
del_token(lines, token[, start[, end]]):
|
||||
Like find_token, but deletes the line if it finds one.
|
||||
Returns True if a line got deleted, otherwise False.
|
||||
|
||||
Use get_* with the optional argument "delete=True", if you want to
|
||||
get and delete a token.
|
||||
|
||||
find_beginning_of(lines, i, start_token, end_token):
|
||||
Here, start_token and end_token are meant to be a matching
|
||||
pair, like "\\begin_layout" and "\\end_layout". We look for
|
||||
Here, start_token and end_token are meant to be a matching
|
||||
pair, like "\\begin_layout" and "\\end_layout". We look for
|
||||
the start_token that pairs with the end_token that occurs
|
||||
on or after line i. Returns -1 if not found.
|
||||
So, in the layout case, this would find the \\begin_layout
|
||||
for the layout line i is in.
|
||||
So, in the layout case, this would find the \\begin_layout
|
||||
for the layout line i is in.
|
||||
Example:
|
||||
ec = find_token(document.body, "</cell", i)
|
||||
bc = find_beginning_of(document.body, ec, \
|
||||
@ -95,7 +106,7 @@ find_beginning_of(lines, i, start_token, end_token):
|
||||
Now, assuming no -1s, bc-ec wraps the cell for line i.
|
||||
|
||||
find_end_of(lines, i, start_token, end_token):
|
||||
Like find_beginning_of, but looking for the matching
|
||||
Like find_beginning_of, but looking for the matching
|
||||
end_token. This might look like:
|
||||
bc = find_token_(document.body, "<cell", i)
|
||||
ec = find_end_of(document.body, bc, "<cell", "</cell")
|
||||
@ -110,25 +121,25 @@ find_end_of_layout(lines, i):
|
||||
find_end_of_sequence(lines, i):
|
||||
Find the end of the sequence of layouts of the same kind.
|
||||
Considers nesting. If the last paragraph in sequence is nested,
|
||||
the position of the last \end_deeper is returned, else
|
||||
the position of the last \end_layout.
|
||||
the position of the last \\end_deeper is returned, else
|
||||
the position of the last \\end_layout.
|
||||
|
||||
is_in_inset(lines, i, inset):
|
||||
Checks if line i is in an inset of the given type.
|
||||
If so, returns starting and ending lines. Otherwise,
|
||||
returns False.
|
||||
is_in_inset(lines, i, inset, default=(-1,-1)):
|
||||
Check if line i is in an inset of the given type.
|
||||
If so, returns starting and ending lines. Otherwise,
|
||||
return default.
|
||||
Example:
|
||||
is_in_inset(document.body, i, "\\begin_inset Tabular")
|
||||
returns False unless i is within a table. If it is, then
|
||||
returns (-1,-1) unless i is within a table. If it is, then
|
||||
it returns the line on which the table begins and the one
|
||||
on which it ends. Note that this pair will evaulate to
|
||||
boolean True, so
|
||||
if is_in_inset(...):
|
||||
if is_in_inset(..., default=False):
|
||||
will do what you expect.
|
||||
|
||||
get_containing_inset(lines, i):
|
||||
Finds out what kind of inset line i is within. Returns a
|
||||
list containing what follows \begin_inset on the line
|
||||
Finds out what kind of inset line i is within. Returns a
|
||||
list containing what follows \\begin_inset on the line
|
||||
on which the inset begins, plus the starting and ending line.
|
||||
Returns False on any kind of error or if it isn't in an inset.
|
||||
So get_containing_inset(document.body, i) might return:
|
||||
@ -152,7 +163,7 @@ is_nonempty_line(line):
|
||||
count_pars_in_inset(lines, i):
|
||||
Counts the paragraphs inside an inset.
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
@ -161,9 +172,11 @@ def check_token(line, token):
|
||||
""" check_token(line, token) -> bool
|
||||
|
||||
Return True if token is present in line and is the first element
|
||||
else returns False."""
|
||||
else returns False.
|
||||
|
||||
return line[:len(token)] == token
|
||||
Deprecated. Use line.startswith(token).
|
||||
"""
|
||||
return line.startswith(token)
|
||||
|
||||
|
||||
def is_nonempty_line(line):
|
||||
@ -171,50 +184,53 @@ def is_nonempty_line(line):
|
||||
|
||||
Return False if line is either empty or it has only whitespaces,
|
||||
else return True."""
|
||||
return line != " "*len(line)
|
||||
return bool(line.strip())
|
||||
|
||||
|
||||
# Utilities for a list of lines
|
||||
def find_token(lines, token, start, end = 0, ignorews = False):
|
||||
def find_token(lines, token, start=0, end=0, ignorews=False):
|
||||
""" find_token(lines, token, start[[, end], ignorews]) -> int
|
||||
|
||||
Return the lowest line where token is found, and is the first
|
||||
element, in lines[start, end].
|
||||
|
||||
|
||||
If ignorews is True (default is False), then differences in
|
||||
whitespace are ignored, except that there must be no extra
|
||||
whitespace following token itself.
|
||||
whitespace are ignored, but there must be whitespace following
|
||||
token itself.
|
||||
|
||||
Use find_substring(lines, sub) to find a substring anywhere in `lines`.
|
||||
|
||||
Return -1 on failure."""
|
||||
|
||||
if end == 0 or end > len(lines):
|
||||
end = len(lines)
|
||||
m = len(token)
|
||||
if ignorews:
|
||||
y = token.split()
|
||||
for i in range(start, end):
|
||||
if ignorews:
|
||||
x = lines[i].split()
|
||||
y = token.split()
|
||||
if len(x) < len(y):
|
||||
continue
|
||||
if x[:len(y)] == y:
|
||||
return i
|
||||
else:
|
||||
if lines[i][:m] == token:
|
||||
if lines[i].startswith(token):
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def find_token_exact(lines, token, start, end = 0):
|
||||
def find_token_exact(lines, token, start=0, end=0):
|
||||
return find_token(lines, token, start, end, True)
|
||||
|
||||
|
||||
def find_tokens(lines, tokens, start, end = 0, ignorews = False):
|
||||
def find_tokens(lines, tokens, start=0, end=0, ignorews=False):
|
||||
""" find_tokens(lines, tokens, start[[, end], ignorews]) -> int
|
||||
|
||||
Return the lowest line where one token in tokens is found, and is
|
||||
the first element, in lines[start, end].
|
||||
|
||||
Return -1 on failure."""
|
||||
|
||||
if end == 0 or end > len(lines):
|
||||
end = len(lines)
|
||||
|
||||
@ -228,23 +244,41 @@ def find_tokens(lines, tokens, start, end = 0, ignorews = False):
|
||||
if x[:len(y)] == y:
|
||||
return i
|
||||
else:
|
||||
if lines[i][:len(token)] == token:
|
||||
if lines[i].startswith(token):
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def find_tokens_exact(lines, tokens, start, end = 0):
|
||||
def find_tokens_exact(lines, tokens, start=0, end=0):
|
||||
return find_tokens(lines, tokens, start, end, True)
|
||||
|
||||
|
||||
def find_re(lines, rexp, start, end = 0):
|
||||
""" find_token_re(lines, rexp, start[, end]) -> int
|
||||
def find_substring(lines, sub, start=0, end=0):
|
||||
""" find_substring(lines, sub[, start[, end]]) -> int
|
||||
|
||||
Return the lowest line where rexp, a regular expression, is found
|
||||
in lines[start, end].
|
||||
Return the lowest line number `i` in [start, end] where
|
||||
`sub` is a substring of line[i].
|
||||
|
||||
Return -1 on failure."""
|
||||
|
||||
if end == 0 or end > len(lines):
|
||||
end = len(lines)
|
||||
for i in range(start, end):
|
||||
if sub in lines[i]:
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def find_re(lines, rexp, start=0, end=0):
|
||||
""" find_re(lines, rexp[, start[, end]]) -> int
|
||||
|
||||
Return the lowest line number `i` in [start, end] where the regular
|
||||
expression object `rexp` matches at the beginning of line[i].
|
||||
Return -1 on failure.
|
||||
|
||||
Start your pattern with the wildcard ".*" to find a match anywhere in a
|
||||
line. Use find_substring() to find a substring anywhere in the lines.
|
||||
"""
|
||||
if end == 0 or end > len(lines):
|
||||
end = len(lines)
|
||||
for i in range(start, end):
|
||||
@ -260,10 +294,8 @@ def find_token_backwards(lines, token, start):
|
||||
element, in lines[start, end].
|
||||
|
||||
Return -1 on failure."""
|
||||
m = len(token)
|
||||
for i in range(start, -1, -1):
|
||||
line = lines[i]
|
||||
if line[:m] == token:
|
||||
if lines[i].startswith(token):
|
||||
return i
|
||||
return -1
|
||||
|
||||
@ -278,30 +310,111 @@ def find_tokens_backwards(lines, tokens, start):
|
||||
for i in range(start, -1, -1):
|
||||
line = lines[i]
|
||||
for token in tokens:
|
||||
if line[:len(token)] == token:
|
||||
if line.startswith(token):
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def get_value(lines, token, start, end = 0, default = ""):
|
||||
""" get_value(lines, token, start[[, end], default]) -> string
|
||||
def find_complete_lines(lines, sublines, start=0, end=0):
|
||||
"""Find first occurence of sequence `sublines` in list `lines`.
|
||||
Return index of first line or -1 on failure.
|
||||
|
||||
Efficient search for a sub-list in a large list. Works for any values.
|
||||
|
||||
>>> find_complete_lines([1, 2, 3, 1, 1, 2], [1, 2])
|
||||
0
|
||||
|
||||
The `start` and `end` arguments work similar to list.index()
|
||||
|
||||
>>> find_complete_lines([1, 2, 3, 1, 1 ,2], [1, 2], start=1)
|
||||
4
|
||||
>>> find_complete_lines([1, 2, 3, 1, 1 ,2], [1, 2], start=1, end=4)
|
||||
-1
|
||||
|
||||
The return value can be used to substitute the sub-list.
|
||||
Take care to check before use:
|
||||
|
||||
>>> l = [1, 1, 2]
|
||||
>>> s = find_complete_lines(l, [1, 2])
|
||||
>>> if s != -1:
|
||||
... l[s:s+2] = [3]; l
|
||||
[1, 3]
|
||||
|
||||
See also del_complete_lines().
|
||||
"""
|
||||
if not sublines:
|
||||
return start
|
||||
end = end or len(lines)
|
||||
N = len(sublines)
|
||||
try:
|
||||
while True:
|
||||
for j, value in enumerate(sublines):
|
||||
i = lines.index(value, start, end)
|
||||
if j and i != start:
|
||||
start = i-j
|
||||
break
|
||||
start = i + 1
|
||||
else:
|
||||
return i +1 - N
|
||||
except ValueError: # `sublines` not found
|
||||
return -1
|
||||
|
||||
|
||||
def find_across_lines(lines, sub, start=0, end=0):
|
||||
sublines = sub.splitlines()
|
||||
if len(sublines) > 2:
|
||||
# at least 3 lines: the middle one(s) are complete -> use index search
|
||||
i = find_complete_lines(lines, sublines[1:-1], start+1, end-1)
|
||||
if i < start+1:
|
||||
return -1
|
||||
try:
|
||||
if (lines[i-1].endswith(sublines[0]) and
|
||||
lines[i+len(sublines)].startswith(sublines[-1])):
|
||||
return i-1
|
||||
except IndexError:
|
||||
pass
|
||||
elif len(sublines) > 1:
|
||||
# last subline must start a line
|
||||
i = find_token(lines, sublines[-1], start, end)
|
||||
if i < start + 1:
|
||||
return -1
|
||||
if lines[i-1].endswith(sublines[0]):
|
||||
return i-1
|
||||
else: # no line-break, may be in the middle of a line
|
||||
if end == 0 or end > len(lines):
|
||||
end = len(lines)
|
||||
for i in range(start, end):
|
||||
if sub in lines[i]:
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def get_value(lines, token, start=0, end=0, default="", delete=False):
|
||||
"""Find `token` in `lines` and return part of line that follows it.
|
||||
|
||||
Find the next line that looks like:
|
||||
token followed by other stuff
|
||||
Returns "followed by other stuff" with leading and trailing
|
||||
|
||||
If `delete` is True, delete the line (if found).
|
||||
|
||||
Return "followed by other stuff" with leading and trailing
|
||||
whitespace removed.
|
||||
"""
|
||||
|
||||
i = find_token_exact(lines, token, start, end)
|
||||
if i == -1:
|
||||
return default
|
||||
# TODO: establish desired behaviour, eventually change to
|
||||
# return lines.pop(i)[len(token):].strip() # or default
|
||||
# see test_parser_tools.py
|
||||
l = lines[i].split(None, 1)
|
||||
if delete:
|
||||
del(lines[i])
|
||||
if len(l) > 1:
|
||||
return l[1].strip()
|
||||
return default
|
||||
|
||||
|
||||
def get_quoted_value(lines, token, start, end = 0, default = ""):
|
||||
def get_quoted_value(lines, token, start=0, end=0, default="", delete=False):
|
||||
""" get_quoted_value(lines, token, start[[, end], default]) -> string
|
||||
|
||||
Find the next line that looks like:
|
||||
@ -312,33 +425,52 @@ def get_quoted_value(lines, token, start, end = 0, default = ""):
|
||||
if they are there.
|
||||
Note that we will NOT strip quotes from default!
|
||||
"""
|
||||
val = get_value(lines, token, start, end, "")
|
||||
val = get_value(lines, token, start, end, "", delete)
|
||||
if not val:
|
||||
return default
|
||||
return val.strip('"')
|
||||
|
||||
|
||||
def get_bool_value(lines, token, start, end = 0, default = None):
|
||||
""" get_value(lines, token, start[[, end], default]) -> string
|
||||
bool_values = {"true": True, "1": True,
|
||||
"false": False, "0": False}
|
||||
|
||||
def get_bool_value(lines, token, start=0, end=0, default=None, delete=False):
|
||||
""" get_bool_value(lines, token, start[[, end], default]) -> string
|
||||
|
||||
Find the next line that looks like:
|
||||
token bool_value
|
||||
`token` <bool_value>
|
||||
|
||||
Returns True if bool_value is 1 or true and
|
||||
False if bool_value is 0 or false
|
||||
Return True if <bool_value> is 1 or "true", False if <bool_value>
|
||||
is 0 or "false", else `default`.
|
||||
"""
|
||||
val = get_quoted_value(lines, token, start, end, default, delete)
|
||||
return bool_values.get(val, default)
|
||||
|
||||
val = get_quoted_value(lines, token, start, end, "")
|
||||
|
||||
if val == "1" or val == "true":
|
||||
return True
|
||||
if val == "0" or val == "false":
|
||||
return False
|
||||
return default
|
||||
def set_bool_value(lines, token, value, start=0, end=0):
|
||||
"""Find `token` in `lines` and set to bool(`value`).
|
||||
|
||||
Return previous value. Raise `ValueError` if `token` is not in lines.
|
||||
|
||||
Cf. find_token(), get_bool_value().
|
||||
"""
|
||||
i = find_token(lines, token, start, end)
|
||||
if i == -1:
|
||||
raise ValueError
|
||||
oldvalue = get_bool_value(lines, token, i, i+1)
|
||||
if oldvalue is value:
|
||||
return oldvalue
|
||||
# set to new value
|
||||
if get_quoted_value(lines, token, i, i+1) in ('0', '1'):
|
||||
lines[i] = "%s %d" % (token, value)
|
||||
else:
|
||||
lines[i] = "%s %s" % (token, str(value).lower())
|
||||
|
||||
return oldvalue
|
||||
|
||||
|
||||
def get_option_value(line, option):
|
||||
rx = option + '\s*=\s*"([^"]+)"'
|
||||
rx = option + r'\s*=\s*"([^"]+)"'
|
||||
rx = re.compile(rx)
|
||||
m = rx.search(line)
|
||||
if not m:
|
||||
@ -347,18 +479,18 @@ def get_option_value(line, option):
|
||||
|
||||
|
||||
def set_option_value(line, option, value):
|
||||
rx = '(' + option + '\s*=\s*")[^"]+"'
|
||||
rx = '(' + option + r'\s*=\s*")[^"]+"'
|
||||
rx = re.compile(rx)
|
||||
m = rx.search(line)
|
||||
if not m:
|
||||
return line
|
||||
return re.sub(rx, '\g<1>' + value + '"', line)
|
||||
return re.sub(rx, r'\g<1>' + value + '"', line)
|
||||
|
||||
|
||||
def del_token(lines, token, start, end = 0):
|
||||
def del_token(lines, token, start=0, end=0):
|
||||
""" del_token(lines, token, start, end) -> int
|
||||
|
||||
Find the first line in lines where token is the first element
|
||||
Find the first line in lines where token is the first element
|
||||
and delete that line. Returns True if we deleted a line, False
|
||||
if we did not."""
|
||||
|
||||
@ -368,6 +500,41 @@ def del_token(lines, token, start, end = 0):
|
||||
del lines[k]
|
||||
return True
|
||||
|
||||
def del_complete_lines(lines, sublines, start=0, end=0):
|
||||
"""Delete first occurence of `sublines` in list `lines`.
|
||||
|
||||
Efficient deletion of a sub-list in a list. Works for any values.
|
||||
The `start` and `end` arguments work similar to list.index()
|
||||
|
||||
Returns True if a deletion was done and False if not.
|
||||
|
||||
>>> l = [1, 0, 1, 1, 1, 2]
|
||||
>>> del_complete_lines(l, [0, 1, 1])
|
||||
True
|
||||
>>> l
|
||||
[1, 1, 2]
|
||||
"""
|
||||
i = find_complete_lines(lines, sublines, start, end)
|
||||
if i == -1:
|
||||
return False
|
||||
del(lines[i:i+len(sublines)])
|
||||
return True
|
||||
|
||||
|
||||
def del_value(lines, token, start=0, end=0, default=None):
|
||||
"""
|
||||
Find the next line that looks like:
|
||||
token followed by other stuff
|
||||
Delete that line and return "followed by other stuff"
|
||||
with leading and trailing whitespace removed.
|
||||
|
||||
If token is not found, return `default`.
|
||||
"""
|
||||
i = find_token_exact(lines, token, start, end)
|
||||
if i == -1:
|
||||
return default
|
||||
return lines.pop(i)[len(token):].strip()
|
||||
|
||||
|
||||
def find_beginning_of(lines, i, start_token, end_token):
|
||||
count = 1
|
||||
@ -375,7 +542,7 @@ def find_beginning_of(lines, i, start_token, end_token):
|
||||
i = find_tokens_backwards(lines, [start_token, end_token], i-1)
|
||||
if i == -1:
|
||||
return -1
|
||||
if check_token(lines[i], end_token):
|
||||
if lines[i].startswith(end_token):
|
||||
count = count+1
|
||||
else:
|
||||
count = count-1
|
||||
@ -391,7 +558,7 @@ def find_end_of(lines, i, start_token, end_token):
|
||||
i = find_tokens(lines, [end_token, start_token], i+1)
|
||||
if i == -1:
|
||||
return -1
|
||||
if check_token(lines[i], start_token):
|
||||
if lines[i].startswith(start_token):
|
||||
count = count+1
|
||||
else:
|
||||
count = count-1
|
||||
@ -400,11 +567,11 @@ def find_end_of(lines, i, start_token, end_token):
|
||||
return -1
|
||||
|
||||
|
||||
def find_nonempty_line(lines, start, end = 0):
|
||||
def find_nonempty_line(lines, start=0, end=0):
|
||||
if end == 0:
|
||||
end = len(lines)
|
||||
for i in range(start, end):
|
||||
if is_nonempty_line(lines[i]):
|
||||
if lines[i].strip():
|
||||
return i
|
||||
return -1
|
||||
|
||||
@ -419,35 +586,33 @@ def find_end_of_layout(lines, i):
|
||||
return find_end_of(lines, i, "\\begin_layout", "\\end_layout")
|
||||
|
||||
|
||||
def is_in_inset(lines, i, inset):
|
||||
'''
|
||||
Checks if line i is in an inset of the given type.
|
||||
If so, returns starting and ending lines.
|
||||
Otherwise, returns False.
|
||||
def is_in_inset(lines, i, inset, default=(-1,-1)):
|
||||
"""
|
||||
Check if line i is in an inset of the given type.
|
||||
If so, return starting and ending lines, otherwise `default`.
|
||||
Example:
|
||||
is_in_inset(document.body, i, "\\begin_inset Tabular")
|
||||
returns False unless i is within a table. If it is, then
|
||||
it returns the line on which the table begins and the one
|
||||
on which it ends. Note that this pair will evaulate to
|
||||
boolean True, so
|
||||
if is_in_inset(...):
|
||||
returns (-1,-1) if `i` is not within a "Tabular" inset (i.e. a table).
|
||||
If it is, then it returns the line on which the table begins and the one
|
||||
on which it ends.
|
||||
Note that this pair will evaulate to boolean True, so (with the optional
|
||||
default value set to False)
|
||||
if is_in_inset(..., default=False):
|
||||
will do what you expect.
|
||||
'''
|
||||
defval = (-1, -1)
|
||||
stins = find_token_backwards(lines, inset, i)
|
||||
if stins == -1:
|
||||
return defval
|
||||
endins = find_end_of_inset(lines, stins)
|
||||
# note that this includes the notfound case.
|
||||
if endins < i:
|
||||
return defval
|
||||
return (stins, endins)
|
||||
"""
|
||||
start = find_token_backwards(lines, inset, i)
|
||||
if start == -1:
|
||||
return default
|
||||
end = find_end_of_inset(lines, start)
|
||||
if end < i: # this includes the notfound case.
|
||||
return default
|
||||
return (start, end)
|
||||
|
||||
|
||||
def get_containing_inset(lines, i):
|
||||
'''
|
||||
Finds out what kind of inset line i is within. Returns a
|
||||
list containing (i) what follows \begin_inset on the line
|
||||
'''
|
||||
Finds out what kind of inset line i is within. Returns a
|
||||
list containing (i) what follows \\begin_inset on the line
|
||||
on which the inset begins, plus the starting and ending line.
|
||||
Returns False on any kind of error or if it isn't in an inset.
|
||||
'''
|
||||
@ -472,13 +637,16 @@ def get_containing_inset(lines, i):
|
||||
|
||||
|
||||
def get_containing_layout(lines, i):
|
||||
'''
|
||||
Finds out what kind of layout line i is within. Returns a
|
||||
list containing what follows \begin_layout on the line
|
||||
on which the layout begins, plus the starting and ending line
|
||||
and the start of the paragraph (after all params). I.e, returns:
|
||||
'''
|
||||
Find out what kind of layout line `i` is within.
|
||||
Return a tuple
|
||||
(layoutname, layoutstart, layoutend, startofcontent)
|
||||
Returns False on any kind of error.
|
||||
containing
|
||||
* layout style/name,
|
||||
* start line number,
|
||||
* end line number, and
|
||||
* number of first paragraph line (after all params).
|
||||
Return `False` on any kind of error.
|
||||
'''
|
||||
j = i
|
||||
while True:
|
||||
@ -493,10 +661,13 @@ def get_containing_layout(lines, i):
|
||||
if endlay < i:
|
||||
return False
|
||||
|
||||
lay = get_value(lines, "\\begin_layout", stlay)
|
||||
if lay == "":
|
||||
# shouldn't happen
|
||||
return False
|
||||
layoutname = get_value(lines, "\\begin_layout", stlay)
|
||||
if layoutname == "": # layout style missing
|
||||
# TODO: What shall we do in this case?
|
||||
pass
|
||||
# layoutname == "Standard" # use same fallback as the LyX parser:
|
||||
# raise ValueError("Missing layout name on line %d"%stlay) # diagnosis
|
||||
# return False # generic error response
|
||||
par_params = ["\\noindent", "\\indent", "\\indent-toggle", "\\leftindent",
|
||||
"\\start_of_appendix", "\\paragraph_spacing", "\\align",
|
||||
"\\labelwidthstring"]
|
||||
@ -505,7 +676,7 @@ def get_containing_layout(lines, i):
|
||||
stpar += 1
|
||||
if lines[stpar].split(' ', 1)[0] not in par_params:
|
||||
break
|
||||
return (lay, stlay, endlay, stpar)
|
||||
return (layoutname, stlay, endlay, stpar)
|
||||
|
||||
|
||||
def count_pars_in_inset(lines, i):
|
||||
@ -518,7 +689,8 @@ def count_pars_in_inset(lines, i):
|
||||
pars = 0
|
||||
for j in range(ins[1], ins[2]):
|
||||
m = re.match(r'\\begin_layout (.*)', lines[j])
|
||||
if m and get_containing_inset(lines, j)[0] == ins[0]:
|
||||
found_inset = get_containing_inset(lines, j)
|
||||
if m and found_inset and found_inset[1] == ins[1]:
|
||||
pars += 1
|
||||
|
||||
return pars
|
||||
@ -553,4 +725,3 @@ def find_end_of_sequence(lines, i):
|
||||
i = i + 1
|
||||
|
||||
return endlay
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#! /usr/bin/env python
|
||||
#! /usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2004 José Matos <jamatos@lyx.org>
|
||||
#
|
||||
|
79
lib/lyx2lyx/test_lyx2lyx_tools.py
Normal file
79
lib/lyx2lyx/test_lyx2lyx_tools.py
Normal file
@ -0,0 +1,79 @@
|
||||
# This file is part of lyx2lyx
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2018 The LyX team
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
" This modules tests the auxiliary functions for lyx2lyx."
|
||||
|
||||
from lyx2lyx_tools import *
|
||||
|
||||
import unittest
|
||||
|
||||
class TestParserTools(unittest.TestCase):
|
||||
|
||||
def test_put_cmd_in_ert(self):
|
||||
ert = [u'\\begin_inset ERT',
|
||||
u'status collapsed',
|
||||
u'',
|
||||
u'\\begin_layout Plain Layout',
|
||||
u'',
|
||||
u'',
|
||||
u'\\backslash',
|
||||
u'texttt{Gr',
|
||||
u'\\backslash',
|
||||
u'"{u}',
|
||||
u'\\backslash',
|
||||
u'ss{}e}',
|
||||
u'\\end_layout',
|
||||
u'',
|
||||
u'\\end_inset']
|
||||
ert_open = ert[:]
|
||||
ert_open[1] = u'status open'
|
||||
ert_paragraph = ["\\begin_layout Standard",
|
||||
u'\\begin_inset ERT',
|
||||
u'status collapsed',
|
||||
u'',
|
||||
u'\\begin_layout Plain Layout',
|
||||
u'',
|
||||
u'',
|
||||
u'\\backslash',
|
||||
u'texttt{Gr',
|
||||
u'\\backslash',
|
||||
u'"{u}',
|
||||
u'\\backslash',
|
||||
u'ss{}e}',
|
||||
u'\\end_layout',
|
||||
u'',
|
||||
u'\\end_inset',
|
||||
u'',
|
||||
u'',
|
||||
u'\\end_layout',
|
||||
u'']
|
||||
self.assertEqual(put_cmd_in_ert("\\texttt{Grüße}"), ert)
|
||||
self.assertEqual(put_cmd_in_ert([u"\\texttt{Grüße}"]), ert)
|
||||
self.assertEqual(put_cmd_in_ert(u"\\texttt{Grüße}", is_open=True), ert_open)
|
||||
self.assertEqual(put_cmd_in_ert(u"\\texttt{Grüße}", as_paragraph=True), ert_paragraph)
|
||||
|
||||
def test_latex_length(self):
|
||||
self.assertEqual(latex_length("-30.5col%"), (True, "-0.305\\columnwidth"))
|
||||
self.assertEqual(latex_length("35baselineskip%"), (True, "0.35\\baselineskip"))
|
||||
self.assertEqual(latex_length("11em"), (False, "11em"))
|
||||
self.assertEqual(latex_length("-0.4pt"), (False, "-0.4pt"))
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -22,7 +22,7 @@ from parser_tools import *
|
||||
|
||||
import unittest
|
||||
|
||||
ug = r"""
|
||||
lines = r"""
|
||||
\begin_layout Standard
|
||||
The
|
||||
\begin_inset Quotes eld
|
||||
@ -56,9 +56,26 @@ Introduction
|
||||
describes that, too.
|
||||
\end_layout
|
||||
|
||||
"""
|
||||
""".splitlines()
|
||||
|
||||
header = r"""\begin_header
|
||||
\origin unavailable
|
||||
\paperpagestyle default
|
||||
\output_changes false
|
||||
\html_math_output 0
|
||||
\html_css_as_file 0
|
||||
\html_be_strict fallse
|
||||
\end_header""".splitlines()
|
||||
|
||||
newheader = r"""\begin_header
|
||||
\origin unavailable
|
||||
\paperpagestyle default
|
||||
\output_changes true
|
||||
\html_math_output 0
|
||||
\html_css_as_file 1
|
||||
\html_be_strict false
|
||||
\end_header""".splitlines()
|
||||
|
||||
lines = ug.splitlines()
|
||||
|
||||
class TestParserTools(unittest.TestCase):
|
||||
|
||||
@ -77,10 +94,21 @@ class TestParserTools(unittest.TestCase):
|
||||
|
||||
def test_find_token(self):
|
||||
self.assertEqual(find_token(lines, '\\emph', 0), 7)
|
||||
self.assertEqual(find_token(lines, '\\emph', 0, 5), -1)
|
||||
self.assertEqual(find_token(lines, '\\emp', 0, 0, True), -1)
|
||||
self.assertEqual(find_token(lines, '\\emp', 0, 0, False), 7)
|
||||
# no line starts with "emph" (without backspace):
|
||||
self.assertEqual(find_token(lines, 'emph', 0), -1)
|
||||
# token on line[start] is found:
|
||||
self.assertEqual(find_token(lines, '\\emph', 7), 7)
|
||||
self.assertEqual(find_token(lines, '\\emph', 8), 9)
|
||||
# token on line[end] is not found:
|
||||
self.assertEqual(find_token(lines, '\\emph', 0, 7), -1)
|
||||
# `ignorews` looks for whitespace-separated tokens:
|
||||
self.assertEqual(find_token(lines, '\\emp', 0, ignorews=True), -1)
|
||||
self.assertEqual(find_token(lines, '\\emph',0, ignorews=True), 7)
|
||||
self.assertEqual(find_token(lines, '\\emph', 7, ignorews=True), 7)
|
||||
self.assertEqual(find_token(lines, '\\emph', 0, 7, True), -1)
|
||||
# only first token is found:
|
||||
self.assertEqual(find_token(lines, 'Quotes', 0), -1)
|
||||
self.assertEqual(find_token(lines, 'Quotes', 0, ignorews=True), -1)
|
||||
|
||||
|
||||
def test_find_tokens(self):
|
||||
@ -89,5 +117,128 @@ class TestParserTools(unittest.TestCase):
|
||||
self.assertEqual(find_tokens(lines, tokens, 0, 4), -1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
def test_find_substring(self):
|
||||
# Quotes is not a "token" (substring at the start of any line):
|
||||
self.assertEqual(find_token(lines, "Quotes", 0), -1)
|
||||
self.assertEqual(find_substring(lines, "Quotes", 0), 3)
|
||||
# return -1 on failure:
|
||||
self.assertEqual(find_substring(lines, "Qualen", 0), -1)
|
||||
|
||||
|
||||
def test_find_re(self):
|
||||
regexp_object = re.compile(r'\\begin.*Quote')
|
||||
# matching starts with line[start] (default: start=0)
|
||||
self.assertEqual(find_re(lines, regexp_object), 3)
|
||||
self.assertEqual(find_re(lines, regexp_object, start=3), 3)
|
||||
# matching ends one line *before* line[end]:
|
||||
self.assertEqual(find_re(lines, regexp_object, start=4), 11)
|
||||
self.assertEqual(find_re(lines, regexp_object, start=4, end=11), -1)
|
||||
|
||||
def test_find_complete_lines(self):
|
||||
sublines = ["\\begin_inset Quotes eld",
|
||||
"\\end_inset"]
|
||||
# return index of first line of sublines:
|
||||
self.assertEqual(find_complete_lines(lines, sublines), 3)
|
||||
self.assertEqual(find_complete_lines(lines, ["\\end_inset"]), 4)
|
||||
# return -1 if sublines is not found:
|
||||
self.assertEqual(find_complete_lines(lines, ['x']), -1)
|
||||
# search includes line `start`:
|
||||
self.assertEqual(find_complete_lines(lines, sublines, 3), 3)
|
||||
self.assertEqual(find_complete_lines(lines, sublines, 4), 20)
|
||||
self.assertEqual(find_complete_lines(lines, sublines, 21), -1)
|
||||
# serch excludes line `end`
|
||||
self.assertEqual(find_complete_lines(lines, sublines, 4, 20), -1)
|
||||
# an empty list is always found
|
||||
self.assertEqual(find_complete_lines(lines, []), 0)
|
||||
|
||||
|
||||
def test_find_across_lines(self):
|
||||
# sub with at least 2 line-breaks (uses find_complete_lines):
|
||||
sub = "Quotes eld\n\\end_inset\n\n\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), 3)
|
||||
# Return -1 if not found
|
||||
self.assertEqual(find_across_lines(lines, sub, 4), -1)
|
||||
self.assertEqual(find_across_lines(lines, sub, 0, 6), -1)
|
||||
sub = "Quotes eld\n\\end_inset\nx\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), -1)
|
||||
sub = "Quotes X\n\\end_inset\n\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), -1)
|
||||
sub = "Quotes eld\n\\end_insert\n\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), -1)
|
||||
# sub with up to 1 line-break:
|
||||
sub = "Quotes eld\n\\end_inset"
|
||||
self.assertEqual(find_across_lines(lines, sub), 3)
|
||||
self.assertEqual(find_across_lines(lines, sub, 4), -1)
|
||||
self.assertEqual(find_across_lines(lines, sub, 0, 4), -1)
|
||||
self.assertEqual(find_across_lines(lines, sub, 4, 3), -1)
|
||||
sub = "Quotes X eld\n\\end_inset\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), -1)
|
||||
sub = "Quotes eld\n\\end_insert\n"
|
||||
self.assertEqual(find_across_lines(lines, sub), -1)
|
||||
# sub without line-break
|
||||
sub = "end_"
|
||||
self.assertEqual(find_across_lines(lines, sub), 4)
|
||||
self.assertEqual(find_across_lines(lines, sub, 5), 12)
|
||||
self.assertEqual(find_across_lines(lines, sub, 0, 4), -1)
|
||||
self.assertEqual(find_across_lines(lines, sub, 2, 1), -1)
|
||||
self.assertEqual(find_across_lines(lines, "XXX"), -1)
|
||||
|
||||
|
||||
def test_get_value(self):
|
||||
self.assertEqual(get_value(lines, "\\begin_inset"), "Quotes eld")
|
||||
# TODO: do we want this:
|
||||
self.assertEqual(get_value(lines, "\\begin_inset Quotes"), "Quotes eld")
|
||||
# or only the part after "token":
|
||||
# self.assertEqual(get_value(lines, "\\begin_inset Quotes"), "eld")
|
||||
# return default if not found
|
||||
self.assertEqual(get_value(lines, "\\begin_insert", default=42), 42)
|
||||
# TODO: do we want this:
|
||||
self.assertEqual(get_value(lines, "\\end_inset", default=None), None)
|
||||
# or emtpy string if token is found but has no value:
|
||||
# self.assertEqual(get_value(lines, "\\end_inset", default=None), "")
|
||||
|
||||
def test_get_bool_value(self):
|
||||
self.assertEqual(get_bool_value(header, "\\output_changes"), False)
|
||||
self.assertEqual(get_bool_value(newheader, "\\output_changes"), True)
|
||||
self.assertEqual(get_bool_value(header, "\\html_css_as_file"), False)
|
||||
self.assertEqual(get_bool_value(newheader, "\\html_css_as_file"), True)
|
||||
self.assertEqual(get_bool_value(header, "\\something"), None)
|
||||
self.assertEqual(get_bool_value(header, "\\output_changes", 4), None)
|
||||
|
||||
def test_set_bool_value(self):
|
||||
# set to new value, return old value
|
||||
self.assertEqual(set_bool_value(header, "\\output_changes", True), False)
|
||||
self.assertEqual(set_bool_value(header, "\\html_css_as_file", True), False)
|
||||
# return default if misspelled:
|
||||
self.assertEqual(set_bool_value(header, "\\html_be_strict", False), None)
|
||||
# catch error and insert new setting:
|
||||
self.assertRaises(ValueError, set_bool_value, header, "\\something", 0)
|
||||
self.assertEqual(header, newheader)
|
||||
|
||||
def test_del_complete_lines(self):
|
||||
l = lines[:]
|
||||
sublines = ["\\begin_inset Quotes eld",
|
||||
"\\end_inset"]
|
||||
# normal operation: remove the first occurence of sublines:
|
||||
self.assertEqual(del_complete_lines(l, sublines), True)
|
||||
self.assertEqual(l[3], "")
|
||||
self.assertEqual(len(l), len(lines)-len(sublines))
|
||||
# special cases:
|
||||
l = lines[:]
|
||||
self.assertEqual(del_complete_lines(l, sublines, 21), False)
|
||||
self.assertEqual(l, lines)
|
||||
# deleting empty sublist returns success but does not change the list:
|
||||
self.assertEqual(del_complete_lines(l, [], 21), True)
|
||||
self.assertEqual(l, lines)
|
||||
|
||||
def test_del_value(self):
|
||||
l = lines[:]
|
||||
self.assertEqual(del_value(l, "\\begin_inset"), "Quotes eld")
|
||||
self.assertEqual(del_value(l, "\\begin_inset Quotes"), "erd")
|
||||
# return default if not found
|
||||
self.assertEqual(del_value(l, "\\begin_insert", default=42), 42)
|
||||
self.assertEqual(del_value(l, "\\end_inset", default=None), "")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
" Import unicode_reps from this module for access to the unicode<->LaTeX mapping. "
|
||||
|
||||
import sys, os, re
|
||||
import sys, os, re, codecs
|
||||
|
||||
# Provide support for both python 2 and 3
|
||||
PY2 = sys.version_info[0] == 2
|
||||
@ -28,14 +28,13 @@ if not PY2:
|
||||
|
||||
def read_unicodesymbols():
|
||||
" Read the unicodesymbols list of unicode characters and corresponding commands."
|
||||
pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
|
||||
pathname = os.path.abspath(os.path.dirname(__file__))
|
||||
filename = os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols')
|
||||
|
||||
# For python 3+ we have to specify the encoding for those systems
|
||||
# where the default is not UTF-8
|
||||
fp = open(filename, encoding="utf8") if (not PY2) else open(filename)
|
||||
# Read as Unicode strings in both, Python 2 and 3
|
||||
# Specify the encoding for those systems where the default is not UTF-8
|
||||
fp = codecs.open(filename, encoding="utf8")
|
||||
|
||||
spec_chars = []
|
||||
# A backslash, followed by some non-word character, and then a character
|
||||
# in brackets. The idea is to check for constructs like: \"{u}, which is how
|
||||
# they are written in the unicodesymbols file; but they can also be written
|
||||
@ -43,36 +42,42 @@ def read_unicodesymbols():
|
||||
# The two backslashes in the string literal are needed to specify a literal
|
||||
# backslash in the regex. Without r prefix, these would be four backslashes.
|
||||
r = re.compile(r'\\(\W)\{(\w)\}')
|
||||
|
||||
spec_chars = []
|
||||
for line in fp.readlines():
|
||||
if line[0] != '#' and line.strip() != "":
|
||||
# Note: backslashes in the string literals with r prefix are not escaped,
|
||||
# so one backslash in the source file equals one backslash in memory.
|
||||
# Without r prefix backslahses are escaped, so two backslashes in the
|
||||
# source file equal one backslash in memory.
|
||||
line=line.replace(' "',' ') # remove all quotation marks with spaces before
|
||||
line=line.replace('" ',' ') # remove all quotation marks with spaces after
|
||||
line=line.replace(r'\"','"') # unescape "
|
||||
line=line.replace(r'\\','\\') # unescape \
|
||||
try:
|
||||
[ucs4,command,dead] = line.split(None,2)
|
||||
if command[0:1] != "\\":
|
||||
continue
|
||||
if (line.find("notermination=text") < 0 and
|
||||
line.find("notermination=both") < 0 and command[-1] != "}"):
|
||||
command = command + "{}"
|
||||
spec_chars.append([command, unichr(eval(ucs4))])
|
||||
except:
|
||||
if not line.strip() or line.startswith('#'):
|
||||
# skip empty lines and comments
|
||||
continue
|
||||
# Note: backslashes in the string literals with r prefix are not escaped,
|
||||
# so one backslash in the source file equals one backslash in memory.
|
||||
# Without r prefix backslahses are escaped, so two backslashes in the
|
||||
# source file equal one backslash in memory.
|
||||
line=line.replace(' "',' ') # remove all quotation marks with spaces before
|
||||
line=line.replace('" ',' ') # remove all quotation marks with spaces after
|
||||
line=line.replace(r'\"','"') # unescape "
|
||||
line=line.replace(r'\\','\\') # unescape \
|
||||
try:
|
||||
[ucs4,command,dead] = line.split(None,2)
|
||||
if command[0:1] != "\\":
|
||||
continue
|
||||
m = r.match(command)
|
||||
if m != None:
|
||||
command = "\\"
|
||||
commandbl = command
|
||||
command += m.group(1) + m.group(2)
|
||||
commandbl += m.group(1) + ' ' + m.group(2)
|
||||
spec_chars.append([command, unichr(eval(ucs4))])
|
||||
spec_chars.append([commandbl, unichr(eval(ucs4))])
|
||||
literal_char = unichr(int(ucs4, 16))
|
||||
if (line.find("notermination=text") < 0 and
|
||||
line.find("notermination=both") < 0 and command[-1] != "}"):
|
||||
command = command + "{}"
|
||||
spec_chars.append([command, literal_char])
|
||||
except:
|
||||
continue
|
||||
m = r.match(command)
|
||||
if m != None:
|
||||
command = "\\"
|
||||
commandbl = command
|
||||
command += m.group(1) + m.group(2)
|
||||
commandbl += m.group(1) + ' ' + m.group(2)
|
||||
spec_chars.append([command, literal_char])
|
||||
spec_chars.append([commandbl, literal_char])
|
||||
fp.close()
|
||||
return spec_chars
|
||||
|
||||
|
||||
unicode_reps = read_unicodesymbols()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user