Added support for renamed file detection in cmds.git_status()
[ugit.git] / py / utils.py
blob01c974c944b5183c44032d32fa13fa97f63a2817
1 #!/usr/bin/env python
2 import os
3 import re
4 import commands
6 KNOWN_FILE_TYPES = {
7 'ascii c': 'c.png',
8 'python': 'script.png',
9 'ruby': 'script.png',
10 'shell': 'script.png',
11 'perl': 'script.png',
12 'java': 'script.png',
13 'assembler': 'binary.png',
14 'binary': 'binary.png',
15 'byte': 'binary.png',
16 'image': 'image.png',
19 ICONSDIR = os.path.join (os.path.dirname (__file__), 'icons')
21 def ident_file_type (filename):
22 '''Returns an icon based on the contents of filename.'''
23 if os.path.exists (filename):
24 quoted_filename = shell_quote (filename)
25 fileinfo = commands.getoutput('file -b %s' % quoted_filename)
26 for filetype, iconname in KNOWN_FILE_TYPES.iteritems():
27 if filetype in fileinfo.lower():
28 return iconname
29 else:
30 return 'removed.png'
31 # Fallback for modified files of an unknown type
32 return 'generic.png'
34 def get_icon (filename):
35 '''Returns the full path to an icon file corresponding to
36 filename's contents.'''
37 icon_file = ident_file_type (filename)
38 return os.path.join (ICONSDIR, icon_file)
40 def get_staged_icon (filename):
41 '''Special-case method for staged items. These are only
42 ever 'staged' and 'removed' items in the staged list.'''
44 if os.path.exists (filename):
45 return os.path.join (ICONSDIR, 'staged.png')
46 else:
47 return os.path.join (ICONSDIR, 'removed.png')
49 def get_untracked_icon():
50 return os.path.join (ICONSDIR, 'untracked.png')
52 def get_directory_icon():
53 return os.path.join (ICONSDIR, 'dir.png')
55 def get_file_icon():
56 return os.path.join (ICONSDIR, 'generic.png')
58 def shell_quote (*inputs):
59 '''Quote strings so that they can be suitably martialled
60 off to the shell. This method supports POSIX sh syntax.
61 This is crucial to properly handle command line arguments
62 with spaces, quotes, double-quotes, etc.'''
64 regex = re.compile ('[^\w!%+,\-./:@^]')
65 quote_regex = re.compile ("((?:'\\''){2,})")
67 ret = []
68 for input in inputs:
69 if not input:
70 continue
72 if '\x00' in input:
73 raise AssertionError, ('No way to quote strings '
74 'containing null (\\000) bytes')
76 # = does need quoting else in command position it's a
77 # program-local environment setting
78 match = regex.search (input)
79 if match:
80 # ' -> '\''
81 input = input.replace ("'", "'\\''")
83 # make multiple ' in a row look simpler
84 # '\'''\'''\'' -> '"'''"'
85 quote_match = quote_regex.match (input)
86 if quote_match:
87 quotes = match.group (1)
88 input.replace (quotes,
89 ("'" * (len(quotes)/4)) + "\"'")
91 input = "'%s'" % input
92 if input.startswith ("''"):
93 input = input.lstrip ("''")
95 if input.endswith ("''"):
96 input = input.rstrip ("''")
97 ret.append (input)
98 return ' '.join (ret)
100 ANSI_BACKGROUND_COLOR = '41'
101 ANSI_TABLE = {
102 '1': 'grey',
103 '30': 'black',
104 '31': 'red',
105 '32': 'green',
106 '33': 'yellow',
107 '34': 'blue',
108 '35': 'magenta',
109 '36': 'cyan',
110 '37': 'white',
113 def ansi_to_html (ansi):
114 '''Converts a block of ANSI text into an equivalent html fragment.'''
116 html = []
117 regex = re.compile ('(.*?)\x1b\[(\d*)m')
119 for line in ansi.split ('\n'):
121 linecopy = html_encode(line)
122 match = regex.match (linecopy)
123 tagged = False
125 while match:
126 start, end = match.span()
128 prefix = match.group (1)
129 middle = match.group (2)
130 postfix = linecopy[end:]
132 if middle in ANSI_TABLE:
133 color = ANSI_TABLE[middle]
134 middle = '<span style="color: %s">' % color
135 tagged = True
137 elif middle == ANSI_BACKGROUND_COLOR:
138 middle = '<span style="background-color:red">'
139 tagged = True
141 else:
142 if tagged:
143 middle = '</span>'
144 else:
145 middle = ''
147 linecopy = prefix + middle + postfix
148 match = regex.match (linecopy)
150 html.append (linecopy)
152 return '<br/>'.join (html)
154 def html_header (header):
155 return '''
156 <p style="color: black;
157 background-color: yellow">
159 </p>''' % header
161 def html_encode (ascii):
162 '''HTML-encodes text. This method explicitly avoids encoding
163 alphanumeric and ANSI-escape sequences.'''
165 html = []
166 for char in ascii:
167 if char.isalnum():
168 html.append (char)
170 elif char == '\t':
171 # There is no HTML equivalent to a tab, so just
172 # insert eight spaces
173 html.append ( '&nbsp;' * 8 )
175 elif char == '\x1b' or char == '[':
176 # Don't encode ANSI characters since these
177 # are stripped out during ansi_to_html
178 html.append (char)
180 else:
181 html.append (ENTITIES[char])
183 return ''.join (html)
185 # Keep this at the bottom of the file since it's generated output.
186 # Generated by html2py.pl from HTML::Entities on Wed Dec 5 16:28:55 PST 2007
187 ENTITIES = {
188 chr(0) : '&#0;',
189 chr(1) : '&#1;',
190 chr(2) : '&#2;',
191 chr(3) : '&#3;',
192 chr(4) : '&#4;',
193 chr(5) : '&#5;',
194 chr(6) : '&#6;',
195 chr(7) : '&#7;',
196 chr(8) : '&#8;',
197 chr(9) : '&#9;',
198 chr(10) : '&#10;',
199 chr(11) : '&#11;',
200 chr(12) : '&#12;',
201 chr(13) : '&#13;',
202 chr(14) : '&#14;',
203 chr(15) : '&#15;',
204 chr(16) : '&#16;',
205 chr(17) : '&#17;',
206 chr(18) : '&#18;',
207 chr(19) : '&#19;',
208 chr(20) : '&#20;',
209 chr(21) : '&#21;',
210 chr(22) : '&#22;',
211 chr(23) : '&#23;',
212 chr(24) : '&#24;',
213 chr(25) : '&#25;',
214 chr(26) : '&#26;',
215 chr(27) : '&#27;',
216 chr(28) : '&#28;',
217 chr(29) : '&#29;',
218 chr(30) : '&#30;',
219 chr(31) : '&#31;',
220 chr(32) : '&#32;',
221 chr(33) : '&#33;',
222 chr(34) : '&quot;',
223 chr(35) : '&#35;',
224 chr(36) : '&#36;',
225 chr(37) : '&#37;',
226 chr(38) : '&amp;',
227 chr(39) : '&#39;',
228 chr(40) : '&#40;',
229 chr(41) : '&#41;',
230 chr(42) : '&#42;',
231 chr(43) : '&#43;',
232 chr(44) : '&#44;',
233 chr(45) : '&#45;',
234 chr(46) : '&#46;',
235 chr(47) : '&#47;',
236 chr(48) : '&#48;',
237 chr(49) : '&#49;',
238 chr(50) : '&#50;',
239 chr(51) : '&#51;',
240 chr(52) : '&#52;',
241 chr(53) : '&#53;',
242 chr(54) : '&#54;',
243 chr(55) : '&#55;',
244 chr(56) : '&#56;',
245 chr(57) : '&#57;',
246 chr(58) : '&#58;',
247 chr(59) : '&#59;',
248 chr(60) : '&lt;',
249 chr(61) : '&#61;',
250 chr(62) : '&gt;',
251 chr(63) : '&#63;',
252 chr(64) : '&#64;',
253 chr(65) : '&#65;',
254 chr(66) : '&#66;',
255 chr(67) : '&#67;',
256 chr(68) : '&#68;',
257 chr(69) : '&#69;',
258 chr(70) : '&#70;',
259 chr(71) : '&#71;',
260 chr(72) : '&#72;',
261 chr(73) : '&#73;',
262 chr(74) : '&#74;',
263 chr(75) : '&#75;',
264 chr(76) : '&#76;',
265 chr(77) : '&#77;',
266 chr(78) : '&#78;',
267 chr(79) : '&#79;',
268 chr(80) : '&#80;',
269 chr(81) : '&#81;',
270 chr(82) : '&#82;',
271 chr(83) : '&#83;',
272 chr(84) : '&#84;',
273 chr(85) : '&#85;',
274 chr(86) : '&#86;',
275 chr(87) : '&#87;',
276 chr(88) : '&#88;',
277 chr(89) : '&#89;',
278 chr(90) : '&#90;',
279 chr(91) : '&#91;',
280 chr(92) : '&#92;',
281 chr(93) : '&#93;',
282 chr(94) : '&#94;',
283 chr(95) : '&#95;',
284 chr(96) : '&#96;',
285 chr(97) : '&#97;',
286 chr(98) : '&#98;',
287 chr(99) : '&#99;',
288 chr(100) : '&#100;',
289 chr(101) : '&#101;',
290 chr(102) : '&#102;',
291 chr(103) : '&#103;',
292 chr(104) : '&#104;',
293 chr(105) : '&#105;',
294 chr(106) : '&#106;',
295 chr(107) : '&#107;',
296 chr(108) : '&#108;',
297 chr(109) : '&#109;',
298 chr(110) : '&#110;',
299 chr(111) : '&#111;',
300 chr(112) : '&#112;',
301 chr(113) : '&#113;',
302 chr(114) : '&#114;',
303 chr(115) : '&#115;',
304 chr(116) : '&#116;',
305 chr(117) : '&#117;',
306 chr(118) : '&#118;',
307 chr(119) : '&#119;',
308 chr(120) : '&#120;',
309 chr(121) : '&#121;',
310 chr(122) : '&#122;',
311 chr(123) : '&#123;',
312 chr(124) : '&#124;',
313 chr(125) : '&#125;',
314 chr(126) : '&#126;',
315 chr(127) : '&#127;',
316 chr(128) : '&#128;',
317 chr(129) : '&#129;',
318 chr(130) : '&#130;',
319 chr(131) : '&#131;',
320 chr(132) : '&#132;',
321 chr(133) : '&#133;',
322 chr(134) : '&#134;',
323 chr(135) : '&#135;',
324 chr(136) : '&#136;',
325 chr(137) : '&#137;',
326 chr(138) : '&#138;',
327 chr(139) : '&#139;',
328 chr(140) : '&#140;',
329 chr(141) : '&#141;',
330 chr(142) : '&#142;',
331 chr(143) : '&#143;',
332 chr(144) : '&#144;',
333 chr(145) : '&#145;',
334 chr(146) : '&#146;',
335 chr(147) : '&#147;',
336 chr(148) : '&#148;',
337 chr(149) : '&#149;',
338 chr(150) : '&#150;',
339 chr(151) : '&#151;',
340 chr(152) : '&#152;',
341 chr(153) : '&#153;',
342 chr(154) : '&#154;',
343 chr(155) : '&#155;',
344 chr(156) : '&#156;',
345 chr(157) : '&#157;',
346 chr(158) : '&#158;',
347 chr(159) : '&#159;',
348 chr(160) : '&nbsp;',
349 chr(161) : '&iexcl;',
350 chr(162) : '&cent;',
351 chr(163) : '&pound;',
352 chr(164) : '&curren;',
353 chr(165) : '&yen;',
354 chr(166) : '&brvbar;',
355 chr(167) : '&sect;',
356 chr(168) : '&uml;',
357 chr(169) : '&copy;',
358 chr(170) : '&ordf;',
359 chr(171) : '&laquo;',
360 chr(172) : '&not;',
361 chr(173) : '&shy;',
362 chr(174) : '&reg;',
363 chr(175) : '&macr;',
364 chr(176) : '&deg;',
365 chr(177) : '&plusmn;',
366 chr(178) : '&sup2;',
367 chr(179) : '&sup3;',
368 chr(180) : '&acute;',
369 chr(181) : '&micro;',
370 chr(182) : '&para;',
371 chr(183) : '&middot;',
372 chr(184) : '&cedil;',
373 chr(185) : '&sup1;',
374 chr(186) : '&ordm;',
375 chr(187) : '&raquo;',
376 chr(188) : '&frac14;',
377 chr(189) : '&frac12;',
378 chr(190) : '&frac34;',
379 chr(191) : '&iquest;',
380 chr(192) : '&Agrave;',
381 chr(193) : '&Aacute;',
382 chr(194) : '&Acirc;',
383 chr(195) : '&Atilde;',
384 chr(196) : '&Auml;',
385 chr(197) : '&Aring;',
386 chr(198) : '&AElig;',
387 chr(199) : '&Ccedil;',
388 chr(200) : '&Egrave;',
389 chr(201) : '&Eacute;',
390 chr(202) : '&Ecirc;',
391 chr(203) : '&Euml;',
392 chr(204) : '&Igrave;',
393 chr(205) : '&Iacute;',
394 chr(206) : '&Icirc;',
395 chr(207) : '&Iuml;',
396 chr(208) : '&ETH;',
397 chr(209) : '&Ntilde;',
398 chr(210) : '&Ograve;',
399 chr(211) : '&Oacute;',
400 chr(212) : '&Ocirc;',
401 chr(213) : '&Otilde;',
402 chr(214) : '&Ouml;',
403 chr(215) : '&times;',
404 chr(216) : '&Oslash;',
405 chr(217) : '&Ugrave;',
406 chr(218) : '&Uacute;',
407 chr(219) : '&Ucirc;',
408 chr(220) : '&Uuml;',
409 chr(221) : '&Yacute;',
410 chr(222) : '&THORN;',
411 chr(223) : '&szlig;',
412 chr(224) : '&agrave;',
413 chr(225) : '&aacute;',
414 chr(226) : '&acirc;',
415 chr(227) : '&atilde;',
416 chr(228) : '&auml;',
417 chr(229) : '&aring;',
418 chr(230) : '&aelig;',
419 chr(231) : '&ccedil;',
420 chr(232) : '&egrave;',
421 chr(233) : '&eacute;',
422 chr(234) : '&ecirc;',
423 chr(235) : '&euml;',
424 chr(236) : '&igrave;',
425 chr(237) : '&iacute;',
426 chr(238) : '&icirc;',
427 chr(239) : '&iuml;',
428 chr(240) : '&eth;',
429 chr(241) : '&ntilde;',
430 chr(242) : '&ograve;',
431 chr(243) : '&oacute;',
432 chr(244) : '&ocirc;',
433 chr(245) : '&otilde;',
434 chr(246) : '&ouml;',
435 chr(247) : '&divide;',
436 chr(248) : '&oslash;',
437 chr(249) : '&ugrave;',
438 chr(250) : '&uacute;',
439 chr(251) : '&ucirc;',
440 chr(252) : '&uuml;',
441 chr(253) : '&yacute;',
442 chr(254) : '&thorn;',
443 chr(255) : '&yuml;',