Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
Upcoming (TBD)
==============

Bug Fixes
---------
* Don't write ANSI prompt escapes to `tee` output.


Internal
---------
* Avoid refreshing the prompt unless needed.


1.58.0 (2026/02/28)
==============

Expand Down
11 changes: 9 additions & 2 deletions mycli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ def __init__(
self.my_cnf['mysqld'] = {}
prompt_cnf = self.read_my_cnf(self.my_cnf, ["prompt"])["prompt"]
self.prompt_format = prompt or prompt_cnf or c["main"]["prompt"] or self.default_prompt
self.prompt_lines = 0
self.multiline_continuation_char = c["main"]["prompt_continuation"]
self.prompt_app = None
self.destructive_keywords = [
Expand Down Expand Up @@ -918,7 +919,10 @@ def get_prompt_message(app) -> ANSI:
prompt = self.get_prompt(self.prompt_format)
if self.prompt_format == self.default_prompt and len(prompt) > self.max_len_prompt:
prompt = self.get_prompt(self.default_prompt_splitln)
self.prompt_lines = prompt.count('\n') + 1
prompt = prompt.replace("\\x1b", "\x1b")
if not self.prompt_lines:
self.prompt_lines = prompt.count('\n') + 1
self.last_prompt_message = ANSI(prompt)
return self.last_prompt_message

Expand Down Expand Up @@ -1160,7 +1164,8 @@ def one_iteration(text: str | None = None) -> None:
try:
logger.debug("sql: %r", text)

special.write_tee(self.get_prompt(self.prompt_format) + text)
special.write_tee(self.last_prompt_message, nl=False)
special.write_tee(text)
self.log_query(text)

successful = False
Expand Down Expand Up @@ -1372,7 +1377,9 @@ def bell(self) -> None:
def get_output_margin(self, status: str | None = None) -> int:
"""Get the output margin (number of rows for the prompt, footer and
timing message."""
margin = self.get_reserved_space() + self.get_prompt(self.prompt_format).count("\n") + 1
if not self.prompt_lines:
self.prompt_lines = self.get_prompt(self.prompt_format).count('\n') + 1
margin = self.get_reserved_space() + self.prompt_lines
if special.is_timing_enabled():
margin += 1
if status:
Expand Down
13 changes: 8 additions & 5 deletions mycli/packages/special/iocommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import click
from configobj import ConfigObj
from prompt_toolkit.formatted_text import ANSI, FormattedText, to_plain_text
from pymysql.cursors import Cursor
import pyperclip
import sqlparse
Expand Down Expand Up @@ -435,12 +436,14 @@ def no_tee(arg: str, **_) -> list[SQLResult]:
return [SQLResult(status="")]


def write_tee(output: str) -> None:
def write_tee(output: str | ANSI | FormattedText, nl: bool = True) -> None:
global tee_file
if tee_file:
click.echo(output, file=tee_file, nl=False)
click.echo("\n", file=tee_file, nl=False)
tee_file.flush()
if not tee_file:
return
click.echo(to_plain_text(output), file=tee_file, nl=False)
if nl:
click.echo('\n', file=tee_file, nl=False)
tee_file.flush()


@special_command("\\once", "\\once [-o] <filename>", "Append next result to an output file (overwrite using -o).", aliases=["\\o"])
Expand Down