golines

package module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2021 License: MIT Imports: 25 Imported by: 1

README

Circle CI Go Report Card GoDoc Coverage

golines

Golines is a golang formatter that shortens long lines, in addition to all of the formatting fixes done by gofmt.

Motivation

The standard golang formatting tools (gofmt, goimports, etc.) are great, but deliberately don't shorten long lines; instead, this is an activity left to developers.

While there are different tastes when it comes to line lengths in go, we've generally found that very long lines are more difficult to read than their shortened alternatives. As an example:

myMap := map[string]string{"first key": "first value", "second key": "second value", "third key": "third value", "fourth key": "fourth value", "fifth key": "fifth value"}

vs.

myMap := map[string]string{
	"first key": "first value",
	"second key": "second value",
	"third key": "third value",
	"fourth key": "fourth value",
	"fifth key": "fifth value",
}

We built golines to give go developers the option to automatically shorten long lines, like the one above, according to their preferences.

More background and technical details are available in this blog post.

Examples

See this before and after view of a file with very long lines. More example pairs can be found in the _fixtures directory.

Usage

First, install the tool:

go get -u github.com/segmentio/golines

Then, run:

golines [paths to format]

The paths can be either directories or individual files. If no paths are provided, then input is taken from stdin (as with gofmt).

By default, the results are printed to stdout. To overwrite the existing files in place, use the -w flag.

Options

Some other options are described in the sections below. Run golines --help to see all available flags and settings.

Line length settings

By default, the tool tries to shorten lines that are longer than 100 columns and assumes that 1 tab = 4 columns. The latter can be changed via the -m and -t flags respectively.

Dry-run mode

Running the tool with the --dry-run flag will show pretty, git-style diffs via an embedded Python script.

Comment shortening

