Tiny Text Editor (Simpler than vi) in Java

This is a complete tiny text editor in one Java file.

Read the mental model first

Download source file

Quick Run (from repo root)

1cd Site/static/code/examples/java
2javac TinyTextEditor.java
3java TinyTextEditor

It keeps things intentionally simple:

  • open or create a text file
  • show lines with numbers
  • append, edit, and delete lines
  • save to disk
  • warn on unsaved quit

Code (Single Public Class)

  1import java.io.IOException;
  2import java.nio.file.Files;
  3import java.nio.file.Path;
  4import java.util.ArrayList;
  5import java.util.List;
  6import java.util.Scanner;
  7
  8public class TinyTextEditor {
  9    public static void main(String[] args) {
 10        Scanner scanner = new Scanner(System.in);
 11        System.out.print("File name (default notes.txt): ");
 12        String fileName = scanner.nextLine().trim();
 13        if (fileName.isEmpty()) {
 14            fileName = "notes.txt";
 15        }
 16
 17        EditorState editor = new EditorState(Path.of(fileName));
 18        editor.load();
 19
 20        System.out.println("Commands: show, append, edit, delete, save, quit");
 21
 22        while (true) {
 23            System.out.print("> ");
 24            String command = scanner.nextLine().trim().toLowerCase();
 25
 26            switch (command) {
 27                case "show":
 28                    editor.show();
 29                    break;
 30                case "append":
 31                    System.out.print("Text: ");
 32                    editor.append(scanner.nextLine());
 33                    break;
 34                case "edit":
 35                    System.out.print("Line number: ");
 36                    int editLine = parseLineNumber(scanner.nextLine());
 37                    if (editLine > 0) {
 38                        System.out.print("New text: ");
 39                        editor.edit(editLine, scanner.nextLine());
 40                    }
 41                    break;
 42                case "delete":
 43                    System.out.print("Line number: ");
 44                    int deleteLine = parseLineNumber(scanner.nextLine());
 45                    if (deleteLine > 0) {
 46                        editor.delete(deleteLine);
 47                    }
 48                    break;
 49                case "save":
 50                    editor.save();
 51                    break;
 52                case "quit":
 53                    if (editor.isDirty()) {
 54                        System.out.print(
 55                                "Unsaved changes. Type quit! to force: "
 56                        );
 57                        String confirm = scanner.nextLine().trim();
 58                        if (!"quit!".equals(confirm)) {
 59                            break;
 60                        }
 61                    }
 62                    System.out.println("Bye.");
 63                    return;
 64                default:
 65                    System.out.println("Use: show, append, edit, delete, save, quit");
 66            }
 67        }
 68    }
 69
 70    private static int parseLineNumber(String raw) {
 71        try {
 72            return Integer.parseInt(raw.trim());
 73        } catch (NumberFormatException e) {
 74            System.out.println("Please enter a number.");
 75            return -1;
 76        }
 77    }
 78
 79    private static class EditorState {
 80        private final Path file;
 81        private final List<String> lines = new ArrayList<>();
 82        private boolean dirty = false;
 83
 84        private EditorState(Path file) {
 85            this.file = file;
 86        }
 87
 88        private void load() {
 89            if (!Files.exists(file)) {
 90                System.out.println("New file: " + file);
 91                return;
 92            }
 93            try {
 94                lines.addAll(Files.readAllLines(file));
 95                System.out.println("Loaded " + lines.size() + " line(s).");
 96            } catch (IOException e) {
 97                System.out.println("Could not read file. Starting empty.");
 98            }
 99        }
100
101        private void show() {
102            if (lines.isEmpty()) {
103                System.out.println("(empty)");
104                return;
105            }
106            for (int i = 0; i < lines.size(); i++) {
107                System.out.printf("%3d | %s%n", i + 1, lines.get(i));
108            }
109        }
110
111        private void append(String text) {
112            lines.add(text);
113            dirty = true;
114            System.out.println("Appended line " + lines.size() + ".");
115        }
116
117        private void edit(int lineNumber, String newText) {
118            int index = lineNumber - 1;
119            if (index < 0 || index >= lines.size()) {
120                System.out.println("Line out of range.");
121                return;
122            }
123            lines.set(index, newText);
124            dirty = true;
125            System.out.println("Line updated.");
126        }
127
128        private void delete(int lineNumber) {
129            int index = lineNumber - 1;
130            if (index < 0 || index >= lines.size()) {
131                System.out.println("Line out of range.");
132                return;
133            }
134            lines.remove(index);
135            dirty = true;
136            System.out.println("Line deleted.");
137        }
138
139        private void save() {
140            try {
141                Files.write(file, lines);
142                dirty = false;
143                System.out.println("Saved to " + file + ".");
144            } catch (IOException e) {
145                System.out.println("Save failed.");
146            }
147        }
148
149        private boolean isDirty() {
150            return dirty;
151        }
152    }
153}

Run It

1javac TinyTextEditor.java
2java TinyTextEditor

Why this works for beginners

  • One public class and one nested state class keep things readable.
  • The command loop is easy to trace.
  • You still get real file editing and save safety.