2016-11-18 22:39:22 +01:00

183 lines
4.3 KiB
Go

package main
import (
"io/ioutil"
"os"
"strings"
)
func LoadNonemptyLines(fname string, joinContinuationLines bool) []*Line {
lines, err := readLines(fname, joinContinuationLines)
if err != nil {
NewLineWhole(fname).Error0("Cannot be read.")
return nil
}
if len(lines) == 0 {
NewLineWhole(fname).Error0("Must not be empty.")
return nil
}
return lines
}
func LoadExistingLines(fname string, foldBackslashLines bool) []*Line {
lines, err := readLines(fname, foldBackslashLines)
if err != nil {
NewLineWhole(fname).Fatalf("Cannot be read.")
}
if lines == nil {
NewLineWhole(fname).Fatalf("Must not be empty.")
}
return lines
}
func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) *Line {
{ // Handle the common case efficiently
index := *pindex
rawLine := rawLines[*pindex]
textnl := rawLine.textnl
if hasSuffix(textnl, "\n") && !hasSuffix(textnl, "\\\n") {
*pindex = index + 1
return NewLine(fname, rawLine.Lineno, textnl[:len(textnl)-1], rawLines[index:index+1])
}
}
text := ""
index := *pindex
firstlineno := rawLines[index].Lineno
var lineRawLines []*RawLine
interestingRawLines := rawLines[index:]
for i, rawLine := range interestingRawLines {
indent, rawText, outdent, cont := splitRawLine(rawLine.textnl)
if text == "" {
text += indent
}
text += rawText
lineRawLines = append(lineRawLines, rawLine)
if cont != "" && i != len(interestingRawLines)-1 {
text += " "
index++
} else {
text += outdent + cont
break
}
}
lastlineno := rawLines[index].Lineno
*pindex = index + 1
return NewLineMulti(fname, firstlineno, lastlineno, text, lineRawLines)
}
func splitRawLine(textnl string) (leadingWhitespace, text, trailingWhitespace, cont string) {
i, m := 0, len(textnl)
if m > i && textnl[m-1] == '\n' {
m--
}
if m > i && textnl[m-1] == '\\' {
m--
cont = textnl[m : m+1]
}
trailingEnd := m
for m > i && (textnl[m-1] == ' ' || textnl[m-1] == '\t') {
m--
}
trailingStart := m
trailingWhitespace = textnl[trailingStart:trailingEnd]
leadingStart := i
for i < m && (textnl[i] == ' ' || textnl[i] == '\t') {
i++
}
leadingEnd := i
leadingWhitespace = textnl[leadingStart:leadingEnd]
text = textnl[leadingEnd:trailingStart]
return
}
func readLines(fname string, joinContinuationLines bool) ([]*Line, error) {
rawText, err := ioutil.ReadFile(fname)
if err != nil {
return nil, err
}
return convertToLogicalLines(fname, string(rawText), joinContinuationLines), nil
}
func convertToLogicalLines(fname string, rawText string, joinContinuationLines bool) []*Line {
var rawLines []*RawLine
for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
if rawLine != "" {
rawLines = append(rawLines, &RawLine{1 + lineno, rawLine, rawLine})
}
}
var loglines []*Line
if joinContinuationLines {
for lineno := 0; lineno < len(rawLines); {
loglines = append(loglines, getLogicalLine(fname, rawLines, &lineno))
}
} else {
for _, rawLine := range rawLines {
text := strings.TrimSuffix(rawLine.textnl, "\n")
logline := NewLine(fname, rawLine.Lineno, text, []*RawLine{rawLine})
loglines = append(loglines, logline)
}
}
if 0 < len(rawLines) && !hasSuffix(rawLines[len(rawLines)-1].textnl, "\n") {
NewLineEOF(fname).Error0("File must end with a newline.")
}
return loglines
}
func SaveAutofixChanges(lines []*Line) (autofixed bool) {
if !G.opts.Autofix {
for _, line := range lines {
if line.changed {
G.autofixAvailable = true
}
}
return
}
changes := make(map[string][]string)
changed := make(map[string]bool)
for _, line := range lines {
if line.changed {
changed[line.Fname] = true
}
changes[line.Fname] = append(changes[line.Fname], line.modifiedLines()...)
}
for fname := range changed {
changedLines := changes[fname]
tmpname := fname + ".pkglint.tmp"
text := ""
for _, changedLine := range changedLines {
text += changedLine
}
err := ioutil.WriteFile(tmpname, []byte(text), 0666)
if err != nil {
NewLineWhole(tmpname).Error0("Cannot write.")
continue
}
err = os.Rename(tmpname, fname)
if err != nil {
NewLineWhole(fname).Error0("Cannot overwrite with auto-fixed content.")
continue
}
msg := "Has been auto-fixed. Please re-run pkglint."
logs(llAutofix, fname, "", msg, msg)
autofixed = true
}
return
}