]> git.lyx.org Git - lyx.git/blob - lib/scripts/prefs2prefs.py
00d619de211d800978076b99583262a97c177b00
[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 Kimberly 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. The converter functions are all in the subsidiary 
17 # files. 
18
19 # The format of the existing files was format 0, as of 2.0.alpha6.
20
21 from __future__ import print_function
22 import os, re, string, sys
23 from getopt import getopt
24 import io
25
26 ###########################################################
27 # Utility functions, borrowed from layout2layout.py
28
29 def trim_bom(line):
30         " Remove byte order mark."
31         if line[0:3] == u"\357\273\277":
32                 return line[3:]
33         else:
34                 return line
35
36
37 def read(source):
38         " Read input file and strip lineendings."
39         lines = source.read().splitlines() or ['']
40         lines[0] = trim_bom(lines[0])
41         return lines
42
43
44 def write(output, lines):
45         " Write output file with native lineendings."
46         output.write(os.linesep.join(lines) + os.linesep)
47
48
49 # for use by find_format_lines
50 re_comment = re.compile(r'^#')
51 re_empty   = re.compile(r'^\s*$')
52
53 def find_format_line(lines):
54         '''
55         Returns (bool, int), where int is number of the line the `Format'
56         specification is on, or else the number of the first non-blank,
57         non-comment line. The bool tells whether we found a format line.
58         '''
59         for i in range(len(lines)):
60                 l = lines[i]
61                 if re_comment.search(l) or re_empty.search(l):
62                         continue
63                 m = re_format.search(l)
64                 if m:
65                         return (True, i)
66                 # we're done when we have hit a non-comment, non-empty line
67                 break
68         return (False, i)
69
70
71 # for use by get_format
72 re_format  = re.compile(r'^Format\s+(\d+)\s*$')
73
74 def get_format(lines):
75         " Gets format of current file and replaces the format line with a new one "
76         (found, format_line) = find_format_line(lines)
77         if not found:
78                 return 0
79         line = lines[format_line]
80         m = re_format.search(line)
81         if not m:
82                 sys.stderr.write("Couldn't match format line!\n" + line + "\n")
83                 sys.exit(1)
84         return int(m.group(1))
85
86
87 def update_format(lines):
88         " Writes new format line "
89         (found, format_line) = find_format_line(lines)
90         if not found:
91                 lines[format_line:format_line] = ("Format 1", "")
92                 return
93
94         line = lines[format_line]
95         m = re_format.search(line)
96         if not m:
97                 sys.stderr.write("Couldn't match format line!\n" + line + "\n")
98                 sys.exit(1)
99         format = int(m.group(1))
100         lines[format_line] = "Format " + str(format + 1)
101
102
103 def abort(msg):
104         sys.stderr.write("\n%s\n" % (msg))
105         sys.exit(10)
106
107 #
108 ###########################################################
109
110 def usage():
111         print ("%s [-l] [-p] infile outfile" % sys.argv[0])
112         print ("or: %s [-l] [-p] <infile >outfile" % sys.argv[0])
113         print ("  -l: convert LFUNs (bind and ui files)")
114         print ("  -p: convert preferences")
115         print ("Note that exactly one of -l and -p is required.")
116
117
118 def main(argv):
119         try:
120                 (options, args) = getopt(sys.argv[1:], "lp")
121         except:
122                 usage()
123                 abort("Unrecognized option")
124
125         opened_files = False
126         # Open files
127         if len(args) == 0:
128                 source = sys.stdin
129                 output = sys.stdout
130         elif len(args) == 2:
131                 source = io.open(args[0], 'r', encoding='utf_8', errors='surrogateescape')
132                 output = io.open(args[1], 'w', encoding='utf_8', newline='\n')
133                 opened_files = True
134         else:
135                 usage()
136                 abort("Either zero or two arguments must be given.")
137
138         conversions = False
139
140         for (opt, param) in options:
141                 if opt == "-l":
142                         from prefs2prefs_lfuns import conversions
143                 elif opt == "-p":
144                         from prefs2prefs_prefs import conversions
145
146         if not conversions:
147                 usage()
148                 abort("Neither -l nor -p given.")
149         elif len(options) > 1:
150                 usage()
151                 abort("Only one of -l or -p should be given.")
152
153         current_format = len(conversions)
154         lines = read(source)
155         format = get_format(lines)
156
157         while format < current_format:
158                 target_format, convert = conversions[format]
159                 old_format = format
160
161                 # make sure the conversion list is sequential
162                 if int(old_format) + 1 != target_format:
163                         abort("Something is wrong with the conversion chain.")
164
165                 for c in convert:
166                         try:
167                                 # first see if the routine will accept a list of lines
168                                 c(lines)
169                         except:
170                                 # if not, it wants individual lines
171                                 for i in range(len(lines)):
172                                         (update, newline) = c(lines[i])
173                                         if update:
174                                                 lines[i] = newline
175
176                 update_format(lines)
177                 format = get_format(lines)
178
179                 # sanity check
180                 if int(old_format) + 1 != int(format):
181                         abort("Failed to convert to new format!")
182
183         write(output, lines)
184
185         # Close files
186         if opened_files:
187                 source.close()
188                 output.close()
189
190         return 0
191
192
193 if __name__ == "__main__":
194         main(sys.argv)