5050 from .unix_console import UnixConsole as Console , _error
5151
5252ENCODING = sys .getdefaultencoding () or "latin1"
53+ _EDITLINE_MARKER = "_HiStOrY_V2_"
54+ _EDITLINE_BYTES_MARKER = b"_HiStOrY_V2_"
5355
5456
5557# types
6062TYPE_CHECKING = False
6163
6264if TYPE_CHECKING :
63- from typing import Any , Mapping
65+ from typing import Any , IO , Mapping
6466
6567
6668MoreLinesCallable = Callable [[str ], bool ]
@@ -425,6 +427,19 @@ def set_history_length(self, length: int) -> None:
425427 def get_current_history_length (self ) -> int :
426428 return len (self .get_reader ().history )
427429
430+ @staticmethod
431+ def _analyze_history_file (filename : str | IO [bytes ]) -> tuple [bool , str ]:
432+ if isinstance (filename , str ):
433+ if not os .path .exists (filename ):
434+ return False , "utf-8"
435+ with open (filename , "rb" ) as f :
436+ is_editline = f .readline ().startswith (_EDITLINE_BYTES_MARKER )
437+ else :
438+ is_editline = f .readline ().startswith (_EDITLINE_BYTES_MARKER )
439+ if is_editline :
440+ return True , "unicode-escape"
441+ return False , "utf-8"
442+
428443 def read_history_file (self , filename : str = gethistoryfile ()) -> None :
429444 # multiline extension (really a hack) for the end of lines that
430445 # are actually continuations inside a single multiline_input()
@@ -433,12 +448,9 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None:
433448 history = self .get_reader ().history
434449
435450 with open (os .path .expanduser (filename ), 'rb' ) as f :
436- is_editline = f .readline ().startswith (b"_HiStOrY_V2_" )
437- if is_editline :
438- encoding = "unicode-escape"
439- else :
451+ is_editline , encoding = self ._analyze_history_file (f )
452+ if not is_editline :
440453 f .seek (0 )
441- encoding = "utf-8"
442454
443455 lines = [line .decode (encoding , errors = 'replace' ) for line in f .read ().split (b'\n ' )]
444456 buffer = []
@@ -457,9 +469,12 @@ def read_history_file(self, filename: str = gethistoryfile()) -> None:
457469 def write_history_file (self , filename : str = gethistoryfile ()) -> None :
458470 maxlength = self .saved_history_length
459471 history = self .get_reader ().get_trimmed_history (maxlength )
460- f = open (os .path .expanduser (filename ), "w" ,
461- encoding = "utf-8" , newline = "\n " )
462- with f :
472+
473+ filename = os .path .expanduser (filename )
474+ is_editline , encoding = self ._analyze_history_file (filename )
475+ with open (filename , "w" , encoding = encoding , newline = "\n " ) as f :
476+ if is_editline :
477+ f .write (f"{ _EDITLINE_MARKER } \n " )
463478 for entry in history :
464479 entry = entry .replace ("\n " , "\r \n " ) # multiline history support
465480 f .write (entry + "\n " )
@@ -469,9 +484,10 @@ def append_history_file(self, filename: str = gethistoryfile()) -> None:
469484 saved_length = self .get_history_length ()
470485 length = self .get_current_history_length () - saved_length
471486 history = reader .get_trimmed_history (length )
472- f = open (os .path .expanduser (filename ), "a" ,
473- encoding = "utf-8" , newline = "\n " )
474- with f :
487+
488+ filename = os .path .expanduser (filename )
489+ _ , encoding = self ._analyze_history_file (filename )
490+ with open (filename , "a" , encoding = encoding , newline = "\n " ) as f :
475491 for entry in history :
476492 entry = entry .replace ("\n " , "\r \n " ) # multiline history support
477493 f .write (entry + "\n " )
0 commit comments