import os from method import Method, arg import buffer.colors import util import lex class VcException(Exception): pass class VcBase(Method): _is_method = False def _get_path(self, w): if not hasattr(w.buffer, 'path'): raise VcException("buffer has no path") cwd = os.getcwd() + os.path.sep path = w.buffer.path if path.startswith(cwd): path = path[len(cwd):] return path class VcBlame(Method): _is_method = False line_re = None prefix_fmt = None pretest_err_msg = None num_fields = 1 def _pretest(self): return True def _filter(self, line): m = self.line_re.match(line) if not m: raise VcException("couldn't parse %r" % line) groups = m.groups() return {'fields': groups[:-1], 'content': groups[-1], 'tokens': []} def _open_pipe(self, w, **vargs): raise Exception('unimplemented') def _build_groups(self, w, **vargs): pipe = self._open_pipe(w, **vargs) groups = [] gsizes = [0] * self.num_fields for s in pipe.stdout: line = s.decode('UTF-8') d = self._filter(line) for i in range(0, self.num_fields): gsizes[i] = max(gsizes[i], len(d['fields'][i])) groups.append(d) status = pipe.wait() >> 8 if status != 0: raise Exception("There was an error (%d)" % status) return groups, gsizes def _lex_groups(self, groups, w, **vargs): if w.mode.grammar: lexer = lex.Lexer(w.mode, w.mode.grammar) for t in lexer.lex([d['content'] for d in groups]): groups[t.y]['tokens'].append(t) def _build_lines(self, groups, gsizes, w, **vargs): self._lex_groups(groups, w, **vargs) lines = [] for d in groups: if d['tokens']: suffix = '' for t in d['tokens']: code = buffer.colors.get_cbuf_code(*t.color) suffix += code + util.cbuf_escape(t.string) else: suffix = d['content'] + '\n' tpl = tuple(util.flatzip(gsizes, d['fields'])) lines.append(self.prefix_fmt % tpl + ' ' + suffix) return lines def _execute(self, w, **vargs): if not self._pretest(): w.set_error(self.pretest_err_msg) return elif not hasattr(w.buffer, 'path'): w.set_error("Buffer has no corresponding file") return try: groups, gsizes = self._build_groups(w, **vargs) except Exception as e: w.set_error(str(e)) return data = ''.join(self._build_lines(groups, gsizes, w, **vargs)) w.application.color_data_buffer("*Blame*", data, switch_to=True) class VcRevView(Method): '''show file contents at revision''' _is_method = False namebase = 'VC' def _get_path(self, w, **vargs): cwd = os.getcwd() + os.path.sep path = w.buffer.path if path.startswith(cwd): path = path[len(cwd):] return path def _get_cmd(self, w, **vargs): path = self._get_path(w, **vargs) raise Exception("unimplemented") def _get_name(self, w, **vargs): return '*%s:%s-%s' % (self.namebase, w.buffer.name(), vargs['revision']) def _execute(self, w, **vargs): if not hasattr(w.buffer, 'path'): w.set_error("Buffer has no corresponding file") return cmd = self._get_cmd(w, **vargs) name = self._get_name(w, **vargs) mname = w.mode.name.lower() status, out, err = util.communicate(cmd) w.application.data_buffer(name, out, switch_to=True, modename=mname) class VcDateView(VcRevView): '''show file contents at date''' args = [arg("date", t=type(""), p="Date: ", h="date specifier")] def _get_name(self, w, **vargs): return '*%s:%s-%s' % (self.namebase, w.buffer.name(), vargs['date'])