1 # win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users
3 # Copyright 2005, 2007-2009 Matt Mackall <mpm@selenic.com> and others
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
8 '''perform automatic newline conversion
10 To perform automatic newline conversion, use::
22 If not doing conversion, to make sure you do not commit CRLF/CR by accident::
25 pretxncommit.crlf = python:hgext.win32text.forbidcrlf
26 # or pretxncommit.cr = python:hgext.win32text.forbidcr
28 To do the same check on a server to prevent CRLF/CR from being
32 pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
33 # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
36 from mercurial.i18n import _
37 from mercurial.node import short
38 from mercurial import util
41 # regexp for single LF without CR preceding.
42 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
44 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
45 filterstr = {'\r\n': 'clever', '\r': 'mac'}
47 def checknewline(s, newline, ui=None, repo=None, filename=None):
48 # warn if already has 'newline' in repository.
49 # it might cause unexpected eol conversion.
51 # http://mercurial.selenic.com/bts/issue302
52 if newline in s and ui and filename and repo:
53 ui.warn(_('WARNING: %s already has %s line endings\n'
54 'and does not need EOL conversion by the win32text plugin.\n'
55 'Before your next commit, please reconsider your '
56 'encode/decode settings in \nMercurial.ini or %s.\n') %
57 (filename, newlinestr[newline], repo.join('hgrc')))
59 def dumbdecode(s, cmd, **kwargs):
60 checknewline(s, '\r\n', **kwargs)
61 # replace single LF to CRLF
62 return re_single_lf.sub('\\1\r\n', s)
64 def dumbencode(s, cmd):
65 return s.replace('\r\n', '\n')
67 def macdumbdecode(s, cmd, **kwargs):
68 checknewline(s, '\r', **kwargs)
69 return s.replace('\n', '\r')
71 def macdumbencode(s, cmd):
72 return s.replace('\r', '\n')
74 def cleverdecode(s, cmd, **kwargs):
75 if not util.binary(s):
76 return dumbdecode(s, cmd, **kwargs)
79 def cleverencode(s, cmd):
80 if not util.binary(s):
81 return dumbencode(s, cmd)
84 def macdecode(s, cmd, **kwargs):
85 if not util.binary(s):
86 return macdumbdecode(s, cmd, **kwargs)
89 def macencode(s, cmd):
90 if not util.binary(s):
91 return macdumbencode(s, cmd)
95 'dumbdecode:': dumbdecode,
96 'dumbencode:': dumbencode,
97 'cleverdecode:': cleverdecode,
98 'cleverencode:': cleverencode,
99 'macdumbdecode:': macdumbdecode,
100 'macdumbencode:': macdumbencode,
101 'macdecode:': macdecode,
102 'macencode:': macencode,
105 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
108 # we try to walk changesets in reverse order from newest to
109 # oldest, so that if we see a file multiple times, we take the
110 # newest version as canonical. this prevents us from blocking a
111 # changegroup that contains an unacceptable commit followed later
112 # by a commit that fixes the problem.
114 for rev in xrange(len(repo)-1, repo[node].rev()-1, -1):
117 if f in seen or f not in tip or f not in c:
121 if not util.binary(data) and newline in data:
123 ui.warn(_('Attempt to commit or push text file(s) '
124 'using %s line endings\n') %
126 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
128 if halt and hooktype == 'pretxnchangegroup':
129 crlf = newlinestr[newline].lower()
130 filter = filterstr[newline]
131 ui.warn(_('\nTo prevent this mistake in your local repository,\n'
132 'add to Mercurial.ini or .hg/hgrc:\n'
135 'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
137 'and also consider adding:\n'
140 'hgext.win32text =\n'
144 '** = %sdecode:\n') % (crlf, crlf, filter, filter))
147 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
148 return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs)
150 def forbidcr(ui, repo, hooktype, node, **kwargs):
151 return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs)
153 def reposetup(ui, repo):
156 for name, fn in _filters.iteritems():
157 repo.adddatafilter(name, fn)