JNotes is a simple text editor I'm developing to explore the challenges that arise when building something seemingly simple, like a text editor without using builtin textbox components. The inspiration for this project came from Austin Z. Henley's article, Challenging projects every programmer should try, which highlights various data structures I might use and other interesting key concepts.
- Enter and edit text.
- Insert new lines.
- Delete characters to the left or right of the cursor.
- Navigate the cursor using arrow keys (up, down, left, right).
- Highlight text in any direction from the cursor.
- Jump the cursor to the start or end of a line.
- Highlight text from the cursor to the start or end of a line.
- Undo and redo actions.
- Save, Save As and Open file.
- Show lines number.
The first naive approach I've used to handle the logic for sequential characters insertion, deletion, cursor movement and adding new lines was to use an ArrayList. However, it wasn't efficient for character insertion and deletion as, in the worst case scenario, the operation would take O(n) time complexity.
The final approach that I've decided to use is to implement a GapBuffer data structure which reduces the time complexity of insertion and deletion to O(1). This data structure however can be quite "expensive" for the cursor movement.
To manage user operations such as character insertion and deletion in a structured manner, I have used the Command design pattern which enforces the Single Responsibility Principle and Open/Closed Principle.
- Java JDK 22 or higher.
- Maven 3.6.0 or higher (for building and running tests).
- JUnit 5 5.10.0 (for unit testing).
git clone https://github.com/zhrfrd/JNotesIf you have Maven installed:
mvn clean installThis project uses JUnit 5 for unit testing.
Run all JUnit tests under src/text/java:
mvn testRun a specific test class:
mvn -Dtest=GapBufferTest testRun all JUnit tests under src/text/java:
./gradlew testRun a specific test class:
./gradlew test --tests "zhrfrd.jnotes.GapBufferTest"JNotes/
├── src
│ ├── main
│ │ ├── java
│ │ │ └── zhrfrd
│ │ │ └── jnotes
│ │ │ ├── buffer
│ │ │ │ └── GapBuffer.java
│ │ │ ├── command
│ │ │ │ ├── Command.java
│ │ │ │ ├── CommandManager.java
│ │ │ │ ├── CopyCommand.java
│ │ │ │ ├── DeleteNextCharCommand.java
│ │ │ │ ├── DeletePreviousCharCommand.java
│ │ │ │ ├── HighlightCommand.java
│ │ │ │ ├── InsertCharCommand.java
│ │ │ │ ├── Command.java
│ │ │ │ ├── MoveCursorCommand.java
│ │ │ │ └── PasteCommand.java
│ │ │ ├── ui
│ │ │ │ ├── JAreaText.java
│ │ │ │ ├── JAreaTextMenuBar.java
│ │ │ │ └── JLineNumberPanel.java
│ │ │ ├── util
│ │ │ │ └── Direction.java
│ │ │ └── Main.java
│ │ └── resources
│ └── test
│ ├── zhrfrd
│ │ └── jnotes
│ │ └── myeditor
│ │ ├── buffer
│ │ └───── GapBufferTest.java
├───────┴── resources
├── pom.xml
├── README.md
└── .gitignore
- Add support for mouse selection, highlight, copy, cut and paste.
- Adjust text highlight height.
- When deleting text after resizing the buffer, re-shrink the buffer in order to not waste too much memory.
Currently, JNotes does not support supplementary characters.
