TUI Word Processor in Java

This is a complete terminal word processor in one Java file.

Read the mental model first

Download source file

Quick Run (from repo root)

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

It supports:

  • append, insert, edit, and delete by line number
  • save/open support
  • word and line count
  • unsaved-change warning on 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 TuiWordProcessor {
  9    public static void main(String[] args) {
 10        Scanner scanner = new Scanner(System.in);
 11        System.out.print("File name (default draft.txt): ");
 12        String fileName = scanner.nextLine().trim();
 13        if (fileName.isEmpty()) {
 14            fileName = "draft.txt";
 15        }
 16
 17        Document doc = new Document(Path.of(fileName));
 18        doc.load();
 19
 20        System.out.println("Commands: show, append, insert, edit, delete, stats, 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                    doc.show();
 29                    break;
 30                case "append":
 31                    System.out.print("Text: ");
 32                    doc.append(scanner.nextLine());
 33                    break;
 34                case "insert":
 35                    System.out.print("Line number: ");
 36                    int insertAt = parseLine(scanner.nextLine());
 37                    if (insertAt > 0) {
 38                        System.out.print("Text: ");
 39                        doc.insert(insertAt, scanner.nextLine());
 40                    }
 41                    break;
 42                case "edit":
 43                    System.out.print("Line number: ");
 44                    int editAt = parseLine(scanner.nextLine());
 45                    if (editAt > 0) {
 46                        System.out.print("New text: ");
 47                        doc.edit(editAt, scanner.nextLine());
 48                    }
 49                    break;
 50                case "delete":
 51                    System.out.print("Line number: ");
 52                    int deleteAt = parseLine(scanner.nextLine());
 53                    if (deleteAt > 0) {
 54                        doc.delete(deleteAt);
 55                    }
 56                    break;
 57                case "stats":
 58                    doc.stats();
 59                    break;
 60                case "save":
 61                    doc.save();
 62                    break;
 63                case "quit":
 64                    if (doc.dirty) {
 65                        System.out.print("Unsaved changes. Type quit! to force: ");
 66                        if (!"quit!".equals(scanner.nextLine().trim())) {
 67                            break;
 68                        }
 69                    }
 70                    return;
 71                default:
 72                    System.out.println("Use: show, append, insert, edit, delete, stats, save, quit");
 73            }
 74        }
 75    }
 76
 77    private static int parseLine(String raw) {
 78        try {
 79            return Integer.parseInt(raw.trim());
 80        } catch (NumberFormatException e) {
 81            System.out.println("Please enter a number.");
 82            return -1;
 83        }
 84    }
 85
 86    private static class Document {
 87        private final Path file;
 88        private final List<String> lines = new ArrayList<>();
 89        private boolean dirty = false;
 90
 91        private Document(Path file) {
 92            this.file = file;
 93        }
 94
 95        private void load() {
 96            if (!Files.exists(file)) {
 97                System.out.println("New file: " + file);
 98                return;
 99            }
100            try {
101                lines.addAll(Files.readAllLines(file));
102                System.out.println("Loaded " + lines.size() + " line(s).");
103            } catch (IOException e) {
104                System.out.println("Could not load file.");
105            }
106        }
107
108        private void show() {
109            if (lines.isEmpty()) {
110                System.out.println("(empty)");
111                return;
112            }
113            for (int i = 0; i < lines.size(); i++) {
114                System.out.printf("%3d | %s%n", i + 1, lines.get(i));
115            }
116        }
117
118        private void append(String text) {
119            lines.add(text);
120            dirty = true;
121            System.out.println("Appended line " + lines.size() + ".");
122        }
123
124        private void insert(int lineNo, String text) {
125            int index = lineNo - 1;
126            if (index < 0 || index > lines.size()) {
127                System.out.println("Line out of range.");
128                return;
129            }
130            lines.add(index, text);
131            dirty = true;
132            System.out.println("Inserted.");
133        }
134
135        private void edit(int lineNo, String text) {
136            int index = lineNo - 1;
137            if (index < 0 || index >= lines.size()) {
138                System.out.println("Line out of range.");
139                return;
140            }
141            lines.set(index, text);
142            dirty = true;
143            System.out.println("Updated.");
144        }
145
146        private void delete(int lineNo) {
147            int index = lineNo - 1;
148            if (index < 0 || index >= lines.size()) {
149                System.out.println("Line out of range.");
150                return;
151            }
152            lines.remove(index);
153            dirty = true;
154            System.out.println("Deleted.");
155        }
156
157        private void stats() {
158            int wordCount = 0;
159            for (String line : lines) {
160                String trimmed = line.trim();
161                if (!trimmed.isEmpty()) {
162                    wordCount += trimmed.split("\\s+").length;
163                }
164            }
165            System.out.println("Lines: " + lines.size() + ", Words: " + wordCount);
166        }
167
168        private void save() {
169            try {
170                Files.write(file, lines);
171                dirty = false;
172                System.out.println("Saved to " + file + ".");
173            } catch (IOException e) {
174                System.out.println("Could not save file.");
175            }
176        }
177    }
178}

Run It

1javac TuiWordProcessor.java
2java TuiWordProcessor

Why this works for beginners

  • One public class keeps it focused.
  • Commands map directly to document operations.
  • stats gives instant writing feedback.