]> git.lyx.org Git - lyx.git/blob - lib/scripts/prefs2prefs.py
Revert "DocBook: add new layout parameter DocBookWrapperMergeWithPrevious."
[lyx.git] / lib / scripts / prefs2prefs.py
1 # -*- coding: utf-8 -*-
2
3 # file prefs2prefs.py
4 # This file is part of LyX, the document processor.
5 # Licence details can be found in the file COPYING.
6
7 # author Richard Heck
8
9 # Full author contact details are available in file CREDITS
10
11 # This is the main file for the user preferences conversion system.
12 # There are two subsidiary files:
13 #     prefs2prefs_lfuns.py
14 #     prefs2prefs_prefs.py
15 # The former is used to convert bind and ui files; the latter, to convert
16 # the preferences file.
17 #
18 # I've organized it this way because, in many ways, converting bind and ui
19 # files  lfuns) and converting the preferences file are the same task. It's
20 # very line-by-line, unlike lyx2lyx and layout2layout, where changes can be
21 # more "global". So we read the file, line by line, and give a bunch of
22 # converter functions a chance to see if they want to modify that line.
23
24 # The converter functions are all in the subsidiary files. They take a line
25 # as  argument and return a list: (Bool, NewLine), where the Bool says if
26 # we've modified anything and the NewLine is the new line, if so, which will
27 # be used to replace the old line.
28
29 # The format of the existing files is format 0, as of 2.0.alpha6. We'll
30 # introduce new format numbers as we proceed, just as with layout2layout.
31 # These will be different for the bind and ui files and for the preferences
32 # file.
33
34 from __future__ import print_function
35 import os, re, string, sys
36 from getopt import getopt
37 import io
38
39 ###########################################################
40 # Utility functions, borrowed from layout2layout.py
41
42 def trim_bom(line):
43     " Remove byte order mark."
44     if line[0:3] == u"\357\273\277":
45         return line[3:]
46     else:
47         return     line
48
49
50 def read(source):
51     " Read input file and strip lineendings."
52     lines = source.read().splitlines() or ['']
53     lines[0] = trim_bom(lines[0])
54     return lines
55
56
57 def write(output, lines):
58     " Write output file with native lineendings."
59     output.write(os.linesep.join(lines) + os.linesep)
60
61
62 # for use by find_format_lines
63 re_comment = re.compile(r'^#')
64 re_empty   = re.compile(r'^\s*$')
65
66 def find_format_line(lines):
67     '''
68     Returns (bool, int), where int is number of the line the `Format'
69     specification is on, or else the number of the first non-blank,
70     non-comment line. The bool tells whether we found a format line.
71     '''
72     for i in range(len(lines)):
73         l = lines[i]
74         if re_comment.search(l) or re_empty.search(l):
75             continue
76         m = re_format.search(l)
77         if m:
78             return (True, i)
79         # we're done when we have hit a non-comment, non-empty line
80         break
81     return (False, i)
82
83
84 # for use by get_format
85 re_format  = re.compile(r'^Format\s+(\d+)\s*$')
86
87 def get_format(lines):
88     " Gets format of current file and replaces the format line with a new one "
89     (found, format_line) = find_format_line(lines)
90     if not found:
91         return 0
92     line = lines[format_line]
93     m = re_format.search(line)
94     if not m:
95         sys.stderr.write("Couldn't match format line!\n" + line + "\n")
96         sys.exit(1)
97     return int(m.group(1))
98
99
100 def update_format(lines):
101     " Writes new format line "
102     (found, format_line) = find_format_line(lines)
103     if not found:
104         lines[format_line:format_line] = ("Format 1", "")
105         return
106
107     line = lines[format_line]
108     m = re_format.search(line)
109     if not m:
110         sys.stderr.write("Couldn't match format line!\n" + line + "\n")
111         sys.exit(1)
112     format = int(m.group(1))
113     lines[format_line] = "Format " + str(format + 1)
114
115
116 def abort(msg):
117     sys.stderr.write("\n%s\n" % (msg))
118     sys.exit(10)
119
120 #
121 ###########################################################
122
123 def usage():
124     print ("%s [-l] [-p] infile outfile" % sys.argv[0])
125     print ("or: %s [-l] [-p] <infile >outfile" % sys.argv[0])
126     print ("  -l: convert LFUNs (bind and ui files)")
127     print ("  -p: convert preferences")
128     print ("Note that exactly one of -l and -p is required.")
129
130
131 def main(argv):
132     try:
133         (options, args) = getopt(sys.argv[1:], "lp")
134     except:
135         usage()
136         abort("Unrecognized option")
137
138     opened_files = False
139     # Open files
140     if len(args) == 0:
141         source = sys.stdin
142         output = sys.stdout
143     elif len(args) == 2:
144         source = io.open(args[0], 'r', encoding='utf_8', errors='surrogateescape')
145         output = io.open(args[1], 'w', encoding='utf_8', newline='\n')
146         opened_files = True
147     else:
148         usage()
149         abort("Either zero or two arguments must be given.")
150
151     conversions = False
152
153     for (opt, param) in options:
154         if opt == "-l":
155             from prefs2prefs_lfuns import conversions
156         elif opt == "-p":
157             from prefs2prefs_prefs import conversions
158
159     if not conversions:
160         usage()
161         abort("Neither -l nor -p given.")
162     elif len(options) > 1:
163         usage()
164         abort("Only one of -l or -p should be given.")
165
166     current_format = len(conversions)
167     lines = read(source)
168     format = get_format(lines)
169
170     while format < current_format:
171         target_format, convert = conversions[format]
172         old_format = format
173
174         # make sure the conversion list is sequential
175         if int(old_format) + 1 != target_format:
176             abort("Something is wrong with the conversion chain.")
177
178         for c in convert:
179             for i in range(len(lines)):
180                 (update, newline) = c(lines[i])
181                 if update:
182                     lines[i] = newline
183
184         update_format(lines)
185         format = get_format(lines)
186
187         # sanity check
188         if int(old_format) + 1 != int(format):
189             abort("Failed to convert to new format!")
190
191     write(output, lines)
192
193     # Close files
194     if opened_files:
195         source.close()
196         output.close()
197
198     return 0
199
200
201 if __name__ == "__main__":
202     main(sys.argv)