Class DefaultHistory

java.lang.Object
org.jline.reader.impl.history.DefaultHistory
All Implemented Interfaces:
Iterable<History.Entry>, History

public class DefaultHistory extends Object implements History
Default implementation of History with file-based persistent storage.

This class provides a complete implementation of the History interface with the following features:

  • In-memory storage of history entries with configurable size limits
  • Persistent storage in a text file with configurable location and size limits
  • Support for timestamped history entries
  • Filtering of entries based on patterns defined in the LineReader.HISTORY_IGNORE variable
  • Options to ignore duplicates, reduce blanks, and ignore commands starting with spaces
  • Incremental saving of history entries
  • History navigation (previous/next, first/last, etc.)

The history file format is either plain text with one command per line, or if LineReader.Option.HISTORY_TIMESTAMPED is set, each line starts with a timestamp in milliseconds since epoch, followed by a colon and the command text.

Applications using this class should install a shutdown hook to call save() to ensure history is saved to disk when the application exits.

Example usage:

 LineReader reader = LineReaderBuilder.builder()
     .variable(LineReader.HISTORY_FILE, Paths.get(System.getProperty("user.home"), ".myapp_history"))
     .build();
 // History is automatically attached to the reader

 // To save history manually:
 ((DefaultHistory) reader.getHistory()).save();
 
