2021-10-26
Vim visual mode and an unfortunate restriction on the filter operation
Since discovering Vim's visual (selection) mode I've found myself using it periodically for various things (which I may write up some other day, as there are a couple of common cases where it comes in handy). However, I recently re-discovered an unfortunate restriction on operators on the visual area, specifically filtering. This is that no matter what (as far as I know), they apply on a line-wise basis even if you made a visual block selection.
Suppose, hypothetically, that you have a shell script or a program with a block of comments:
# This is a comment that # I am in the process of editing and # shuffling words around. And # sentences too. It's wound up # all ragged.
What I often want to do is reflow this paragraph of comments. If
you're an innocent or forgetful person, one way to do this in Vim
is to use Ctrl-V to make a block selection of the actual comment
text, excluding the '# ' that starts them all, and then reflow it
with !fmt
(my normal choice). Unfortunately,
as explicitly documented, filtering operates in line mode even if
you made a visual selection, which means that if you do this fmt
will reflow your leading '# ' comment markers with the text and
suddenly you won't have a comment block.
(Fortunately you can undo this, which is what I immediately did when I noticed that my reflow seemed to have gone very wrong. Then I remembered the special 'always line based' operation of filtering.)
The Vim documentation for the visual gq
command and comment formatting suggests that
under the right circumstances, Vim will magically recognize comments
and do the right thing. However, processing a block of text through
fmt
is more general (it works in any context where you have a
captive block of text that you want to reflow, not just comments),
and I'm a person of fixed Vim habits.
I kind of wish that Vim always did filtering with only the selection regardless of what sort of visual selection it was, but I sort of see why Vim does it the current way. For block mode specifically, Vim would definitely need a rule to describe when it introduced newlines (you'd normally want them at the end of each line of the block selection).
(For my own use I have a more general replacement for fmt
(also), but this doesn't
help when I'm editing a configuration file or script as root or I'm
on a system where I haven't dragged over my usual set of tools.)
Go 1.18 will embed source version information into binaries
Since Go 1.13, Go has embedded information about the modules used
to build a program into its binary, and has reported them if you
used 'go version -m ...
' (release notes). This information has
historically included a variety of things,
including the path and module that the program was built from, an
indication of any module replacements being used, and a marker that
the program was being built from a source tree instead of with 'go
install ...@...'. However, it hasn't historically included any
information about the state of the source tree when you built from
source.
In Go 1.18, this is changing due to issue 37475 and issue 35667. To quote from the draft release notes:
The
go
command now embeds version control information in binaries including the currently checked-out revision and a flag indicating whether edited or untracked files are present. Version control information is embedded if thego
command is invoked in a directory within a Git or Mercurial repository, and themain
package and its containing main module are in the same repository. This information may be omitted using the flag-buildvcs=false
.Additionally, the
go
command embeds information about the build including build and tool tags (set with-tags
), compiler, assembler, and linker flags (like-gcflags
), whether cgo was enabled, and if it was, the values of the cgo environment variables (likeCGO_CFLAGS
). This information may be omitted using the flag-buildinfo=false
. [...]
(I don't know if the module and other information that will be embedded also includes information about the Go workspace you're in, if you're in one.)
At the moment this information is recorded in Go binaries in a form
that can be read by Go 1.17's 'go version -m
', and probably this
also works for earlier versions (as I believe much of this information
is actually in the binary as text).
The current information is pretty verbose by default since cgo is generally enabled, and this adds five lines of output, even if the code being compiled didn't actually use it and you have no special environment variables set. I suspect that this won't get reduced before release; the Go team seems to like being comprehensive here.
If nothing else, having this information embedded into binaries will make it harder to lose track of what exactly you're running. Now you have a better chance of figuring out the provenance of some old Go binary that's been running in the corner for who knows how long. People who distribute binaries widely and build them doing funny things may now have more of those funny things be somewhat visible, though. Well, until they turn these features off with those documented flags.
(As threatened, Go 1.18 will only support
building programs in module mode, so this information only coming
from 'go version -m
' doesn't matter any more.)
Sidebar: What this extra information looks like today
Here is the additional output added by this, as reported by 'go
version -m
' from the current development version:
build compiler gc build tags goexperiment.regabiwrappers,goexperiment.regabireflect,goexperiment.regabiargs build CGO_ENABLED true build CGO_CPPFLAGS build CGO_CFLAGS build CGO_CXXFLAGS build CGO_LDFLAGS build gitrevision 4f8a1b5f197fc69bc1252b32b5a8ed670ff557b6 build gituncommitted false
I wouldn't be surprised if some of the current build tags go away in the released version of Go 1.18, as some experiments are promoted out of that state.
Documentation on the current experiments is in the source code in
internal/goexperiment/flags.go,
and can be gotten for your particular version of Go with 'go doc
goexperiment.Flags
'. I'm not sure how you can find out the default
set of experiments enabled in your version of Go, but in the source
code this seems to be in the 'baseline
' variable set in
ParseGOEXPERIMENT()
function in internal/buildcfg/exp.go.
The current Go 1.18 build tags reported above appear to be this
baseline state on amd64.