diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
index f78935ee..2fe3dd6d 100644
--- a/.idea/dictionaries/ericf.xml
+++ b/.idea/dictionaries/ericf.xml
@@ -151,15 +151,19 @@
basew
bastd
batools
+ bblk
+ bblu
bbot
bbtn
bcppcompiler
+ bcyn
bdfl
belarussian
benboncan
bfiledir
bfiles
bgmodel
+ bgrn
bgterrain
bgtex
bgthread
@@ -175,6 +179,7 @@
bldtp
blocksize
bluetooth
+ bmag
bname
bndl
boffs
@@ -217,6 +222,8 @@
buttondown
buttonwidget
bval
+ bwht
+ bylw
bytecount
byteswap
cachable
@@ -536,6 +543,7 @@
enumtype
enumval
envhash
+ envval
epath
epicfail
ericf
@@ -883,6 +891,7 @@
ipaddress
ipos
iprof
+ isatty
iscale
iserverget
iserverput
@@ -1528,8 +1537,18 @@
sandboxing
sandyrb
saxutils
+ sbblk
+ sbblu
+ sbcyn
+ sbgrn
+ sblk
+ sblu
+ sbmag
sbpos
+ sbred
sbtn
+ sbwht
+ sbylw
scenefile
scenefiles
scenename
@@ -1550,6 +1569,7 @@
scrlw
scrollw
scrollwidget
+ scyn
sdata
sdkutils
sdtk
@@ -1576,6 +1596,7 @@
setmusic
settingname
setversion
+ sgrn
shakaharu
sharedctypes
sharedobj
@@ -1595,6 +1616,7 @@
skey
sline
slval
+ smag
smlh
smtpd
smtplib
@@ -1644,6 +1666,7 @@
srcpydata
srcstr
srctxt
+ sred
sshd
sslproto
stackstr
@@ -1703,8 +1726,10 @@
sver
svne
svvv
+ swht
swip
swipsound
+ sylw
symlinked
syncable
syncall
@@ -1749,6 +1774,7 @@
tempfile
tempfilepath
templatecb
+ termcolors
termios
testbuffer
testcall
diff --git a/assets/.asset_manifest_1.json b/assets/.asset_manifest_1.json
index 8608699d..c5c5457c 100644
--- a/assets/.asset_manifest_1.json
+++ b/assets/.asset_manifest_1.json
@@ -456,6 +456,7 @@
"ba_data/python/efro/__pycache__/dataclassutils.cpython-37.opt-1.pyc",
"ba_data/python/efro/__pycache__/executils.cpython-37.opt-1.pyc",
"ba_data/python/efro/__pycache__/jsonutils.cpython-37.opt-1.pyc",
+ "ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc",
"ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc",
"ba_data/python/efro/dataclassutils.py",
"ba_data/python/efro/entity/__init__.py",
@@ -474,6 +475,7 @@
"ba_data/python/efro/entity/util.py",
"ba_data/python/efro/executils.py",
"ba_data/python/efro/jsonutils.py",
+ "ba_data/python/efro/terminal.py",
"ba_data/python/efro/util.py",
"server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc",
"server/ballisticacore_server.py"
diff --git a/assets/Makefile b/assets/Makefile
index f4eafcfa..47bab3c3 100644
--- a/assets/Makefile
+++ b/assets/Makefile
@@ -145,6 +145,7 @@ SCRIPT_TARGETS_PY_1 = \
build/server/ballisticacore_server.py \
build/ba_data/python/efro/executils.py \
build/ba_data/python/efro/dataclassutils.py \
+ build/ba_data/python/efro/terminal.py \
build/ba_data/python/efro/util.py \
build/ba_data/python/efro/__init__.py \
build/ba_data/python/efro/jsonutils.py \
@@ -386,6 +387,7 @@ SCRIPT_TARGETS_PYC_1 = \
build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc \
build/ba_data/python/efro/__pycache__/executils.cpython-37.opt-1.pyc \
build/ba_data/python/efro/__pycache__/dataclassutils.cpython-37.opt-1.pyc \
+ build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \
build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc \
build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc \
build/ba_data/python/efro/__pycache__/jsonutils.cpython-37.opt-1.pyc \
@@ -651,6 +653,11 @@ build/ba_data/python/efro/__pycache__/dataclassutils.cpython-37.opt-1.pyc: \
@echo Compiling script: $^
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \
+ build/ba_data/python/efro/terminal.py
+ @echo Compiling script: $^
+ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
+
build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \
build/ba_data/python/efro/util.py
@echo Compiling script: $^
diff --git a/assets/src/ba_data/python/efro/terminal.py b/assets/src/ba_data/python/efro/terminal.py
new file mode 100644
index 00000000..13605da5
--- /dev/null
+++ b/assets/src/ba_data/python/efro/terminal.py
@@ -0,0 +1,189 @@
+# Copyright (c) 2011-2020 Eric Froemling
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+# -----------------------------------------------------------------------------
+"""Functionality related to terminal IO."""
+from __future__ import annotations
+
+import sys
+import os
+from enum import Enum, unique
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ pass
+
+
+@unique
+class TerminalColor(Enum):
+ """Color codes for printing to terminals."""
+
+ # Styles
+ RESET = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+ INVERSE = '\033[7m'
+
+ # Normal foreground colors
+ BLACK = '\033[30m'
+ RED = '\033[31m'
+ GREEN = '\033[32m'
+ YELLOW = '\033[33m'
+ BLUE = '\033[34m'
+ MAGENTA = '\033[35m'
+ CYAN = '\033[36m'
+ WHITE = '\033[37m'
+
+ # Normal background colors.
+ BG_BLACK = '\033[40m'
+ BG_RED = '\033[41m'
+ BG_GREEN = '\033[42m'
+ BG_YELLOW = '\033[43m'
+ BG_BLUE = '\033[44m'
+ BG_MAGENTA = '\033[45m'
+ BG_CYAN = '\033[46m'
+ BG_WHITE = '\033[47m'
+
+ # Strong foreground colors
+ STRONG_BLACK = '\033[90m'
+ STRONG_RED = '\033[91m'
+ STRONG_GREEN = '\033[92m'
+ STRONG_YELLOW = '\033[93m'
+ STRONG_BLUE = '\033[94m'
+ STRONG_MAGENTA = '\033[95m'
+ STRONG_CYAN = '\033[96m'
+ STRONG_WHITE = '\033[97m'
+
+ # Strong background colors.
+ STRONG_BG_BLACK = '\033[100m'
+ STRONG_BG_RED = '\033[101m'
+ STRONG_BG_GREEN = '\033[102m'
+ STRONG_BG_YELLOW = '\033[103m'
+ STRONG_BG_BLUE = '\033[104m'
+ STRONG_BG_MAGENTA = '\033[105m'
+ STRONG_BG_CYAN = '\033[106m'
+ STRONG_BG_WHITE = '\033[107m'
+
+
+class Clr:
+ """Convenience class for color terminal output.
+
+ These will be set to ANSI color escape sequences if the current process
+ seems to be an interactive terminal (sys.__stdout__.isatty()), otherwise
+ they will be empty strings.
+ If the environment variable EFRO_TERMCOLORS is set to 0 or 1, that
+ value will be used instead.
+ """
+ _envval = os.environ.get('EFRO_TERMCOLORS')
+ color_enabled = (True if _envval == '1' else
+ False if _envval == '0' else sys.__stdout__.isatty())
+ if color_enabled:
+
+ # Styles
+ RST = TerminalColor.RESET.value
+ BLD = TerminalColor.BOLD.value
+ UND = TerminalColor.UNDERLINE.value
+ INV = TerminalColor.INVERSE.value
+
+ # Normal foreground colors
+ BLK = TerminalColor.BLACK.value
+ RED = TerminalColor.RED.value
+ GRN = TerminalColor.GREEN.value
+ YLW = TerminalColor.YELLOW.value
+ BLU = TerminalColor.BLUE.value
+ MAG = TerminalColor.MAGENTA.value
+ CYN = TerminalColor.CYAN.value
+ WHT = TerminalColor.WHITE.value
+
+ # Normal background colors.
+ BBLK = TerminalColor.BG_BLACK.value
+ BRED = TerminalColor.BG_RED.value
+ BGRN = TerminalColor.BG_GREEN.value
+ BYLW = TerminalColor.BG_YELLOW.value
+ BBLU = TerminalColor.BG_BLUE.value
+ BMAG = TerminalColor.BG_MAGENTA.value
+ BCYN = TerminalColor.BG_CYAN.value
+ BWHT = TerminalColor.BG_WHITE.value
+
+ # Strong foreground colors
+ SBLK = TerminalColor.STRONG_BLACK.value
+ SRED = TerminalColor.STRONG_RED.value
+ SGRN = TerminalColor.STRONG_GREEN.value
+ SYLW = TerminalColor.STRONG_YELLOW.value
+ SBLU = TerminalColor.STRONG_BLUE.value
+ SMAG = TerminalColor.STRONG_MAGENTA.value
+ SCYN = TerminalColor.STRONG_CYAN.value
+ SWHT = TerminalColor.STRONG_WHITE.value
+
+ # Strong background colors.
+ SBBLK = TerminalColor.STRONG_BG_BLACK.value
+ SBRED = TerminalColor.STRONG_BG_RED.value
+ SBGRN = TerminalColor.STRONG_BG_GREEN.value
+ SBYLW = TerminalColor.STRONG_BG_YELLOW.value
+ SBBLU = TerminalColor.STRONG_BG_BLUE.value
+ SBMAG = TerminalColor.STRONG_BG_MAGENTA.value
+ SBCYN = TerminalColor.STRONG_BG_CYAN.value
+ SBWHT = TerminalColor.STRONG_BG_WHITE.value
+
+ else:
+ # Styles
+ RST = ''
+ BLD = ''
+ UND = ''
+ INV = ''
+
+ # Normal foreground colors
+ BLK = ''
+ RED = ''
+ GRN = ''
+ YLW = ''
+ BLU = ''
+ MAG = ''
+ CYN = ''
+ WHT = ''
+
+ # Normal background colors.
+ BBLK = ''
+ BRED = ''
+ BGRN = ''
+ BYLW = ''
+ BBLU = ''
+ BMAG = ''
+ BCYN = ''
+ BWHT = ''
+
+ # Strong foreground colors
+ SBLK = ''
+ SRED = ''
+ SGRN = ''
+ SYLW = ''
+ SBLU = ''
+ SMAG = ''
+ SCYN = ''
+ SWHT = ''
+
+ # Strong background colors.
+ SBBLK = ''
+ SBRED = ''
+ SBGRN = ''
+ SBYLW = ''
+ SBBLU = ''
+ SBMAG = ''
+ SBCYN = ''
+ SBWHT = ''
diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py
index ed3c45c7..2f5d87e9 100755
--- a/assets/src/server/ballisticacore_server.py
+++ b/assets/src/server/ballisticacore_server.py
@@ -67,7 +67,7 @@ class ServerManagerApp:
@property
def config(self) -> ServerConfig:
- """The current config settings for the app."""
+ """The current config for the app."""
return self._config
@config.setter
diff --git a/tools/batools/build.py b/tools/batools/build.py
index 6bfae5df..65af5c05 100644
--- a/tools/batools/build.py
+++ b/tools/batools/build.py
@@ -30,13 +30,11 @@ import subprocess
from pathlib import Path
from typing import TYPE_CHECKING
+from efro.terminal import Clr
+
if TYPE_CHECKING:
from typing import List, Sequence, Optional
-CLRBLU = '\033[94m' # Blue.
-CLRHDR = '\033[95m' # Header.
-CLREND = '\033[0m' # End.
-
# Python pip packages we require for this project.
@dataclass
@@ -113,8 +111,8 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory,
def _testpath(path: str) -> bool:
# Now see this path is newer than our target..
if mtime is None or os.path.getmtime(path) >= mtime:
- print(f'{CLRHDR}Build of {tnamepretty} triggered by'
- f' {path}{CLREND}')
+ print(f'{Clr.SMAG}Build of {tnamepretty} triggered by'
+ f' {path}{Clr.RST}')
return True
return False
@@ -159,8 +157,8 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory,
if _testpath(fpath):
return True
unchanged_count += 1
- print(f'{CLRBLU}Lazybuild: skipping "{tnamepretty}"'
- f' ({unchanged_count} inputs unchanged).{CLREND}')
+ print(f'{Clr.SBLU}Lazybuild: skipping "{tnamepretty}"'
+ f' ({unchanged_count} inputs unchanged).{Clr.RST}')
return False