:export_rank has been renamed to :export_vars as it now also exports the
[polysh.git] / gsh / display_names.py
blob1127f31bd2610848aa979d9823af87d57a2a3815
1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 # See the COPYING file for license information.
17 # Copyright (c) 2008 Guillaume Chazarain <guichaz@gmail.com>
19 from gsh.rb_tree import RBTree
21 # {'prefix': <display_name_prefix object>}
22 PREFIXES = {}
24 # Red/black tree with key:len(display_name) value:nr of enabled shells with a
25 # display_name of such a length
26 NR_ENABLED_DISPLAY_NAMES_BY_LENGTH = RBTree()
28 # Cache the right most element in the NR_ENABLED_DISPLAY_NAMES_BY_LENGTH tree
29 max_display_name_length = 0
31 class display_name_prefix(object):
32 def __init__(self):
33 self.next_suffix = 0
34 self.holes = RBTree()
36 def new_suffix(self):
37 if len(self.holes) == 0:
38 suffix = self.next_suffix
39 self.next_suffix += 1
40 else:
41 first_node = self.holes.firstNode()
42 suffix = first_node.key
43 self.holes.deleteNode(first_node)
44 return suffix
46 def putback_suffix(self, suffix):
47 if suffix + 1 != self.next_suffix:
48 self.holes.insertNode(suffix, suffix)
49 return
51 self.next_suffix = suffix
52 while True:
53 prev_suffix = self.next_suffix - 1
54 prev_suffix_node = self.holes.findNode(prev_suffix)
55 if not prev_suffix_node:
56 return
57 self.holes.deleteNode(prev_suffix_node)
58 self.next_suffix = prev_suffix
60 def empty(self):
61 return self.next_suffix == 0
63 def make_unique_name(prefix):
64 prefix_obj = PREFIXES.get(prefix, None)
65 if prefix_obj is None:
66 prefix_obj = display_name_prefix()
67 PREFIXES[prefix] = prefix_obj
69 suffix = prefix_obj.new_suffix()
70 if suffix:
71 name = '%s#%d' % (prefix, suffix)
72 else:
73 name = prefix
75 return name
77 def update_max_display_name_length():
78 from gsh import dispatchers
79 if len(NR_ENABLED_DISPLAY_NAMES_BY_LENGTH) == 0:
80 new_max = 0
81 else:
82 new_max = NR_ENABLED_DISPLAY_NAMES_BY_LENGTH.lastNode().key
83 global max_display_name_length
84 if new_max != max_display_name_length:
85 max_display_name_length = new_max
86 dispatchers.update_terminal_size()
88 def change(prev_display_name, new_prefix):
89 if new_prefix and '#' in new_prefix:
90 raise Exception('Names cannot contain #')
92 if prev_display_name is not None:
93 if new_prefix is not None:
94 set_enabled(prev_display_name, False)
95 split = prev_display_name.split('#')
96 prev_prefix = split[0]
97 if len(split) == 1:
98 prev_suffix = 0
99 else:
100 prev_suffix = int(split[1])
101 prefix_obj = PREFIXES[prev_prefix]
102 prefix_obj.putback_suffix(prev_suffix)
103 if prefix_obj.empty():
104 del PREFIXES[prev_prefix]
105 if new_prefix is None:
106 return
108 name = make_unique_name(new_prefix)
109 set_enabled(name, True)
111 return name
113 def set_enabled(display_name, enabled):
114 length = len(display_name)
115 node = NR_ENABLED_DISPLAY_NAMES_BY_LENGTH.findNode(length)
116 if enabled:
117 if node:
118 node.value += 1
119 else:
120 NR_ENABLED_DISPLAY_NAMES_BY_LENGTH.insertNode(length, 1)
121 else:
122 node.value -= 1
123 if not node.value:
124 NR_ENABLED_DISPLAY_NAMES_BY_LENGTH.deleteNode(node)
126 update_max_display_name_length()