]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/parser_tools.py
5a88da238586f78570a928a5caeca67d46565ea0
[lyx.git] / lib / lyx2lyx / parser_tools.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2002-2010 Dekel Tsur <dekel@lyx.org>, 
4 # José Matos <jamatos@lyx.org>, Richard Heck <rgheck@comcast.net>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 " This modules offer several free functions to help parse lines. "
21
22 # Utilities for one line
23 def check_token(line, token):
24     """ check_token(line, token) -> bool
25
26     Return True if token is present in line and is the first element
27     else returns False."""
28
29     return line[:len(token)] == token
30
31
32 def is_nonempty_line(line):
33     """ is_nonempty_line(line) -> bool
34
35     Return False if line is either empty or it has only whitespaces,
36     else return True."""
37     return line != " "*len(line)
38
39
40 # Utilities for a list of lines
41 def find_token(lines, token, start, end = 0, exact = False):
42     """ find_token(lines, token, start[[, end], exact]) -> int
43
44     Return the lowest line where token is found, and is the first
45     element, in lines[start, end].
46
47     Return -1 on failure."""
48
49     if end == 0 or end > len(lines):
50         end = len(lines)
51     m = len(token)
52     for i in xrange(start, end):
53         if exact:
54             x = lines[i].split()
55             y = token.split()
56             if len(x) < len(y):
57                 continue
58             if x[:len(y)] == y:
59                 return i
60         else:
61             if lines[i][:m] == token:
62                 return i
63     return -1
64
65
66 def find_token_exact(lines, token, start, end = 0):
67     return find_token(lines, token, start, end, True)
68
69
70 def find_tokens(lines, tokens, start, end = 0, exact = False):
71     """ find_tokens(lines, tokens, start[[, end], exact]) -> int
72
73     Return the lowest line where one token in tokens is found, and is
74     the first element, in lines[start, end].
75
76     Return -1 on failure."""
77     if end == 0:
78         end = len(lines)
79
80     for i in xrange(start, end):
81         for token in tokens:
82             if exact:
83                 x = lines[i].split()
84                 y = token.split()
85                 if len(x) < len(y):
86                     continue
87                 if x[:len(y)] == y:
88                     return i
89             else:
90                 if lines[i][:len(token)] == token:
91                     return i
92     return -1
93
94
95 def find_tokens_exact(lines, tokens, start, end = 0):
96     return find_tokens(lines, tokens, start, end, True)
97
98
99 def find_re(lines, rexp, start, end = 0):
100     """ find_token_re(lines, rexp, start[, end]) -> int
101
102     Return the lowest line where rexp, a regular expression, is found
103     in lines[start, end].
104
105     Return -1 on failure."""
106
107     if end == 0:
108         end = len(lines)
109     for i in xrange(start, end):
110         if rexp.match(lines[i]):
111                 return i
112     return -1
113
114
115 def find_token_backwards(lines, token, start):
116     """ find_token_backwards(lines, token, start) -> int
117
118     Return the highest line where token is found, and is the first
119     element, in lines[start, end].
120
121     Return -1 on failure."""
122     m = len(token)
123     for i in xrange(start, -1, -1):
124         line = lines[i]
125         if line[:m] == token:
126             return i
127     return -1
128
129
130 def find_tokens_backwards(lines, tokens, start):
131     """ find_tokens_backwards(lines, token, start) -> int
132
133     Return the highest line where token is found, and is the first
134     element, in lines[end, start].
135
136     Return -1 on failure."""
137     for i in xrange(start, -1, -1):
138         line = lines[i]
139         for token in tokens:
140             if line[:len(token)] == token:
141                 return i
142     return -1
143
144
145 def get_value(lines, token, start, end = 0, default = ""):
146     """ get_value(lines, token, start[[, end], default]) -> string
147
148     Find the next line that looks like:
149       token followed by other stuff
150     Returns "followed by other stuff".
151     """
152
153     i = find_token_exact(lines, token, start, end)
154     if i == -1:
155         return default
156     l = lines[i].split(None, 1)
157     if len(l) > 1:
158         return l[1]
159     return default
160
161
162 def get_value_string(lines, token, start, end = 0, trim = False, default = ""):
163     """ get_value_string(lines, token, start[[, end], trim, default]) -> string
164
165     Return tokens after token as string, in lines, where
166     token is the first element. When trim is used, the first and last character
167     of the string is trimmed."""
168
169     i = find_token_exact(lines, token, start, end)
170     if i == -1:
171         return default
172     if len(lines[i].split()) > 1:
173         for k in range (0, len(lines[i])):
174             if lines[i][k] == ' ':
175                 if trim == False:
176                     return lines[i][k+1:len(lines[i])]
177                 else:
178                     return lines[i][k+2:len(lines[i])-1]
179     else:
180         return default
181
182
183 def del_token(lines, token, start, end):
184     """ del_token(lines, token, start, end) -> int
185
186     Find the lower line in lines where token is the first element and
187     delete that line.
188
189     Returns the number of lines remaining."""
190
191     k = find_token_exact(lines, token, start, end)
192     if k == -1:
193         return end
194     else:
195         del lines[k]
196         return end - 1
197
198
199 def find_beginning_of(lines, i, start_token, end_token):
200     count = 1
201     while i > 0:
202         i = find_tokens_backwards(lines, [start_token, end_token], i-1)
203         if i == -1:
204             return -1
205         if check_token(lines[i], end_token):
206             count = count+1
207         else:
208             count = count-1
209         if count == 0:
210             return i
211     return -1
212
213
214 def find_end_of(lines, i, start_token, end_token):
215     count = 1
216     n = len(lines)
217     while i < n:
218         i = find_tokens(lines, [end_token, start_token], i+1)
219         if i == -1:
220             return -1
221         if check_token(lines[i], start_token):
222             count = count+1
223         else:
224             count = count-1
225         if count == 0:
226             return i
227     return -1
228
229
230 def find_nonempty_line(lines, start, end = 0):
231     if end == 0:
232         end = len(lines)
233     for i in xrange(start, end):
234         if is_nonempty_line(lines[i]):
235             return i
236     return -1
237
238
239 def find_end_of_inset(lines, i):
240     " Find end of inset, where lines[i] is included."
241     return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
242
243
244 def find_end_of_layout(lines, i):
245     " Find end of layout, where lines[i] is included."
246     return find_end_of(lines, i, "\\begin_layout", "\\end_layout")
247
248
249 # checks if line i is in the inset e.g., "\\begin_inset CommandInset ref"
250 # if so, returns starting and ending lines
251 # otherwise, returns (-1, -1)
252 def get_containing_inset(lines, i, inset):
253     defval = (-1, -1)
254     stins = find_token_backwards(lines, inset, i)
255     if stins == -1:
256       return defval
257     endins = find_end_of_inset(lines, stins)
258     # note that this includes the notfound case.
259     if endins < i:
260       return defval
261     return (stins, endins)