diff --git a/darkdraw/ansi.py b/darkdraw/ansi.py index f241e80..c2630cc 100644 --- a/darkdraw/ansi.py +++ b/darkdraw/ansi.py @@ -413,11 +413,20 @@ def _add_char(self, char: str): bg24 = self.background24 fg24 = self.foreground24 + # iCE colors: the blink bit is repurposed as "use high bg". + # Emit high bg and strip blink so it doesn't show as an attribute. + if self.icecolors and self.blink: + if bg24 == 0 and bg < 8: + bg += 8 + blink_out = False + else: + blink_out = self.blink + self.chars.append(AnsiChar( column=self.column, row=self.row, background=bg, foreground=fg, background24=bg24, foreground24=fg24, character=char, bold=self.bold, italic=self.italic, underline=self.underline, - blink=self.blink, reverse=self.invert, dim=self.dim + blink=blink_out, reverse=self.invert, dim=self.dim )) self.column += 1 @@ -538,17 +547,12 @@ def _handle_sgr(self, seq: bytes): if val == 1: self.foreground = (self.foreground % 8) + 8 self.foreground24 = 0 - elif val == 5 and self.icecolors: - self.background = (self.background % 8) + 8 - self.blink = False elif val in ATTR_OFF: for attr in ATTR_OFF[val]: setattr(self, attr, False) if val == 22 and self.foreground >= 8: self.foreground -= 8 - elif val == 25 and self.icecolors and self.background >= 8: - self.background -= 8 elif 30 <= val <= 37: self.foreground = val - 30 + (8 if self.bold else 0) @@ -558,7 +562,7 @@ def _handle_sgr(self, seq: bytes): self.foreground24 = 0 elif 40 <= val <= 47: - self.background = val - 40 + (8 if self.blink and self.icecolors else 0) + self.background = val - 40 self.background24 = 0 elif 100 <= val <= 107: self.background = val - 92 diff --git a/darkdraw/drawing.py b/darkdraw/drawing.py index 0883b9f..bc00aa8 100644 --- a/darkdraw/drawing.py +++ b/darkdraw/drawing.py @@ -9,6 +9,18 @@ from visidata import * from visidata import dispwidth, CharBox, boundingBox, asyncthread from visidata.bezier import bezier +import visidata.cliptext as _cliptext + +# Patch VisiData's _dispch to not replace modifier characters (Lm, Sk) +# with placeholders. They are legitimate drawing characters in a terminal art tool. +_orig_dispch = _cliptext._dispch.__wrapped__ +@functools.lru_cache(maxsize=100000) +def _ddw_dispch(c, oddspacech=None, combch=None, modch=None): + ccat = unicodedata.category(c) + if ccat in ('Lm', 'Sk'): + return c, dispwidth(c, literal=True) + return _orig_dispch(c, oddspacech=oddspacech, combch=combch, modch=modch) +_cliptext._dispch = _ddw_dispch vd.allPrefixes += list('01') @@ -800,7 +812,9 @@ def paste_chars(self, srcrows, box, n=None): if oldr.color and newx < box.x2 and newy < box.y2-1: for existing in self._displayedRows[(newx, newy)][-(n or 0):]: npasted += 1 + oldcolor = existing.color existing.color = oldr.color + vd.addUndo(setattr, existing, 'color', oldcolor) if npasted == 0: vd.warning(f'paste mode {self.paste_mode} had nothing to paste') @@ -873,6 +887,15 @@ def set_color(self, color, rows): r.color = color vd.addUndo(setattr, r, 'color', oldcolor) +@Drawing.api +def generate_sauce(sheet): + from .ansi import default_sauce_rows + maxX, maxY = sheet.maxXY + sheet.source.deleteBy(lambda r: (r.get('frame') or '') == 'SAUCE record') + for i, r in enumerate(default_sauce_rows(maxX, maxY)): + sheet.source.addRow(AttrDict(r), index=i) + vd.status(f'SAUCE record generated ({maxX+1}x{maxY+1})') + @Drawing.api def select_top(sheet, box): r = [] @@ -1159,6 +1182,8 @@ def box_cursor(sheet): Drawing.unbindkey('Ctrl+R') BaseSheet.addCommand(None, 'open-tutorial-darkdraw', 'vd.push(openSource(Drawing.tutorial_url))', 'Download and open DarkDraw tutorial as a DarkDraw sheet') +Drawing.addCommand(None, 'generate-sauce', 'sheet.generate_sauce()', 'generate SAUCE metadata rows for current drawing') + Drawing.addCommand('.', 'next-point', 'next_point(cursorBox.x1, cursorBox.y1)', '') Drawing.addCommand('w', 'line-drawing-mode', 'set_linedraw_mode()', '') Drawing.addCommand('BUTTON1_PRESSED', 'click-cursor', 'click(mouseX, mouseY)', 'start cursor box with left mouse button press') @@ -1171,6 +1196,7 @@ def box_cursor(sheet): Help > DarkDraw tutorial > open-tutorial-darkdraw Edit > Add text > add-input DarkDraw > New drawing > new-drawing + DarkDraw > View > Transparent background > toggle-transparent-bg DarkDraw > View > Colors sheet > open-colors DarkDraw > View > Unicode characters > open-unicode DarkDraw > View > Backing table > open-backing diff --git a/darkdraw/save_ans.py b/darkdraw/save_ans.py index 65237a7..d660dc1 100644 --- a/darkdraw/save_ans.py +++ b/darkdraw/save_ans.py @@ -48,6 +48,14 @@ def save_ans(vd, p, vs): do_sauce = vd.options.ans_sauce enc = resolve_encoding(vd.options.ans_encoding) + # Infer output params from SAUCE unless user overrides + if sauce and not vd.options.ans_ignore_sauce: + if sauce.t_info1: + cols = sauce.t_info1 + ice = bool(sauce.t_flags & 0x01) + if sauce.t_info_s.startswith('Amiga'): + enc = 'iso8859-1' + ansi_bytes = render_ansi(chars, columns=cols, use_256color=use_256, icecolors=ice, use_truecolor=use_true, encoding=enc) @@ -57,7 +65,7 @@ def save_ans(vd, p, vs): f.write(bytes([26])) if do_sauce and sauce: - file_size = len(ansi_bytes) + 1 + file_size = len(ansi_bytes) comment_block = build_comment_block(sauce.comments) sauce_block = build_sauce_block( sauce, file_size,