/** * Deal with formatting characters. * * <p>Parsing is as follows: - Treat all contiguous strings of formatting characters as one block. * (This method processes one block.) - Only a single instance of a particular format character * within a block is used to determine whether to turn on/off that type of formatting; other * instances simply print the character itself. - If the format is to be turned on, we use the * _first_ instance; if it is to be turned off, we use the _last_ instance (by appending the * format.) * * <p>Example: **string** turns into <b>*string*</b> */ private boolean parseFormatting() { if (!parseFormatting) { return false; } int endChar = nextChar; while ((endChar < text.length()) && isFormatChar(text.charAt(endChar))) { endChar += 1; } if ((endChar == nextChar) || !isWordBreak(endChar)) { return false; } // Keeps track of whether we've seen a character (in map if we've seen it) // and whether we should append a closing format token (if value in // map is TRUE). Linked hashmap for consistent ordering. LinkedHashMap<Character, Boolean> seenCharacters = new LinkedHashMap<Character, Boolean>(); for (int index = nextChar; index < endChar; ++index) { char ch = text.charAt(index); Character key = Character.valueOf(ch); if (seenCharacters.containsKey(key)) { // Already seen this character, just append an unmatched token, which // will print plaintext character addToken(new Format(ch, false)); } else { Format start = formatStart.get(key); if (start != null) { // Match the start token, and ask an end token to be appended start.setMatched(true); formatStart.remove(key); seenCharacters.put(key, Boolean.TRUE); } else { // Append start token start = new Format(ch, true); formatStart.put(key, start); addToken(start); seenCharacters.put(key, Boolean.FALSE); } } } // Append any necessary end tokens for (Character key : seenCharacters.keySet()) { if (seenCharacters.get(key) == Boolean.TRUE) { Format end = new Format(key.charValue(), false); end.setMatched(true); addToken(end); } } nextChar = endChar; return true; }