diff --git a/README.md b/READ GENERAL.md similarity index 100% rename from README.md rename to READ GENERAL.md diff --git a/java/PhaseNote.java b/java/PhaseNote.java new file mode 100644 index 0000000..d2ef1c1 --- /dev/null +++ b/java/PhaseNote.java @@ -0,0 +1,398 @@ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import java.util.stream.Collectors; + +// Start of Phase 1 Notes +public class PhaseNote { + private static final Path NOTES_DIR = Path.of(System.getProperty("user.home"), ".notes"); + + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("Error: No command provided."); + System.err.println("Usage: java PhaseNote [command]"); + System.err.println("Try 'java PhaseNote help' for more information."); + System.exit(1); + } + + String command = args[0].toLowerCase(); + switch (command) { + case "help" -> { + showHelp(); + System.exit(0); + } + case "list" -> { + boolean success = listNotes(NOTES_DIR); + System.exit(success ? 0 : 1); + } + case "create" -> { + boolean success = createNote(NOTES_DIR); + System.exit(success ? 0 : 1); + } + case "read" -> { + if (args.length < 2) { + System.err.println("Error: No note number provided."); + System.err.println("Usage: java PhaseNote read [note-number]"); + System.exit(1); + } + try { + int noteNumber = Integer.parseInt(args[1]); + boolean success = readNote(NOTES_DIR, noteNumber); + System.exit(success ? 0 : 1); + } catch (NumberFormatException e) { + System.err.println("Error: Invalid note number '" + args[1] + "'"); + System.exit(1); + } + } + case "delete" -> { + if (args.length < 2) { + System.err.println("Error: No note number provided."); + System.err.println("Usage: java PhaseNote delete [note-number]"); + System.exit(1); + } + try { + int noteNumber = Integer.parseInt(args[1]); + boolean success = deleteNote(NOTES_DIR, noteNumber); + System.exit(success ? 0 : 1); + } catch (NumberFormatException e) { + System.err.println("Error: Invalid note number '" + args[1] + "'"); + System.exit(1); + } + } + case "edit" -> { + if (args.length < 2) { + System.err.println("Error: No note number provided."); + System.err.println("Usage: java PhaseNote edit [note-number]"); + System.exit(1); + } + try { + int noteNumber = Integer.parseInt(args[1]); + boolean success = editNote(NOTES_DIR, noteNumber); + System.exit(success ? 0 : 1); + } catch (NumberFormatException e) { + System.err.println("Error: Invalid note number '" + args[1] + "'"); + System.exit(1); + } + } + default -> { + System.err.println("Error: Unknown command '" + command + "'"); + System.err.println("Try 'java PhaseNote help' for more information."); + System.exit(1); + } + } + } + + private static Map parseYamlHeader(Path path) { + Map metadata = new HashMap<>(); + metadata.put("file", path.getFileName().toString()); + + try { + List lines = Files.readAllLines(path); + if (lines.isEmpty() || !lines.get(0).trim().equals("---")) { + metadata.put("title", path.getFileName().toString()); + return metadata; + } + + // Find the closing --- + int closingIndex = -1; + for (int i = 1; i < lines.size(); i++) { + if (lines.get(i).trim().equals("---")) { + closingIndex = i; + break; + } + } + + if (closingIndex == -1) { + metadata.put("title", path.getFileName().toString()); + return metadata; + } + + // Parse key-value pairs between the markers + for (int i = 1; i < closingIndex; i++) { + String line = lines.get(i).trim(); + if (line.contains(":")) { + String[] parts = line.split(":", 2); + metadata.put(parts[0].trim(), parts[1].trim()); + } + } + } catch (IOException e) { + metadata.put("error", e.getMessage()); + } + + return metadata; + } + + private static boolean listNotes(Path baseDir) { + if (!Files.exists(baseDir)) { + System.err.println("Error: Notes directory does not exist: " + baseDir); + System.err.println("Create it with: mkdir -p ~/.notes/notes"); + return false; + } + + Path searchPath = Files.exists(baseDir.resolve("notes")) ? baseDir.resolve("notes") : baseDir; + List noteFiles; + + try (Stream walk = Files.walk(searchPath, 1)) { + noteFiles = walk + .filter(Files::isRegularFile) + .filter(p -> { + String name = p.getFileName().toString(); + return name.endsWith(".md") || name.endsWith(".note") || name.endsWith(".txt"); + }) + .sorted() + .collect(Collectors.toList()); + } catch (IOException e) { + System.err.println("Error reading notes directory: " + e.getMessage()); + return false; + } + + if (noteFiles.isEmpty()) { + System.out.println("No notes found in " + baseDir); + return true; + } + + System.out.println("Notes in " + baseDir + ":"); + System.out.println("=".repeat(60)); + + for (int i = 0; i < noteFiles.size(); i++) { + Path file = noteFiles.get(i); + Map metadata = parseYamlHeader(file); + String title = metadata.getOrDefault("title", file.getFileName().toString()); + String created = metadata.getOrDefault("created", "N/A"); + String tags = metadata.getOrDefault("tags", ""); + + System.out.println("\n[" + (i + 1) + "] " + file.getFileName()); + System.out.println(" Title: " + title); + if (!"N/A".equals(created)) System.out.println(" Created: " + created); + if (!tags.isEmpty()) System.out.println(" Tags: " + tags); + } + + System.out.println("\n" + noteFiles.size() + " note(s) found."); + return true; + } + + + // createNote + private static boolean createNote(Path baseDir) { + if (!Files.exists(baseDir)) { + System.err.println("Error: Notes directory does not exist: " + baseDir); + System.err.println("Create it with: mkdir -p ~/.notes/notes"); + return false; + } + + Path notesPath = baseDir.resolve("notes"); + if (!Files.exists(notesPath)) { + try { + Files.createDirectories(notesPath); + } catch (IOException e) { + System.err.println("Error creating notes directory: " + e.getMessage()); + return false; + } + } + + try { + // Create a new note with timestamp-based filename + String timestamp = java.time.LocalDateTime.now().format( + java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); + String filename = "note_" + timestamp + ".md"; + Path newNotePath = notesPath.resolve(filename); + + // Create note content with YAML header + String noteContent = String.format(""" + --- + title: New Note + created: %s + tags: + --- + + """, java.time.LocalDate.now().toString()); + + Files.writeString(newNotePath, noteContent); + System.out.println("Note created successfully: " + newNotePath); + return true; + } catch (IOException e) { + System.err.println("Error creating note: " + e.getMessage()); + return false; + } + } + + // readNote + private static boolean readNote(Path baseDir, int noteNumber) { + if (!Files.exists(baseDir)) { + System.err.println("Error: Notes directory does not exist: " + baseDir); + return false; + } + + Path searchPath = Files.exists(baseDir.resolve("notes")) ? baseDir.resolve("notes") : baseDir; + List noteFiles; + + try (Stream walk = Files.walk(searchPath, 1)) { + noteFiles = walk + .filter(Files::isRegularFile) + .filter(p -> { + String name = p.getFileName().toString(); + return name.endsWith(".md") || name.endsWith(".note") || name.endsWith(".txt"); + }) + .sorted() + .collect(Collectors.toList()); + } catch (IOException e) { + System.err.println("Error reading notes directory: " + e.getMessage()); + return false; + } + + // Check if note number is valid + if (noteNumber < 1 || noteNumber > noteFiles.size()) { + System.err.println("Error: Note number " + noteNumber + " not found. Valid range: 1-" + noteFiles.size()); + return false; + } + + try { + Path notePath = noteFiles.get(noteNumber - 1); + String content = Files.readString(notePath); + System.out.println(content); + return true; + } catch (IOException e) { + System.err.println("Error reading note: " + e.getMessage()); + return false; + } + } + + // deleteNote + private static boolean deleteNote(Path baseDir, int noteNumber) { + if (!Files.exists(baseDir)) { + System.err.println("Error: Notes directory does not exist: " + baseDir); + return false; + } + + Path searchPath = Files.exists(baseDir.resolve("notes")) ? baseDir.resolve("notes") : baseDir; + List noteFiles; + + try (Stream walk = Files.walk(searchPath, 1)) { + noteFiles = walk + .filter(Files::isRegularFile) + .filter(p -> { + String name = p.getFileName().toString(); + return name.endsWith(".md") || name.endsWith(".note") || name.endsWith(".txt"); + }) + .sorted() + .collect(Collectors.toList()); + } catch (IOException e) { + System.err.println("Error reading notes directory: " + e.getMessage()); + return false; + } + + // Check if note number is valid + if (noteNumber < 1 || noteNumber > noteFiles.size()) { + System.err.println("Error: Note number " + noteNumber + " not found. Valid range: 1-" + noteFiles.size()); + return false; + } + + try { + Path notePath = noteFiles.get(noteNumber - 1); + Files.delete(notePath); + System.out.println("Note deleted successfully: " + notePath.getFileName()); + return true; + } catch (IOException e) { + System.err.println("Error deleting note: " + e.getMessage()); + return false; + } + } + + // editNote + private static boolean editNote(Path baseDir, int noteNumber) { + if (!Files.exists(baseDir)) { + System.err.println("Error: Notes directory does not exist: " + baseDir); + return false; + } + + Path searchPath = Files.exists(baseDir.resolve("notes")) ? baseDir.resolve("notes") : baseDir; + List noteFiles; + + try (Stream walk = Files.walk(searchPath, 1)) { + noteFiles = walk + .filter(Files::isRegularFile) + .filter(p -> { + String name = p.getFileName().toString(); + return name.endsWith(".md") || name.endsWith(".note") || name.endsWith(".txt"); + }) + .sorted() + .collect(Collectors.toList()); + } catch (IOException e) { + System.err.println("Error reading notes directory: " + e.getMessage()); + return false; + } + + // Check if note number is valid + if (noteNumber < 1 || noteNumber > noteFiles.size()) { + System.err.println("Error: Note number " + noteNumber + " not found. Valid range: 1-" + noteFiles.size()); + return false; + } + + try { + Path notePath = noteFiles.get(noteNumber - 1); + + // Read current content + String currentContent = Files.readString(notePath); + System.out.println("Current note content:"); + System.out.println("=".repeat(60)); + System.out.println(currentContent); + System.out.println("=".repeat(60)); + + // Open editor for user input + System.out.print("Enter new content (or type 'quit' on a new line to cancel):\n"); + java.util.Scanner scanner = new java.util.Scanner(System.in); + StringBuilder newContent = new StringBuilder(); + String line; + + while (scanner.hasNextLine()) { + line = scanner.nextLine(); + if (line.equals("quit")) { + System.out.println("Edit cancelled."); + return false; + } + newContent.append(line).append("\n"); + } + + // Write updated content back to file + Files.writeString(notePath, newContent.toString()); + System.out.println("Note updated successfully: " + notePath.getFileName()); + return true; + } catch (IOException e) { + System.err.println("Error editing note: " + e.getMessage()); + return false; + } + } + + private static void showHelp() { + String helpText = String.format(""" + Future Proof Notes Manager v0.1 + + Usage: java PhaseNote [command] + + Available commands: + help - Display this help information + list - List all notes in the notes directory + create - Create a new note + read - Read a note by number (use list to see note numbers) + edit - Edit a note by number (use list to see note numbers) + delete - Delete a note by number (use list to see note numbers) + + Examples: + java PhaseNote list + java PhaseNote read 1 + java PhaseNote edit 1 + java PhaseNote delete 1 + + Notes directory: %s + + Setup: + mkdir -p ~/.notes/notes + cp test-notes/*.md ~/.notes/notes/ + """, NOTES_DIR); + System.out.println(helpText.trim()); + } +} diff --git a/java/README.md b/java/README JAVA.md similarity index 100% rename from java/README.md rename to java/README JAVA.md