From 2a112a0004f28afcac2c0bb5f8be76703adb9727 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 16 Jul 2015 18:29:38 -0700 Subject: [PATCH] preformat checker --- cmd/mungedocs/mungedocs.go | 1 + cmd/mungedocs/preformatted.go | 57 +++++++++++++++++++++++++++++++++++ cmd/mungedocs/util.go | 53 +++++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 cmd/mungedocs/preformatted.go diff --git a/cmd/mungedocs/mungedocs.go b/cmd/mungedocs/mungedocs.go index 50b3aa5240f..f6db77c6c94 100644 --- a/cmd/mungedocs/mungedocs.go +++ b/cmd/mungedocs/mungedocs.go @@ -47,6 +47,7 @@ Examples: allMunges = []munge{ {"table-of-contents", updateTOC}, {"check-links", checkLinks}, + {"blank-lines-surround-preformatted", checkPreformatted}, {"unversioned-warning", updateUnversionedWarning}, {"analytics", checkAnalytics}, {"kubectl-dash-f", checkKubectlFileTargets}, diff --git a/cmd/mungedocs/preformatted.go b/cmd/mungedocs/preformatted.go new file mode 100644 index 00000000000..bd42f71a5bd --- /dev/null +++ b/cmd/mungedocs/preformatted.go @@ -0,0 +1,57 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +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 main + +import ( + "bytes" +) + +// Blocks of ``` need to have blank lines on both sides or they don't look +// right in HTML. +func checkPreformatted(filePath string, fileBytes []byte) ([]byte, error) { + f := splitByPreformatted(fileBytes) + f = append(fileBlocks{{false, []byte{}}}, f...) + f = append(f, fileBlock{false, []byte{}}) + + output := []byte(nil) + for i := 1; i < len(f)-1; i++ { + prev := &f[i-1] + block := &f[i] + next := &f[i+1] + if !block.preformatted { + continue + } + neededSuffix := []byte("\n\n") + for !bytes.HasSuffix(prev.data, neededSuffix) { + prev.data = append(prev.data, '\n') + } + for !bytes.HasSuffix(block.data, neededSuffix) { + block.data = append(block.data, '\n') + if bytes.HasPrefix(next.data, []byte("\n")) { + // don't change the number of newlines unless needed. + next.data = next.data[1:] + if len(next.data) == 0 { + f = append(f[:i+1], f[i+2:]...) + } + } + } + } + for _, block := range f { + output = append(output, block.data...) + } + return output, nil +} diff --git a/cmd/mungedocs/util.go b/cmd/mungedocs/util.go index 028e427aff9..1a756dec0a9 100644 --- a/cmd/mungedocs/util.go +++ b/cmd/mungedocs/util.go @@ -25,7 +25,9 @@ import ( var ( // Finds all preformatted block start/stops. - preformatRE = regexp.MustCompile("^```.*") + preformatRE = regexp.MustCompile("^[\\s]*```.*") + notPreformatRE = regexp.MustCompile("^[\\s]*```.*```.*") + preformatEndRE = regexp.MustCompile(".*```.*") ) // Splits a document up into a slice of lines. @@ -120,35 +122,58 @@ func endMungeTag(desc string) string { // Calls 'replace' for all sections of the document not in ``` / ``` blocks. So // that you don't have false positives inside those blocks. func replaceNonPreformatted(input []byte, replace func([]byte) []byte) []byte { + f := splitByPreformatted(input) output := []byte(nil) + for _, block := range f { + if block.preformatted { + output = append(output, block.data...) + } else { + output = append(output, replace(block.data)...) + } + } + return output +} + +type fileBlock struct { + preformatted bool + data []byte +} + +type fileBlocks []fileBlock + +func splitByPreformatted(input []byte) fileBlocks { + f := fileBlocks{} + cur := []byte(nil) - keepBlock := true + preformatted := false // SplitAfter keeps the newline, so you don't have to worry about // omitting it on the last line or anything. Also, the documentation // claims it's unicode safe. for _, line := range bytes.SplitAfter(input, []byte("\n")) { - if keepBlock { - if preformatRE.Match(line) { - cur = replace(cur) - output = append(output, cur...) + if !preformatted { + if preformatRE.Match(line) && !notPreformatRE.Match(line) { + if len(cur) > 0 { + f = append(f, fileBlock{false, cur}) + } cur = []byte{} - keepBlock = false + preformatted = true } cur = append(cur, line...) } else { cur = append(cur, line...) - if preformatRE.Match(line) { - output = append(output, cur...) + if preformatEndRE.Match(line) { + if len(cur) > 0 { + f = append(f, fileBlock{true, cur}) + } cur = []byte{} - keepBlock = true + preformatted = false } } } - if keepBlock { - cur = replace(cur) + if len(cur) > 0 { + f = append(f, fileBlock{preformatted, cur}) } - output = append(output, cur...) - return output + return f } // As above, but further uses exp to parse the non-preformatted sections.