Browse Source

Fix #137

Unfortunately, this does not prevent "DAG zero..." from appearing
period. Rather, it just overwrites any junk printed to the console
during the export. The ANSI version is rather limited compared to the
Windows version and completely untested...
pull/152/head
Adam Johnson 5 years ago
parent
commit
b5d3f87c66
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 16
      korman/exporter/logger.py
  2. 2
      korman/korlib/__init__.py
  3. 75
      korman/korlib/console.py

16
korman/exporter/logger.py

@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>. # along with Korman. If not, see <http://www.gnu.org/licenses/>.
from ..korlib import ConsoleToggler from ..korlib import ConsoleCursor, ConsoleToggler
from .explosions import NonfatalExportError from .explosions import NonfatalExportError
from pathlib import Path from pathlib import Path
import threading import threading
@ -142,6 +142,7 @@ class ExportProgressLogger(_ExportLogger):
# because it is difficult to inspect the progress of Blender's internal operators. The best # because it is difficult to inspect the progress of Blender's internal operators. The best
# solution here is to move printing into a thread that can detect long-running ops and display # solution here is to move printing into a thread that can detect long-running ops and display
# something visible such as a moving elipsis # something visible such as a moving elipsis
self._cursor = ConsoleCursor()
self._thread = threading.Thread(target=self._progress_thread) self._thread = threading.Thread(target=self._progress_thread)
self._queued_lines = [] self._queued_lines = []
self._print_condition = threading.Condition() self._print_condition = threading.Condition()
@ -283,6 +284,8 @@ class ExportProgressLogger(_ExportLogger):
def _progress_thread(self): def _progress_thread(self):
num_dots = 0 num_dots = 0
self._cursor.update()
while self._progress_alive: while self._progress_alive:
with self._print_condition: with self._print_condition:
signalled = self._print_condition.wait(timeout=1.0) signalled = self._print_condition.wait(timeout=1.0)
@ -290,12 +293,16 @@ class ExportProgressLogger(_ExportLogger):
# First, we need to print out any queued whole lines. # First, we need to print out any queued whole lines.
# NOTE: no need to lock anything here as Blender uses CPython (GIL) # NOTE: no need to lock anything here as Blender uses CPython (GIL)
if self._queued_lines: with self._cursor:
print(*self._queued_lines, sep='\n') if self._queued_lines:
self._queued_lines.clear() print(*self._queued_lines, sep='\n')
self._queued_lines.clear()
# Now, we need to print out the current volatile line, if any. # Now, we need to print out the current volatile line, if any.
if self._volatile_line: if self._volatile_line:
# On Windows, if we clear the line, the volatile line is nuked as well.
# Probably a race condition in the Win32 console host.
self._cursor.reset()
print(self._volatile_line, end="") print(self._volatile_line, end="")
# If the proc is long running, let us display some elipses so as to not alarm the user # If the proc is long running, let us display some elipses so as to not alarm the user
@ -305,6 +312,7 @@ class ExportProgressLogger(_ExportLogger):
else: else:
num_dots = 0 num_dots = 0
print('.' * num_dots, end=" " * (_MAX_ELIPSES - num_dots)) print('.' * num_dots, end=" " * (_MAX_ELIPSES - num_dots))
self._cursor.update()
def _progress_get_current(self): def _progress_get_current(self):
return self._step_progress return self._step_progress

2
korman/korlib/__init__.py

@ -72,7 +72,7 @@ else:
from _korlib import * from _korlib import *
finally: finally:
from .console import ConsoleToggler from .console import ConsoleCursor, ConsoleToggler
from .python import * from .python import *
from .texture import TEX_DETAIL_ALPHA, TEX_DETAIL_ADD, TEX_DETAIL_MULTIPLY from .texture import TEX_DETAIL_ALPHA, TEX_DETAIL_ADD, TEX_DETAIL_MULTIPLY

75
korman/korlib/console.py

@ -18,6 +18,81 @@ import ctypes
import math import math
import sys import sys
if sys.platform == "win32":
class _Coord(ctypes.Structure):
_fields_ = [("x", ctypes.c_short),
("y", ctypes.c_short)]
class _SmallRect(ctypes.Structure):
_fields_ = [("Left", ctypes.c_short),
("Top", ctypes.c_short),
("Right", ctypes.c_short),
("Bottom", ctypes.c_short),]
class _ConsoleScreenBufferInfo(ctypes.Structure):
_fields_ = [("dwSize", _Coord),
("dwCursorPosition", _Coord),
("wAttributes", ctypes.c_ushort),
("srWindow", _SmallRect),
("dwMaximumWindowSize", _Coord)]
class _ConsoleCursor:
def __init__(self):
self._handle = ctypes.windll.kernel32.GetStdHandle(-11)
self.position = _Coord(0, 0)
def __del__(self):
ctypes.windll.kernel32.CloseHandle(self._handle)
@property
def _screen_buffer_info(self):
info = _ConsoleScreenBufferInfo()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self._handle, ctypes.pointer(info))
return info
def clear(self):
info = self._screen_buffer_info
curPos = info.dwCursorPosition
num_cols = curPos.y - self.position.y
num_rows = curPos.x - self.position.x
num_chars = (info.dwSize.x * num_cols) + num_rows
if num_chars:
nWrite = ctypes.c_ulong()
empty_char = ctypes.c_char(b' ')
ctypes.windll.kernel32.FillConsoleOutputCharacterA(self._handle, empty_char,
num_chars, self.position,
ctypes.pointer(nWrite))
def reset(self):
ctypes.windll.kernel32.SetConsoleCursorPosition(self._handle, self.position)
def update(self):
info = _ConsoleScreenBufferInfo()
ctypes.windll.kernel32.GetConsoleScreenBufferInfo(self._handle, ctypes.pointer(info))
self.position = info.dwCursorPosition
else:
class _ConsoleCursor:
def clear(self):
# Only clears the current line, unfortunately.
sys.stdout.write("\x1B[K")
def reset(self):
# Forcibly clears the line after resetting, just in case more
# than one junk line was printed from somewhere else.
sys.stdout.write("\x1B[u\x1B[K")
def update(self):
sys.stdout.write("\x1B[s")
class ConsoleCursor(_ConsoleCursor):
def __enter__(self):
self.clear()
self.reset()
return self
def __exit__(self, type, value, traceback):
self.update()
class ConsoleToggler: class ConsoleToggler:
_instance = None _instance = None

Loading…
Cancel
Save