See Also:
  • Field Details

  • Constructor Details

    • DefaultHistory

      public DefaultHistory()
      Creates a new DefaultHistory instance.
    • DefaultHistory

      public DefaultHistory(LineReader reader)
      Creates a new DefaultHistory instance and attaches it to the specified LineReader.
      Parameters:
      reader - the LineReader to attach to
  • Method Details

    • getPath

      private Path getPath()
    • attach

      public void attach(LineReader reader)
      Attaches this history to a LineReader.

      This method associates the history with a LineReader and loads the history from the file specified by the LineReader.HISTORY_FILE variable. If the history is already attached to the given reader, this method does nothing.

      Specified by:
      attach in interface History
      Parameters:
      reader - the LineReader to attach this history to
    • load

      public void load() throws IOException
      Loads history from the file specified by the LineReader.HISTORY_FILE variable.

      This method clears the current history and loads entries from the history file. If the file doesn't exist or can't be read, the history will be cleared. If individual lines in the history file are malformed, they will be skipped.

      Specified by:
      load in interface History
      Throws:
      IOException - if an I/O error occurs while reading the history file
    • read

      public void read(Path file, boolean checkDuplicates) throws IOException
      Reads history entries from the specified file and adds them to the current history.

      Unlike load(), this method does not clear the existing history before adding entries from the file. If the file doesn't exist or can't be read, the history will be cleared. If individual lines in the history file are malformed, they will be skipped.

      Specified by:
      read in interface History
      Parameters:
      file - the file to read history from, or null to use the default history file
      checkDuplicates - whether to check for and skip duplicate entries
      Throws:
      IOException - if an I/O error occurs while reading the history file
    • doHistoryFileDataKey

      private String doHistoryFileDataKey(Path path)
    • getHistoryFileData

      private DefaultHistory.HistoryFileData getHistoryFileData(Path path)
    • setHistoryFileData

      private void setHistoryFileData(Path path, DefaultHistory.HistoryFileData historyFileData)
    • isLineReaderHistory

      private boolean isLineReaderHistory(Path path) throws IOException
      Throws:
      IOException
    • setLastLoaded

      private void setLastLoaded(Path path, int lastloaded)
    • setEntriesInFile

      private void setEntriesInFile(Path path, int entriesInFile)
    • incEntriesInFile

      private void incEntriesInFile(Path path, int amount)
    • getLastLoaded

      private int getLastLoaded(Path path)
    • getEntriesInFile

      private int getEntriesInFile(Path path)
    • addHistoryLine

      protected void addHistoryLine(Path path, String line)
      Adds a history line to the specified history file.
      Parameters:
      path - the path to the history file
      line - the line to add
    • addHistoryLine

      protected void addHistoryLine(Path path, String line, boolean checkDuplicates)
      Adds a history line to the specified history file with an option to check for duplicates.
      Parameters:
      path - the path to the history file
      line - the line to add
      checkDuplicates - whether to check for duplicate entries
    • purge

      public void purge() throws IOException
      Clears the history and deletes the history file.

      This method removes all history entries from memory and deletes the history file if it exists.

      Specified by:
      purge in interface History
      Throws:
      IOException - if an I/O error occurs while deleting the history file
    • write

      public void write(Path file, boolean incremental) throws IOException
      Writes the history to the specified file, optionally replacing the existing file.

      If the file exists, it will be deleted and recreated. If incremental is true, only entries that haven't been saved before will be written.

      Specified by:
      write in interface History
      Parameters:
      file - the file to write history to, or null to use the default history file
      incremental - whether to write only new entries (true) or all entries (false)
      Throws:
      IOException - if an I/O error occurs while writing the history file
    • append

      public void append(Path file, boolean incremental) throws IOException
      Appends history entries to the specified file.

      Unlike write(Path, boolean), this method does not delete the existing file before writing. If incremental is true, only entries that haven't been saved before will be appended.

      Specified by:
      append in interface History
      Parameters:
      file - the file to append history to, or null to use the default history file
      incremental - whether to append only new entries (true) or all entries (false)
      Throws:
      IOException - if an I/O error occurs while appending to the history file
    • save

      public void save() throws IOException
      Saves the history to the default history file.

      This method appends any new history entries (those that haven't been saved before) to the history file. It's typically called when the application exits to ensure that history is preserved.

      Specified by:
      save in interface History
      Throws:
      IOException - if an I/O error occurs while saving the history file
    • internalWrite

      private void internalWrite(Path path, int from) throws IOException
      Throws:
      IOException
    • createWithOwnerOnlyPermissions

      private static void createWithOwnerOnlyPermissions(Path path) throws IOException
      Creates the history file restricted to the owner when it does not exist yet. History lines can contain secrets typed on the command line, so the file must not be left group/world readable as the umask default (0644) would. On non-POSIX filesystems the file is created with the platform default.
      Throws:
      IOException
    • warnIfAccessibleByOthers

      private static void warnIfAccessibleByOthers(Path path)
      Warns, at most once per path, when an existing history file is accessible by users other than the owner. The file's permissions are left untouched so as not to surprise the user.
    • trimHistory

      protected void trimHistory(Path path, int max) throws IOException
      Trims the history file to the specified maximum number of entries.
      Parameters:
      path - the path to the history file
      max - the maximum number of entries to keep
      Throws:
      IOException - if an I/O error occurs
    • createEntry

      protected DefaultHistory.EntryImpl createEntry(int index, Instant time, String line)
      Create a history entry. Subclasses may override to use their own entry implementations.
      Parameters:
      index - index of history entry
      time - entry creation time
      line - the entry text
      Returns:
      entry object
    • internalClear

      private void internalClear()
    • doTrimHistory

      static List<History.Entry> doTrimHistory(List<History.Entry> allItems, int max)
    • size

      public int size()
      Description copied from interface: History
      Returns the number of items in the history.
      Specified by:
      size in interface History
      Returns:
      the number of history items
    • isEmpty

      public boolean isEmpty()
      Description copied from interface: History
      Checks if the history is empty.
      Specified by:
      isEmpty in interface History
      Returns:
      true if the history contains no items
    • index

      public int index()
      Description copied from interface: History
      Returns the current index in the history.
      Specified by:
      index in interface History
      Returns:
      the current index
    • first

      public int first()
      Description copied from interface: History
      Returns the index of the first element in the history.
      Specified by:
      first in interface History
      Returns:
      the index of the first history item
    • last

      public int last()
      Description copied from interface: History
      Returns the index of the last element in the history.
      Specified by:
      last in interface History
      Returns:
      the index of the last history item
    • format

      private String format(History.Entry entry)
    • get

      public String get(int index)
      Description copied from interface: History
      Returns the history item at the specified index.
      Specified by:
      get in interface History
      Parameters:
      index - the index of the history item to retrieve
      Returns:
      the history item at the specified index
    • add

      public void add(Instant time, String line)
      Adds a new entry to the history.

      This method adds a new entry to the history with the specified timestamp and command text. The entry may be filtered based on various criteria such as:

      If LineReader.Option.HISTORY_INCREMENTAL is set, the history will be saved to disk after adding the entry.

      Specified by:
      add in interface History
      Parameters:
      time - the timestamp for the new entry
      line - the command text for the new entry
      Throws:
      NullPointerException - if time or line is null
    • matchPatterns

      protected boolean matchPatterns(String patterns, String line)
      Checks if a line matches any of the specified patterns.
      Parameters:
      patterns - the patterns to match against, separated by '|'
      line - the line to check
      Returns:
      true if the line matches any of the patterns
    • internalAdd

      protected void internalAdd(Instant time, String line)
      Adds a line to the history with the specified timestamp.
      Parameters:
      time - the timestamp for the history entry
      line - the line to add
    • internalAdd

      protected void internalAdd(Instant time, String line, boolean checkDuplicates)
      Adds a line to the history with the specified timestamp and an option to check for duplicates.
      Parameters:
      time - the timestamp for the history entry
      line - the line to add
      checkDuplicates - whether to check for duplicate entries
    • maybeResize

      private void maybeResize()
    • iterator

      public ListIterator<History.Entry> iterator(int index)
      Description copied from interface: History
      Returns a list iterator over the history entries starting at the specified index.
      Specified by:
      iterator in interface History
      Parameters:
      index - the index to start iterating from
      Returns:
      a list iterator over the history entries
    • spliterator

      public Spliterator<History.Entry> spliterator()
      Specified by:
      spliterator in interface Iterable<History.Entry>
    • resetIndex

      public void resetIndex()
      Description copied from interface: History
      Reset index after remove
      Specified by:
      resetIndex in interface History
    • moveToLast

      public boolean moveToLast()
      Moves the history cursor to the last entry.

      This positions the cursor at the most recent history entry, which is one position before the position set by moveToEnd(). This is typically used when starting to navigate backward through history.

      Specified by:
      moveToLast in interface History
      Returns:
      true if the cursor was moved, false if there were no history entries or the cursor was already at the last entry
    • moveTo

      public boolean moveTo(int index)
      Moves the history cursor to the specified index.

      This positions the cursor at the history entry with the given index, if it exists. The index is absolute, taking into account the offset of the history buffer.

      Specified by:
      moveTo in interface History
      Parameters:
      index - the absolute index to move to
      Returns:
      true if the cursor was moved, false if the index was out of range
    • moveToFirst

      public boolean moveToFirst()
      Moves the history cursor to the first entry.

      This positions the cursor at the oldest history entry in the buffer. This is typically used when starting to navigate forward through history.

      Specified by:
      moveToFirst in interface History
      Returns:
      true if the cursor was moved, false if there were no history entries or the cursor was already at the first entry
    • moveToEnd

      public void moveToEnd()
      Moves the history cursor to the end of the history buffer.

      This positions the cursor after the last history entry, which represents the current input line (not yet in history). This is the default position when not navigating through history.

      Specified by:
      moveToEnd in interface History
    • current

      public String current()
      Returns the text of the history entry at the current cursor position.

      If the cursor is at the end of the history (after the last entry), this method returns an empty string.

      Specified by:
      current in interface History
      Returns:
      the text of the current history entry, or an empty string if at the end
    • previous

      public boolean previous()
      Moves the history cursor to the previous (older) entry.

      This is typically called when the user presses the up arrow key to navigate backward through history. If the cursor is already at the first entry, this method does nothing and returns false.

      Specified by:
      previous in interface History
      Returns:
      true if the cursor was moved, false if already at the first entry
    • next

      public boolean next()
      Moves the history cursor to the next (newer) entry.

      This is typically called when the user presses the down arrow key to navigate forward through history. If the cursor is already at the end of history, this method does nothing and returns false.

      Specified by:
      next in interface History
      Returns:
      true if the cursor was moved, false if already at the end of history
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • escape

      private static String escape(String s)
    • unescape

      static String unescape(String s)