com.google.googlejavaformat.Newlines.java Source code

Java tutorial

Introduction

Here is the source code for com.google.googlejavaformat.Newlines.java

Source

/*
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.googlejavaformat;

import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;

/** Platform-independent newline handling. */
public class Newlines {

    /** Returns the number of line breaks in the input. */
    public static int count(String input) {
        return Iterators.size(lineOffsetIterator(input)) - 1;
    }

    /** Returns the index of the first break in the input, or {@code -1}. */
    public static int firstBreak(String input) {
        Iterator<Integer> it = lineOffsetIterator(input);
        it.next();
        return it.hasNext() ? it.next() : -1;
    }

    private static final ImmutableSet<String> BREAKS = ImmutableSet.of("\r\n", "\n", "\r");

    /** Returns true if the entire input string is a recognized line break. */
    public static boolean isNewline(String input) {
        return BREAKS.contains(input);
    }

    /** Returns the length of the newline sequence at the current offset, or {@code -1}. */
    public static int hasNewlineAt(String input, int idx) {
        for (String b : BREAKS) {
            if (input.startsWith(b, idx)) {
                return b.length();
            }
        }
        return -1;
    }

    /**
     * Returns the terminating line break in the input, or {@code null} if the input does not end in a
     * break.
     */
    public static String getLineEnding(String input) {
        for (String b : BREAKS) {
            if (input.endsWith(b)) {
                return b;
            }
        }
        return null;
    }

    /**
     * Returns the first line separator in the text, or {@code "\n"} if the text does not contain a
     * single line separator.
     */
    public static String guessLineSeparator(String text) {
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            switch (c) {
            case '\r':
                if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
                    return "\r\n";
                }
                return "\r";
            case '\n':
                return "\n";
            default:
                break;
            }
        }
        return "\n";
    }

    /** Returns true if the input contains any line breaks. */
    public static boolean containsBreaks(String text) {
        return CharMatcher.anyOf("\n\r").matchesAnyOf(text);
    }

    /** Returns an iterator over the start offsets of lines in the input. */
    public static Iterator<Integer> lineOffsetIterator(String input) {
        return new LineOffsetIterator(input);
    }

    /** Returns an iterator over lines in the input, including trailing whitespace. */
    public static Iterator<String> lineIterator(String input) {
        return new LineIterator(input);
    }

    private static class LineOffsetIterator implements Iterator<Integer> {

        private int curr = 0;
        private int idx = 0;
        private final String input;

        private LineOffsetIterator(String input) {
            this.input = input;
        }

        @Override
        public boolean hasNext() {
            return curr != -1;
        }

        @Override
        public Integer next() {
            if (curr == -1) {
                throw new NoSuchElementException();
            }
            int result = curr;
            advance();
            return result;
        }

        private void advance() {
            for (; idx < input.length(); idx++) {
                char c = input.charAt(idx);
                switch (c) {
                case '\r':
                    if (idx + 1 < input.length() && input.charAt(idx + 1) == '\n') {
                        idx++;
                    }
                    // falls through
                case '\n':
                    idx++;
                    curr = idx;
                    return;
                default:
                    break;
                }
            }
            curr = -1;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("remove");
        }
    }

    private static class LineIterator implements Iterator<String> {

        int idx;
        String curr;

        private final String input;
        private final Iterator<Integer> indices;

        private LineIterator(String input) {
            this.input = input;
            this.indices = lineOffsetIterator(input);
            idx = indices.next(); // read leading 0
        }

        private void advance() {
            int last = idx;
            if (indices.hasNext()) {
                idx = indices.next();
            } else if (hasNext()) {
                // no terminal line break
                idx = input.length();
            } else {
                throw new NoSuchElementException();
            }
            curr = input.substring(last, idx);
        }

        @Override
        public boolean hasNext() {
            return idx < input.length();
        }

        @Override
        public String next() {
            advance();
            return curr;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("remove");
        }
    }
}