1
2 '''
3 # DESCRIPTION:
4 # Text formatting and colouring tools
5
6 Copyright 1998-2004 Gentoo Foundation
7 # $Id: output.py 4906 2006-11-01 23:55:29Z zmedico $
8 Copyright (C) 2007-2008 Fabio Erculiani
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 '''
24
25 import sys, os
26 import curses
27 from entropy.const import etpUi
28 from entropy.exceptions import IncorrectParameter
29 from entropy.i18n import _
30 stuff = {}
31 stuff['cols'] = 30
32 try:
33 curses.setupterm()
34 stuff['cols'] = curses.tigetnum('cols')
35 except:
36 pass
37 stuff['cleanline'] = ""
39 stuff['cleanline'] = ""
40 count = stuff['cols']
41 while count:
42 stuff['cleanline'] += ' '
43 count -= 1
44 setcols()
45 stuff['cursor'] = False
46 stuff['ESC'] = chr(27)
47
48 havecolor=1
49 global dotitles
50 dotitles=1
51
52 esc_seq = "\x1b["
53
54 g_attr = {}
55 g_attr["normal"] = 0
56
57 g_attr["bold"] = 1
58 g_attr["faint"] = 2
59 g_attr["standout"] = 3
60 g_attr["underline"] = 4
61 g_attr["blink"] = 5
62 g_attr["overline"] = 6
63 g_attr["reverse"] = 7
64 g_attr["invisible"] = 8
65
66 g_attr["no-attr"] = 22
67 g_attr["no-standout"] = 23
68 g_attr["no-underline"] = 24
69 g_attr["no-blink"] = 25
70 g_attr["no-overline"] = 26
71 g_attr["no-reverse"] = 27
72
73
74 g_attr["black"] = 30
75 g_attr["red"] = 31
76 g_attr["green"] = 32
77 g_attr["yellow"] = 33
78 g_attr["blue"] = 34
79 g_attr["magenta"] = 35
80 g_attr["cyan"] = 36
81 g_attr["white"] = 37
82
83 g_attr["default"] = 39
84 g_attr["bg_black"] = 40
85 g_attr["bg_red"] = 41
86 g_attr["bg_green"] = 42
87 g_attr["bg_yellow"] = 43
88 g_attr["bg_blue"] = 44
89 g_attr["bg_magenta"] = 45
90 g_attr["bg_cyan"] = 46
91 g_attr["bg_white"] = 47
92 g_attr["bg_default"] = 49
93
94
95
96 -def color(fg, bg="default", attr=["normal"]):
97 mystr = esc_seq[:] + "%02d" % g_attr[fg]
98 for x in [bg]+attr:
99 mystr += ";%02d" % g_attr[x]
100 return mystr+"m"
101
102
103
104 codes={}
105 codes["reset"] = esc_seq + "39;49;00m"
106
107 codes["bold"] = esc_seq + "01m"
108 codes["faint"] = esc_seq + "02m"
109 codes["standout"] = esc_seq + "03m"
110 codes["underline"] = esc_seq + "04m"
111 codes["blink"] = esc_seq + "05m"
112 codes["overline"] = esc_seq + "06m"
113
114 ansi_color_codes = []
115 for x in xrange(30, 38):
116 ansi_color_codes.append("%im" % x)
117 ansi_color_codes.append("%i;01m" % x)
118
119 rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00',
120 '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA',
121 '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF']
122
123 for x in xrange(len(rgb_ansi_colors)):
124 codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x]
125
126 del x
127
128 codes["black"] = codes["0x000000"]
129 codes["darkgray"] = codes["0x555555"]
130
131 codes["red"] = codes["0xFF5555"]
132 codes["darkred"] = codes["0xAA0000"]
133
134 codes["green"] = codes["0x55FF55"]
135 codes["darkgreen"] = codes["0x00AA00"]
136
137 codes["yellow"] = codes["0xFFFF55"]
138 codes["brown"] = codes["0xAA5500"]
139
140 codes["blue"] = codes["0x5555FF"]
141 codes["darkblue"] = codes["0x0000AA"]
142
143 codes["fuchsia"] = codes["0xFF55FF"]
144 codes["purple"] = codes["0xAA00AA"]
145
146 codes["turquoise"] = codes["0x55FFFF"]
147 codes["teal"] = codes["0x00AAAA"]
148
149 codes["white"] = codes["0xFFFFFF"]
150 codes["lightgray"] = codes["0xAAAAAA"]
151
152 codes["darkteal"] = codes["turquoise"]
153 codes["darkyellow"] = codes["brown"]
154 codes["fuscia"] = codes["fuchsia"]
155 codes["white"] = codes["bold"]
156
157
158 codes["GOOD"] = codes["green"]
159 codes["WARN"] = codes["yellow"]
160 codes["BAD"] = codes["red"]
161 codes["HILITE"] = codes["teal"]
162 codes["BRACKET"] = codes["blue"]
163
164
165 codes["INFORM"] = codes["darkgreen"]
166 codes["UNMERGE_WARN"] = codes["red"]
167 codes["MERGE_LIST_PROGRESS"] = codes["yellow"]
168
170 if dotitles and "TERM" in os.environ and sys.stderr.isatty():
171 myt=os.environ["TERM"]
172 legal_terms = ["xterm","Eterm","aterm","rxvt","screen","kterm","rxvt-unicode","gnome"]
173 if myt in legal_terms:
174 if not raw:
175 mystr = "\x1b]0;%s\x07" % mystr
176 try:
177 sys.stderr.write(mystr)
178 except UnicodeEncodeError:
179 sys.stderr.write(mystr.encode('utf-8'))
180 sys.stderr.flush()
181
182 default_xterm_title = None
183
203
208
210 "turn off colorization"
211 os.environ['ETP_NO_COLOR'] = "1"
212 global havecolor
213 havecolor=0
214
215 nc = os.getenv("ETP_NO_COLOR")
216 if nc:
217 nocolor()
218
220 return codes["reset"]
221
229
232
235
238
241
244
247
250
253
256
259
262
265
268
271
274
277
280
282 def derived_func(*args):
283 newargs = list(args)
284 newargs.insert(0, color_key)
285 return colorize(*newargs)
286 return derived_func
287
289 out = atom.split("/")
290 return blue(out[0])+"/"+red(out[1])
291
293 if args == None:
294 args = []
295
296 def orig_myfunc(x):
297 return x
298 def orig_myfunc_desc(x):
299 return x
300
301 try:
302 i = args.index("--help")
303 del args[i]
304 command = args.pop(0)
305 except ValueError:
306 command = None
307 except IndexError:
308 command = None
309 section_found = False
310 search_depth = 1
311
312
313 for item in data:
314 myfunc = orig_myfunc
315 myfunc_desc = orig_myfunc_desc
316
317 if not item:
318 if command == None or section_found:
319 writechar("\n")
320 else:
321 n_ident = item[0]
322 name = item[1]
323 n_d_ident = item[2]
324 desc = item[3]
325 if command != None:
326
327 if name == command and n_ident == search_depth:
328 try:
329 command = args.pop(0)
330 search_depth = n_ident + 1
331 except IndexError:
332 command = "##unused_from_now_on"
333 section_found = True
334 indent_level = n_ident
335 elif section_found:
336 if n_ident <= indent_level:
337 return
338 else:
339 continue
340
341 if n_ident == 0:
342 writechar(" ")
343
344 while n_ident > 0:
345 n_ident -= 1
346 writechar("\t")
347 n_ident = item[0]
348
349
350 if n_ident == 0:
351 myfunc = darkgreen
352 elif n_ident == 1:
353 myfunc = blue
354 myfunc_desc = darkgreen
355 elif n_ident == 2:
356 if not name.startswith("--"):
357 myfunc = red
358 myfunc_desc = brown
359 elif n_ident == 3:
360 myfunc = darkblue
361 myfunc_desc = purple
362 try:
363 print myfunc(name),
364 except UnicodeEncodeError:
365 print myfunc(name.encode('utf-8')),
366
367
368 if desc:
369 while n_d_ident > 0:
370 n_d_ident -= 1
371 writechar("\t")
372 try:
373 print myfunc_desc(desc),
374 except UnicodeEncodeError:
375 print myfunc_desc(desc.encode('utf-8')),
376 writechar("\n")
377
382
386
406
426
428 if etpUi['mute']:
429 return
430 if not back:
431 setcols()
432 reset_cursor()
433 writechar("\r")
434 if back:
435 try:
436 print red(">>"),msg,
437 except UnicodeEncodeError:
438 print red(">>"),msg.encode('utf-8'),
439 else:
440 try:
441 print red(">>"),msg
442 except UnicodeEncodeError:
443 print red(">>"),msg.encode('utf-8')
444 if flush:
445 flush_stdouterr()
446
448 if etpUi['mute']:
449 return
450 writechar("\r")
451 try:
452 print msg
453 except UnicodeEncodeError:
454 print msg.encode('utf-8')
455 flush_stdouterr()
456
458 if etpUi['mute']:
459 return
460 try:
461 sys.stdout.write(char)
462 sys.stdout.flush()
463 except IOError, e:
464 if e.errno == 32:
465 return
466 raise
467
468 -def readtext(request, password = False):
469 xtermTitle(_("Entropy needs your attention"))
470 if password:
471 from getpass import getpass
472 try:
473 text = getpass(request+" ")
474 except UnicodeEncodeError:
475 text = getpass(request.encode('utf-8')+" ")
476 else:
477 try:
478 print request,"",
479 except UnicodeEncodeError:
480 print request.encode('utf-8'),"",
481 flush_stdouterr()
482 text = my_raw_input()
483 return text
484
499
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523 - def updateProgress(self, text, header = "", footer = "", back = False, importance = 0, type = "info", count = [], percent = False):
524 if (etpUi['quiet']) or (etpUi['mute']):
525 return
526
527 flush_stdouterr()
528
529 myfunc = print_info
530 if type == "warning":
531 myfunc = print_warning
532 elif type == "error":
533 myfunc = print_error
534
535 count_str = ""
536 if count:
537 if len(count) > 1:
538 if percent:
539 count_str = " ("+str(round((float(count[0])/count[1])*100,1))+"%) "
540 else:
541 count_str = " (%s/%s) " % (red(str(count[0])),blue(str(count[1])),)
542 if importance == 0:
543 myfunc(header+count_str+text+footer, back = back, flush = False)
544 elif importance == 1:
545 myfunc(header+count_str+text+footer, back = back, flush = False)
546 elif importance in (2,3):
547 myfunc(header+count_str+text+footer, back = back, flush = False)
548
549 flush_stdouterr()
550
551
552
553
554
555
556
557
558
559
560
561 - def askQuestion(self, question, importance = 0, responses = ["Yes","No"]):
562
563 colours = [green, red, blue, darkgreen, darkred, darkblue, brown, purple]
564 colours += colours[:]
565 if len(responses) > len(colours):
566 raise IncorrectParameter("IncorrectParameter: %s = %s" % (_("maximum responses length"),len(colours),))
567 try:
568 print darkgreen(question),
569 except UnicodeEncodeError:
570 print darkgreen(question.encode('utf-8')),
571 flush_stdouterr()
572 try:
573 while True:
574 xtermTitle(_("Entropy got a question for you"))
575 flush_stdouterr()
576 response = my_raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
577 flush_stdouterr()
578 for key in responses:
579
580 if response.upper() == key[:len(response)].upper():
581 xtermTitleReset()
582 return key
583 '''
584 try:
585 print "%s '%s'" % (_("I cannot understand"),response,),
586 except UnicodeEncodeError:
587 print "%s '%s'" % (_("I cannot understand"),response.encode('utf-8'),),
588 '''
589 flush_stdouterr()
590 except (EOFError, KeyboardInterrupt):
591 print "%s." % (_("Interrupted"),)
592 xtermTitleReset()
593 raise SystemExit(100)
594 xtermTitleReset()
595 flush_stdouterr()
596
597 '''
598 @ title: title of the input box
599 @ input_parameters: [
600 ('identifier 1','input text 1',input_verification_callback,False),
601 ('password','Password',input_verification_callback,True),
602 ('item_3',('checkbox','Checkbox option (boolean request) - please choose',),input_verification_callback,True),
603 ('item_4',('combo',('Select your favorite option',['option 1', 'option 2', 'option 3']),),input_verification_callback,True),
604 ('item_4',('list',('Setup your list',['default list item 1', 'default list item 2']),),input_verification_callback,True)
605 ]
606 @ cancel_button: show cancel button ?
607 @ output: dictionary as follows:
608 {'identifier 1': result, 'identifier 2': result}
609 '''
610 - def inputBox(self, title, input_parameters, cancel_button = True):
611 results = {}
612 if title:
613 try:
614 print title
615 except UnicodeEncodeError:
616 print title.encode('utf-8')
617 flush_stdouterr()
618
619 def option_chooser(option_data):
620 mydict = {}
621 counter = 1
622 option_text, option_list = option_data
623 self.updateProgress(option_text)
624 for item in option_list:
625 mydict[counter] = item
626 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),)
627 self.updateProgress(txt)
628 counter += 1
629 while 1:
630 myresult = readtext("%s:" % (_('Selected number'),)).decode('utf-8')
631 try:
632 myresult = int(myresult)
633 except ValueError:
634 continue
635 selected = mydict.get(myresult)
636 if selected != None:
637 return myresult, selected
638
639 def list_editor(option_data, can_cancel, callback):
640
641 def selaction():
642 self.updateProgress('')
643 self.updateProgress(darkred(_("Please select an option")))
644 if can_cancel:
645 self.updateProgress(" ("+blue("-1")+") "+darkred(_("Discard all")))
646 self.updateProgress(" ("+blue("0")+") "+darkgreen(_("Confirm")))
647 self.updateProgress(" ("+blue("1")+") "+brown(_("Add item")))
648 self.updateProgress(" ("+blue("2")+") "+darkblue(_("Remove item")))
649 self.updateProgress(" ("+blue("3")+") "+darkgreen(_("Show current list")))
650
651 self.updateProgress('')
652 action = readtext(darkgreen(_("Your choice (type a number and press enter):"))+" ")
653 return action
654
655 mydict = {}
656 counter = 1
657 valid_actions = [0,1,2,3]
658 if can_cancel: valid_actions.insert(0,-1)
659 option_text, option_list = option_data
660 txt = "%s:" % (blue(option_text),)
661 self.updateProgress(txt)
662
663 for item in option_list:
664 mydict[counter] = item
665 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),)
666 self.updateProgress(txt)
667 counter += 1
668
669 def show_current_list():
670 for key in sorted(mydict):
671 txt = "[%s] %s" % (darkgreen(str(key)), blue(mydict[key]),)
672 self.updateProgress(txt)
673
674 while 1:
675 try:
676 action = int(selaction())
677 except (ValueError,TypeError,):
678 self.updateProgress(_("You don't have typed a number."), type = "warning")
679 continue
680 if action not in valid_actions:
681 self.updateProgress(_("Invalid action."), type = "warning")
682 continue
683 if action == -1:
684 raise KeyboardInterrupt
685 elif action == 0:
686 break
687 elif action == 1:
688 while 1:
689 try:
690 s_el = readtext(darkred(_("String to add:"))+" ")
691 if not callback(s_el):
692 raise ValueError
693 mydict[counter] = s_el
694 counter += 1
695 except (ValueError,):
696 self.updateProgress(_("Invalid string."), type = "warning")
697 continue
698 break
699 show_current_list()
700 continue
701 elif action == 2:
702 while 1:
703 try:
704 s_el = int(readtext(darkred(_("Element number to remove:"))+" "))
705 if s_el not in mydict:
706 raise ValueError
707 del mydict[s_el]
708 except (ValueError,TypeError,):
709 self.updateProgress(_("Invalid element."), type = "warning")
710 continue
711 break
712 show_current_list()
713 continue
714 elif action == 3:
715 show_current_list()
716 continue
717 break
718
719 mylist = [mydict[x] for x in sorted(mydict)]
720 return mylist
721
722 for identifier, input_text, callback, password in input_parameters:
723 while 1:
724 use_cb = True
725 try:
726 if isinstance(input_text,tuple):
727 myresult = False
728 input_type, data = input_text
729 if input_type == "checkbox":
730 answer = self.askQuestion(data)
731 if answer == "Yes": myresult = True
732 elif input_type == "combo":
733 myresult = option_chooser(data)
734 elif input_type == "list":
735 use_cb = False
736 myresult = list_editor(data, cancel_button, callback)
737 else:
738 myresult = readtext(input_text+":", password = password).decode('utf-8')
739 except (KeyboardInterrupt,EOFError,):
740 if not cancel_button:
741 continue
742 return None
743 valid = True
744 if use_cb:
745 valid = callback(myresult)
746 if valid:
747 results[identifier] = myresult
748 break
749 return results
750
751
752
753 - def cycleDone(self):
755
756 - def setTitle(self, title):
758
759 - def setTotalCycles(self, total):
761
764
767
768 - def notitles(self):
770