40. Design a Text Editor with cursor operations

Design a Text Editor with cursor operations
Design an in-memory Notepad text editor that stores text as lines and maintains a cursor.
Support cursor movement, reading the current line.

Cursor & Document Model

  • Document is a sequence of lines (no embedded \n inside a line).
  • Cursor is identified by (row, col), both 0-based.
  • Initially: Document is a list of strings. Each string represents a single line.
    cursor is at (0, 0).
  • When cursor moves to previous or next line in move letf, right, up or down then it tries to move to same column it currently is.
    But if next line has fewer characters then cursor simply moves to next right column after last character of next line.

Methods

Class: NotepadEditor

  • NotepadEditor(List <String> lines, int linesPerPage)
    create editor with given page size (lines per page).
    Each string in lines represents a single line of text in the document.
  • void moveLeft()
    move cursor one position left.
  • void moveRight()
    move cursor one position right.

    moveLeft() / moveRight() move within a line.
    if cursor is at 0th column, then moveLeft() will do nothing.
    If cursor is after rightmost character then moveRight() will do nothing.
    Cursor will never move to next line.
  • void moveUp()
    move cursor one line up, trying to keep preferred column.
  • void moveDown()
    move cursor one line down, trying to keep preferred column. If there is no row below then do nothing.

    moveUp() / moveDown() move to previous/next line while trying to keep the cursor's current column, or at end if next line is shorter.
  • void pageUp()
    move cursor up by up to linesPerPage lines.
    If there are not enough lines above, then cursor will remain at its existing place.
  • void pageDown()
    move cursor down by up to linesPerPage lines.
    if there are not enough rows below then cursor will remain at its existing place.
  • readLeft()
    • Returns characters from 0 till cursor's column-1 from the line where the cursor currently is.
    • If the logical line is shorter than cursor's column, then return text from 0 till last character in line.

Example

Example 1: basic horizontal movement and readLeft.

NotepadEditor ed = new NotepadEditor(
    Arrays.asList("hello", "world"),
    2   // linesPerPage
);
Initial:
  lines  = ["hello", "world"]
  cursor = (0,0)   at 'h' of "hello"

ed.moveRight();   // cursor -> (0,1)
ed.moveRight();   // cursor -> (0,2)
ed.moveRight();   // cursor -> (0,3) between 'l' and 'l'

String s1 = ed.readLeft();   // "hel"
// readLeft returns characters from index 0 up to (cursorCol - 1).

ed.moveLeft();    // cursor -> (0,2)
ed.moveLeft();    // cursor -> (0,1)

String s2 = ed.readLeft();   // "h"
// Only characters strictly to the left of the cursor are returned.

------------------------------------------------------------
Example 2: moving between lines of different lengths.

NotepadEditor ed = new NotepadEditor(
    Arrays.asList("hi", "world"),
    2
);
Initial:
  row 0: "hi"
  row 1: "world"
  cursor = (0,0)

ed.moveDown();    // move to same column (0) on next line
                  // cursor -> (1,0) at 'w' of "world"

// Move to the end of "world"
ed.moveRight();   // cursor -> (1,1)
ed.moveRight();   // cursor -> (1,2)
ed.moveRight();   // cursor -> (1,3)
ed.moveRight();   // cursor -> (1,4)
ed.moveRight();   // cursor -> (1,5) just after "world"

String sWorld = ed.readLeft();   // "world"

ed.moveUp();      // try to keep column 5 on previous line "hi"
                  // "hi" has length 2, so cursor moves just after 'i'
                  // cursor -> (0,2)

String sHi = ed.readLeft();      // "hi"
// When moving between lines, if the target line is shorter than the
// current column, the cursor lands just after the last character,
// and readLeft returns the entire line.

------------------------------------------------------------
Example 3: pageDown with enough rows below.

NotepadEditor ed = new NotepadEditor(
    Arrays.asList("short", "world", "hi", "there"),
    2   // linesPerPage
);
Initial:
  row 0: "short"
  row 1: "world"
  row 2: "hi"
  row 3: "there"
  cursor = (0,0)

ed.moveRight();   // cursor -> (0,1)
ed.moveRight();   // cursor -> (0,2)
ed.moveRight();   // cursor -> (0,3)

ed.pageDown();    // try to move down by 2 lines (linesPerPage)
                  // There are enough rows below, so:
                  //   from row 0 -> row 2, trying to keep column 3.
                  // row 2 is "hi" (length 2), so cursor moves just after 'i'
                  // cursor -> (2,2)

String s3 = ed.readLeft();       // "hi"

------------------------------------------------------------
Example 4: pageUp / pageDown with insufficient rows is a no-op.

NotepadEditor ed = new NotepadEditor(
    Arrays.asList("aaa", "bbbb"),
    3   // linesPerPage
);
Initial:
  row 0: "aaa"
  row 1: "bbbb"
  cursor = (0,0)

// Move cursor to the end of the second line:
ed.moveDown();    // cursor -> (1,0)
ed.moveRight();   // cursor -> (1,1)
ed.moveRight();   // cursor -> (1,2)
ed.moveRight();   // cursor -> (1,3)
ed.moveRight();   // cursor -> (1,4) just after "bbbb"

String sStart = ed.readLeft();   // "bbbb"

ed.pageDown();   // wants to move 3 lines down from row 1.
                 // There are no rows below row 1, so cursor does not move.

String sAfterDown = ed.readLeft();   // still "bbbb"

ed.pageUp();     // wants to move 3 lines up from row 1.
                 // There is only 1 row above, not enough for a full page jump,
                 // so cursor again does nothing.

String sAfterUp = ed.readLeft();     // still "bbbb"




Please use Laptop/Desktop or any other large screen to add/edit code.