Welcome to mirror list, hosted at ThFree Co, Russian Federation.

brace.go « bracefmt « cmd « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e6f55d1d4d0e1270a60e9de241ec2020f9dfedca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package main

import (
	"bytes"
	"go/scanner"
	"go/token"
)

type editCommand int

const (
	keepLine editCommand = iota
	addLineBefore
	removeLine
)

type edit struct {
	line int
	cmd  editCommand
}

func braceFmt(src []byte) []byte {
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, scanner.ScanComments)

	var (
		edits                            []edit
		lastNonEmptyLine, lastLBraceLine int
		lastOuterRBraceLine              = -1
	)

	for {
		pos, tok, _ := s.Scan()
		if tok == token.EOF {
			break
		}

		position := fset.Position(pos)
		currentLine := position.Line
		var nextEdit edit

		switch tok {
		case token.RBRACE:
			if currentLine-lastNonEmptyLine > 1 {
				// ......foo
				//
				// ...}
				nextEdit = edit{line: currentLine - 1, cmd: removeLine}
			}

			if position.Column == 1 {
				lastOuterRBraceLine = currentLine
			}

			if lastLBraceLine == currentLine {
				lastLBraceLine = 0
			}
		case token.LBRACE:
			lastLBraceLine = currentLine

			if lastOuterRBraceLine == currentLine {
				lastOuterRBraceLine = -1
			}
		default:
			if currentLine-lastOuterRBraceLine == 1 {
				// }
				// func bar() {
				nextEdit = edit{line: currentLine, cmd: addLineBefore}
			} else if currentLine-lastLBraceLine > 1 && lastNonEmptyLine == lastLBraceLine {
				// ...foo() {
				//
				// ......bar
				nextEdit = edit{line: currentLine - 1, cmd: removeLine}
			}
		}

		if nextEdit.cmd != keepLine {
			if len(edits) == 0 || edits[0] != nextEdit {
				// Store edits in reverse line order: that way line numbers in edits
				// won't become invalid when edits get applied.
				edits = append([]edit{nextEdit}, edits...)
			}
		}

		lastNonEmptyLine = currentLine
	}

	srcLines := bytes.Split(src, []byte("\n"))
	for _, e := range edits {
		i := e.line - 1 // scanner uses 1 based indexing; convert to 0 based

		switch e.cmd {
		case addLineBefore:
			srcLines = append(srcLines[:i], append([][]byte{nil}, srcLines[i:]...)...)
		case removeLine:
			if len(srcLines[i]) == 0 {
				srcLines = append(srcLines[:i], srcLines[i+1:]...)
			}
		}
	}

	return bytes.Join(srcLines, []byte("\n"))
}