From: Svjatoslav Agejenko Date: Sun, 25 Jan 2026 12:20:27 +0000 (+0200) Subject: Refactor `Menu` class: Use static imports for `Math` methods, optimize code in `filte... X-Git-Url: http://www2.svjatoslav.eu/gitweb/?a=commitdiff_plain;h=fbf78972f94f8dfccca15e0db87b83df8e84c66f;p=cli-helper.git Refactor `Menu` class: Use static imports for `Math` methods, optimize code in `filterOptions`, and improve readability in `updateDisplay` logic. --- diff --git a/src/main/java/eu/svjatoslav/commons/cli_helper/Menu.java b/src/main/java/eu/svjatoslav/commons/cli_helper/Menu.java index 73356fb..ac68d82 100644 --- a/src/main/java/eu/svjatoslav/commons/cli_helper/Menu.java +++ b/src/main/java/eu/svjatoslav/commons/cli_helper/Menu.java @@ -7,6 +7,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static java.lang.Math.max; +import static java.lang.Math.min; + /** * Prompts the user to select an option from a list using fuzzy matching and cursor keys. *

@@ -22,6 +25,9 @@ import java.util.List; */ public class Menu { + /** + * Presents an interactive menu; returns selection or null + */ public static String askSelection(String prompt, List options) throws IOException { if (options == null || options.isEmpty()) { throw new IllegalArgumentException("Options list cannot be empty"); @@ -37,15 +43,14 @@ public class Menu { while (true) { - List filtered = filterOptions(options, filterString); + List filteredOptions = filterOptions(options, filterString); // Clamp selected to valid range - selectedIndex = Math.max(0, Math.min(selectedIndex, filtered.size() - 1)); + selectedIndex = max(0, min(selectedIndex, filteredOptions.size() - 1)); - updateDisplay(prompt, filtered, selectedIndex, filterString, lastTotalLines); - lastTotalLines = getCurrentTotalLines(options, filterString); + lastTotalLines = updateDisplay(prompt, filteredOptions, selectedIndex, filterString, lastTotalLines); - int c = System.in.read(); + int c = System.in.read(); // read a single character from user input // Handle Escape key or arrow keys if (c == 27) { // ESC @@ -67,10 +72,10 @@ public class Menu { // Handle Enter key else if (c == 13 || c == 10) { - if (filtered.isEmpty()) { + if (filteredOptions.isEmpty()) { return null; } - return filtered.get(selectedIndex); + return filteredOptions.get(selectedIndex); } // Handle Backspace (8 or 127) @@ -140,17 +145,15 @@ public class Menu { * @return filtered list of options that match the fuzzy pattern */ private static List filterOptions(List options, String filter) { - if (filter == null || filter.isEmpty()) { - return new ArrayList<>(options); - } + if (filter == null || filter.isEmpty()) return new ArrayList<>(options); - List filtered = new ArrayList<>(); - for (String option : options) { - if (matchesFuzzy(filter, option)) { - filtered.add(option); - } - } - return filtered; + List result = new ArrayList<>(); + + for (String option : options) + if (matchesFuzzy(filter, option)) + result.add(option); + + return result; } /** @@ -165,58 +168,46 @@ public class Menu { filter = filter.toLowerCase(); option = option.toLowerCase(); int filterIndex = 0; - for (char c : option.toCharArray()) { - if (filterIndex < filter.length() && c == filter.charAt(filterIndex)) { + + for (char c : option.toCharArray()) + if (filterIndex < filter.length() && c == filter.charAt(filterIndex)) filterIndex++; - } - } + return filterIndex == filter.length(); } - /** - * Updates the display based on the current state and returns the adjusted selected index. + * Updates the display based on the current state. + * @return the total number of lines in the display */ - private static void updateDisplay(String prompt, List filtered, int selected, String filter, int lastTotalLines) { + private static int updateDisplay(String prompt, List filteredOptions, int selectedIndex, String filterString, int lastTotalLines) { - if (filtered.isEmpty()) { - filtered = Collections.singletonList("No matches found"); - } + if (filteredOptions.isEmpty()) filteredOptions = Collections.singletonList("No matches found"); - // ──────────────────────────────────────────────── - // 1. Position cursor at the START of our display area - // ──────────────────────────────────────────────── - if (lastTotalLines > 0) { + // Position cursor at the START of the display area + if (lastTotalLines > 0) System.out.print("\033[" + lastTotalLines + "A"); // move cursor up to prompt line - } + System.out.print("\r"); // go to column 1 (just in case) - // ──────────────────────────────────────────────── - // 2. Clear from here downward (removes old leftover lines perfectly) - // ──────────────────────────────────────────────── + // Clear from here downward (removes old leftover lines perfectly) System.out.print("\033[J"); // ESC [ J = clear from cursor to end of screen - // ──────────────────────────────────────────────── - // 3. Print fresh content - // ──────────────────────────────────────────────── + // Print fresh content: // Prompt + current filter (on one line) - System.out.println(prompt + ": " + filter); + System.out.println(prompt + ": " + filterString); // Menu items - for (int i = 0; i < filtered.size(); i++) { - String line = (i == selected ? "> " : " ") + filtered.get(i); + for (int i = 0; i < filteredOptions.size(); i++) { + String line = (i == selectedIndex ? "> " : " ") + filteredOptions.get(i); System.out.print("\r"); System.out.println(line); } System.out.print("\r"); System.out.flush(); // ensure immediate display - } - private static int getCurrentTotalLines(List options, String filter) { - List filtered = filterOptions(options, filter); - int menuLines = filtered.isEmpty() ? 1 : filtered.size(); - return 1 + menuLines; // 1 for prompt line + menu lines + return filteredOptions.size() + 1; // 1 for prompt line + menu lines } }