Skip to content

Commit 3f1deda

Browse files
committed
Minor fixes to the 'sp list' command output.
Added new core.table module for future use (Thanks to @Ayuto for creating this functionality).
1 parent 10ceccf commit 3f1deda

File tree

2 files changed

+213
-4
lines changed

2 files changed

+213
-4
lines changed

Diff for: addons/source-python/packages/source-python/core/command.py

+18-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from core import core_logger
1717
from core import dumps
1818
from core.manager import core_plugin_manager
19+
# Cvars
20+
from cvars import ConVar
1921
# Engines
2022
from engines.server import engine_server
2123
# Paths
@@ -61,7 +63,7 @@ def print_plugins(self):
6163
'Plugins'].get_string() + '\n' + '=' * 61 + '\n\n'
6264

6365
# Loop through all loaded plugins
64-
for plugin in self.manager:
66+
for plugin in sorted(self.manager):
6567

6668
# Set info to None before retrieving it
6769
info = None
@@ -88,10 +90,19 @@ def print_plugins(self):
8890
message += plugin + ':\n'
8991

9092
# Loop through all items in the PluginInfo instance
91-
for item in info:
93+
for item, value in info.items():
94+
95+
# Is the value a ConVar?
96+
if isinstance(value, ConVar):
97+
98+
# Get the
99+
value = '{0}:\n\t\t\t{1}: {2}'.format(
100+
value.get_name(),
101+
value.get_help_text(),
102+
value.get_string())
92103

93104
# Add message for the current item and its value
94-
message += '\t{0}:\n\t\t{1}\n'.format(item, info[item])
105+
message += '\t{0}:\n\t\t{1}\n'.format(item, value)
95106

96107
# Was no PluginInfo instance found?
97108
else:
@@ -100,7 +111,10 @@ def print_plugins(self):
100111
message += plugin + '\n'
101112

102113
# Add 1 blank line between each plugin
103-
message += '\n' + '=' * 61
114+
message += '\n'
115+
116+
# Add the ending separator
117+
message += '=' * 61
104118

105119
# Print the message
106120
self.logger.log_message(message)
+195
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# ../core/table.py
2+
3+
"""Provides an object oriented way to print out tables."""
4+
5+
# =============================================================================
6+
# >> IMPORTS
7+
# =============================================================================
8+
# Python Imports
9+
# Enum
10+
from enum import Enum
11+
# Itertools
12+
from itertools import zip_longest
13+
14+
15+
# =============================================================================
16+
# >> ALL DECLARATION
17+
# =============================================================================
18+
__all__ = ('Alignment',
19+
'AsciiTable',
20+
'Column',
21+
'Item',
22+
)
23+
24+
25+
# =============================================================================
26+
# >> CLASSES
27+
# =============================================================================
28+
class Alignment(Enum):
29+
30+
"""Contains constants to specify the aligment of table items."""
31+
32+
LEFT = str.ljust
33+
RIGHT = str.rjust
34+
CENTER = str.center
35+
36+
37+
class Column(list):
38+
39+
"""Represents a column of a table."""
40+
41+
def __init__(
42+
self, name, alignment=Alignment.CENTER,
43+
left_padding=2, right_padding=2):
44+
"""Intialize the column.
45+
46+
@param <name>:
47+
Name of the column.
48+
49+
@param <alignment>:
50+
The alignment of the column name.
51+
52+
@param <left_padding>:
53+
Number of spaces for left padding.
54+
55+
@param <right_padding>:
56+
Number of spaces for right padding.
57+
"""
58+
self.name = Item(name, alignment)
59+
self.left_padding = left_padding
60+
self.right_padding = right_padding
61+
62+
def _get_max_padding(self):
63+
"""Return the length of the longest item in the column.
64+
65+
The name of the column is used to determine the length, as well.
66+
"""
67+
length = len(self.name)
68+
if not self:
69+
return length
70+
71+
return max(len(max(self, key=len)), length)
72+
73+
def _format(self):
74+
"""Return the name of the column and all items of the column.
75+
76+
All items (including the name) will be
77+
formatted properly before being returned.
78+
"""
79+
padding = self._get_max_padding()
80+
return (self.name._format(
81+
padding, self.left_padding, self.right_padding), tuple(
82+
item._format(padding, self.left_padding, self.right_padding)
83+
for item in self))
84+
85+
86+
class Item(object):
87+
88+
"""Represents a value/item of a column."""
89+
90+
def __init__(self, value, alignment=Alignment.LEFT):
91+
"""Initialize the item.
92+
93+
@param <value>:
94+
The value this item should have.
95+
96+
@param <aligment>:
97+
The aligment of the item in the table.
98+
"""
99+
self.value = str(value)
100+
self.alignment = alignment
101+
102+
def __len__(self):
103+
"""Return the length of the value."""
104+
return len(self.value)
105+
106+
def _format(self, padding, left_padding, right_padding):
107+
"""Format the item.
108+
109+
@param <padding>:
110+
The length of the longest item in the column.
111+
112+
@param <left_padding>:
113+
A number that defines how many spaces should be added to the left of
114+
the item.
115+
116+
@param <right_padding>:
117+
A number that defines how many spaces should be added to the right of
118+
the item.
119+
"""
120+
return '{0}{1}{2}'.format(
121+
' ' * left_padding, self.alignment(self.value, padding),
122+
' ' * right_padding)
123+
124+
125+
class AsciiTable(object):
126+
127+
"""Represents a table."""
128+
129+
def __init__(self, *columns):
130+
"""Add the given objects as columns to the table.
131+
132+
If a given column is not a Column object, it will be created.
133+
"""
134+
if len(columns) == 0:
135+
raise ValueError('Table must have at least one column.')
136+
137+
self._columns = []
138+
for column in columns:
139+
if not isinstance(column, Column):
140+
column = Column(column)
141+
142+
self._columns.append(column)
143+
144+
def __len__(self):
145+
"""Return the number of columns."""
146+
return len(self._columns)
147+
148+
def __iter__(self):
149+
"""Return an iterator for all columns."""
150+
return iter(self._columns)
151+
152+
def __getitem__(self, index):
153+
"""Return the column at the given index."""
154+
return self._columns[index]
155+
156+
def add_row(self, *items):
157+
"""Append the given items to the table's columns."""
158+
if len(items) != len(self):
159+
raise ValueError(
160+
'You must add exactly the same number of items' +
161+
' like the number of columns.')
162+
163+
for index, item in enumerate(items):
164+
if not isinstance(item, Item):
165+
item = Item(item)
166+
167+
self[index].append(item)
168+
169+
def format(self, header_separator='=', column_separator='|'):
170+
"""Format the table and returns an ASCII table string.
171+
172+
@param <header_separator>:
173+
A single character that defines the character that should be used to
174+
create the horizontal separator.
175+
176+
@param <column_separator>:
177+
A single character that defines the character that should be used to
178+
create the vertical separators.
179+
"""
180+
if not isinstance(header_separator, str) or len(header_separator) != 1:
181+
raise ValueError('Header separator must be a single character.')
182+
183+
columns = []
184+
rows = []
185+
for column in self:
186+
column, row = column._format()
187+
columns.append(column)
188+
rows.append(row)
189+
190+
header = column_separator.join(columns)
191+
return '{0}\n{1}\n{2}'.format(
192+
header,
193+
header_separator * len(header),
194+
'\n'.join(column_separator.join(row) for row in zip_longest(
195+
*rows, fillvalue='')))

0 commit comments

Comments
 (0)