Shortening long comment lines is harder than shortening code because comments can have arbitrary structure and format. golines includes some basic logic for shortening single-line (i.e., //-prefixed) comments, but this is turned off by default since the quality isn't great. To enable this feature anyway, run with the --shorten-comments flag.

Custom formatters

By default, the tool will use goimports as the base formatter (if found), otherwise it will revert to gofmt. An explicit formatter can be set via the --base-formatter flag.

Generated files

By default, the tool will not format any files that look like they're generated. If you want to reformat these too, run with the --no-ignore-generated flag.

Chained method splitting

There are several possible ways to split lines that are part of method chains. The original approach taken by golines was to split on the args, e.g.:

myObj.Method(
	arg1,
	arg2,
	arg3,
).AnotherMethod(
	arg1,
	arg2,
).AThirdMethod(
	arg1,
	arg2,
)

Starting in version 0.3.0, the tool now splits on the dots by default, e.g.:

myObj.Method(arg1, arg2, arg3).
	AnotherMethod(arg1, arg2).
	AThirdMethod(arg1, arg2)

The original behavior can be used by running the tool with the --no-chain-split-dots flag.

Struct tag reformatting

In addition to shortening long lines, the tool also aligns struct tag keys; see the associated before and after examples in the _fixtures directory. To turn this behavior off, run with --no-reformat-tags.

Developer Tooling Integration

vim-go

Add the following lines to your vimrc, substituting 128 with your preferred line length:

let g:go_fmt_command = "golines"
let g:go_fmt_options = {
    \ 'golines': '-m 128',
    \ }
Visual Studio Code
  1. Install the Run on Save extension
  2. Go into the VSCode settings menu, scroll down to the section for the "Run on Save" extension, click the "Edit in settings.json" link
  3. Set the emeraldwalk.runonsave key as follows (adding other flags to the golines command as desired):
    "emeraldwalk.runonsave": {
        "commands": [
            {
                "match": "\\.go$",
                "cmd": "golines ${file} -w"
            }
        ]
    }
  1. Save the settings and restart VSCode
Others

Coming soon.

How It Works

For each input source file, golines runs through the following process:

  1. Read the file, break it into lines
  2. Add a specially-formatted annotation (comment) to each line that's longer than the configured maximum
  3. Use Dave Brophy's excellent decorated syntax tree library to parse the code plus added annotations
  4. Do a depth-first traversal of the resulting tree, looking for nodes that have an annotation on them
  5. If a node is part of a line that's too long, shorten it by altering the newlines around the node and/or its children
  6. Repeat steps 2-5 until no more shortening can be done
  7. Run the base formatter (e.g., gofmt) over the results, write these to either stdout or the source file

See this blog post for more technical details.

Limitations

The tool has been tested on a variety of inputs, but it's not perfect. Among other examples, the handling of long lines in comments could be improved. If you see anything particularly egregious, please report via an issue.

Documentation

Overview

Command golines is a formatter that shortens long go code lines, in addition to the formatting fixes done by gofmt.

$ go get -u github.com/segmentio/golines

See the project README for more details:

https://github.com/segmentio/golines/blob/master/README.md

File bugs or feature requests at:

https://github.com/segmentio/golines/issues

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateAnnotation

func CreateAnnotation(length int) string

CreateAnnotation generates the text of a comment that will annotate long lines.

func CreateDot

func CreateDot(node dst.Node, out io.Writer) error

CreateDot creates a dot representation of the graph associated with a dst node.

func FormatStructTags

func FormatStructTags(fieldList *dst.FieldList)

FormatStructTags formats struct tags so that the keys within each block of fields are aligned. It's not technically a shortening (and it usually makes these tags longer), so it's being kept separate from the core shortening logic for now.

See the struct_tags fixture for examples.

func HasAnnotation

func HasAnnotation(node dst.Node) bool

HasAnnotation determines whether the given AST node has a line length annotation on it.

func HasAnnotationRecursive

func HasAnnotationRecursive(node dst.Node) bool

HasAnnotationRecursive determines whether the given node or one of its children has a golines annotation on it. It's currently implemented for function declarations, fields, call expressions, and selector expressions only.

func HasMultiKeyTags

func HasMultiKeyTags(lines []string) bool

HasMultiKeyTags returns whether the given lines have a multikey struct line. It's used as an optimization step to avoid unnnecessary shortening rounds.

func IsAnnotation

func IsAnnotation(line string) bool

IsAnnotation determines whether the given line is an annotation created with CreateAnnotation.

func ParseAnnotation

func ParseAnnotation(line string) int

ParseAnnotation returns the line length encoded in a golines annotation. If none is found, it returns -1.

func PrettyDiff

func PrettyDiff(path string, contents []byte, results []byte) error

PrettyDiff prints colored, git-style diffs to the console. It uses an embedded Python script (above) to take advantage of Python's difflib package.

func WalkGraph

func WalkGraph(root *GraphNode) (string, error)

WalkGraph walks the graph starting at the argument root and returns a graphviz (dot) representation.

Types

type GraphEdge

type GraphEdge struct {
	Dest         *GraphNode
	Relationship string
}

GraphEdge is a representation of an edge in the AST graph.

type GraphNode

type GraphNode struct {
	Type  string
	Value string
	Node  dst.Node
	Edges []*GraphEdge
	// contains filtered or unexported fields
}

GraphNode is a representation of a node in the AST graph.

func NodeToGraphNode

func NodeToGraphNode(node dst.Node) *GraphNode

type Shortener

type Shortener struct {
	// contains filtered or unexported fields
}

Shortener shortens a single go file according to a small set of user style preferences.

func NewShortener

func NewShortener(config ShortenerConfig) *Shortener

NewShortener creates a new shortener instance from the provided config.

func (*Shortener) Shorten

func (s *Shortener) Shorten(contents []byte) ([]byte, error)

Shorten shortens the provided golang file content bytes.

type ShortenerConfig

type ShortenerConfig struct {
	MaxLen          int    // Max target width for each line
	TabLen          int    // Width of a tab character
	KeepAnnotations bool   // Whether to keep annotations in final result (for debugging only)
	ShortenComments bool   // Whether to shorten comments
	ReformatTags    bool   // Whether to reformat struct tags in addition to shortening long lines
	IgnoreGenerated bool   // Whether to ignore generated files
	DotFile         string // Path to write dot-formatted output to (for debugging only)
	ChainSplitDots  bool   // Whether to split chain methods by putting dots at ends of lines

	// Formatter that will be run before and after main shortening process. If empty,
	// defaults to goimports (if found), otherwise gofmt.
	BaseFormatterCmd string
}

ShortenerConfig stores the configuration options exposed by a Shortener instance.

Directories

Path Synopsis
Package fixtures contains made-up go files used for testing golines under various conditions.
Package fixtures contains made-up go files used for testing golines under various conditions.
Command generate is used to generate code that creates dot files from golang ASTs.
Command generate is used to generate code that creates dot files from golang ASTs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL