161 self.ui = ui |
161 self.ui = ui |
162 self.repo = repo |
162 self.repo = repo |
163 self.match = match.match(repo.root, '', [], inc, exc) |
163 self.match = match.match(repo.root, '', [], inc, exc) |
164 self.restrict = kwtools['hgcmd'] in restricted.split() |
164 self.restrict = kwtools['hgcmd'] in restricted.split() |
165 self.record = False |
165 self.record = False |
166 self.re_kw = None |
|
167 self.re_kwexp = None |
|
168 |
166 |
169 kwmaps = self.ui.configitems('keywordmaps') |
167 kwmaps = self.ui.configitems('keywordmaps') |
170 if kwmaps: # override default templates |
168 if kwmaps: # override default templates |
171 self.templates = dict((k, templater.parsestring(v, False)) |
169 self.templates = dict((k, templater.parsestring(v, False)) |
172 for k, v in kwmaps) |
170 for k, v in kwmaps) |
174 self.templates = _defaultkwmaps(self.ui) |
172 self.templates = _defaultkwmaps(self.ui) |
175 templatefilters.filters.update({'utcdate': utcdate, |
173 templatefilters.filters.update({'utcdate': utcdate, |
176 'svnisodate': svnisodate, |
174 'svnisodate': svnisodate, |
177 'svnutcdate': svnutcdate}) |
175 'svnutcdate': svnutcdate}) |
178 |
176 |
|
177 @util.propertycache |
179 def escape(self): |
178 def escape(self): |
180 '''Returns bar-separated list of keywords.''' |
179 '''Returns bar-separated and escaped keywords.''' |
181 return '|'.join(map(re.escape, self.templates.keys())) |
180 return '|'.join(map(re.escape, self.templates.keys())) |
182 |
181 |
|
182 @util.propertycache |
183 def rekw(self): |
183 def rekw(self): |
184 '''Compiles regex for unexpanded keywords on demand.''' |
184 '''Returns regex for unexpanded keywords.''' |
185 if self.re_kw is None: |
185 return re.compile(r'\$(%s)\$' % self.escape) |
186 self.re_kw = re.compile(r'\$(%s)\$' % self.escape()) |
186 |
187 return self.re_kw |
187 @util.propertycache |
188 |
|
189 def rekwexp(self): |
188 def rekwexp(self): |
190 '''Compiles regex for expanded keywords on demand.''' |
189 '''Returns regex for expanded keywords.''' |
191 if self.re_kwexp is None: |
190 return re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape) |
192 self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape()) |
|
193 return self.re_kwexp |
|
194 |
191 |
195 def substitute(self, data, path, ctx, subfunc): |
192 def substitute(self, data, path, ctx, subfunc): |
196 '''Replaces keywords in data with expanded template.''' |
193 '''Replaces keywords in data with expanded template.''' |
197 def kwsub(mobj): |
194 def kwsub(mobj): |
198 kw = mobj.group(1) |
195 kw = mobj.group(1) |
211 |
208 |
212 def expand(self, path, node, data): |
209 def expand(self, path, node, data): |
213 '''Returns data with keywords expanded.''' |
210 '''Returns data with keywords expanded.''' |
214 if not self.restrict and self.match(path) and not util.binary(data): |
211 if not self.restrict and self.match(path) and not util.binary(data): |
215 ctx = self.linkctx(path, node) |
212 ctx = self.linkctx(path, node) |
216 return self.substitute(data, path, ctx, self.rekw().sub) |
213 return self.substitute(data, path, ctx, self.rekw.sub) |
217 return data |
214 return data |
218 |
215 |
219 def iskwfile(self, cand, ctx): |
216 def iskwfile(self, cand, ctx): |
220 '''Returns subset of candidates which are configured for keyword |
217 '''Returns subset of candidates which are configured for keyword |
221 expansion are not symbolic links.''' |
218 expansion are not symbolic links.''' |
229 return |
226 return |
230 kwcmd = self.restrict and lookup # kwexpand/kwshrink |
227 kwcmd = self.restrict and lookup # kwexpand/kwshrink |
231 if self.restrict or expand and lookup: |
228 if self.restrict or expand and lookup: |
232 mf = ctx.manifest() |
229 mf = ctx.manifest() |
233 lctx = ctx |
230 lctx = ctx |
234 re_kw = (self.restrict or rekw) and self.rekw() or self.rekwexp() |
231 re_kw = (self.restrict or rekw) and self.rekw or self.rekwexp |
235 msg = (expand and _('overwriting %s expanding keywords\n') |
232 msg = (expand and _('overwriting %s expanding keywords\n') |
236 or _('overwriting %s shrinking keywords\n')) |
233 or _('overwriting %s shrinking keywords\n')) |
237 for f in candidates: |
234 for f in candidates: |
238 if self.restrict: |
235 if self.restrict: |
239 data = self.repo.file(f).read(mf[f]) |
236 data = self.repo.file(f).read(mf[f]) |
258 self.repo.dirstate.normallookup(f) |
255 self.repo.dirstate.normallookup(f) |
259 |
256 |
260 def shrink(self, fname, text): |
257 def shrink(self, fname, text): |
261 '''Returns text with all keyword substitutions removed.''' |
258 '''Returns text with all keyword substitutions removed.''' |
262 if self.match(fname) and not util.binary(text): |
259 if self.match(fname) and not util.binary(text): |
263 return _shrinktext(text, self.rekwexp().sub) |
260 return _shrinktext(text, self.rekwexp.sub) |
264 return text |
261 return text |
265 |
262 |
266 def shrinklines(self, fname, lines): |
263 def shrinklines(self, fname, lines): |
267 '''Returns lines with keyword substitutions removed.''' |
264 '''Returns lines with keyword substitutions removed.''' |
268 if self.match(fname): |
265 if self.match(fname): |
269 text = ''.join(lines) |
266 text = ''.join(lines) |
270 if not util.binary(text): |
267 if not util.binary(text): |
271 return _shrinktext(text, self.rekwexp().sub).splitlines(True) |
268 return _shrinktext(text, self.rekwexp.sub).splitlines(True) |
272 return lines |
269 return lines |
273 |
270 |
274 def wread(self, fname, data): |
271 def wread(self, fname, data): |
275 '''If in restricted mode returns data read from wdir with |
272 '''If in restricted mode returns data read from wdir with |
276 keyword substitutions removed.''' |
273 keyword substitutions removed.''' |