edit

package
v0.0.0-...-dbc7887 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2019 License: MIT Imports: 11 Imported by: 9

Documentation

Overview

Package edit implements a subset of the Sam editing language. It does not implement undo/redo, or multi-buffer commands. However, these could be easily added on top of this implementation.

The langage is described below using an informal, EBNF-like style. Items enclosed in brackets, [ ] ,are optional, and items in braces, { }, may be repeated 0 or more times.

Some details may differ from the original. See https://9fans.github.io/plan9port/man/man1/sam.html for the original language description.

Addresses

The edit language is comprised of addresses and commands. Addresses identify a sequence of runes in the text. They are described by the grammar:

addr = range.

range = [ relative ] "," [ range ] | [ relative ] ";" [ range ] | relative.
	[a2],[a3] is the string from the start of the address a2 to the end of a3.
	If the a2 is absent, 0 is used. If the a3 is absent, $ is used.

	[a2];[a3] is like the previous,
	but with . set to the address a2 before evaluating a3.
	If the a2 is absent, 0 is used. If the a3 is absent, $ is used.

relative = [ simple ] "+" [ relative ] | [ simple ] "-" [ relative ] | simple relative | simple.
	[a1]+[a2] is the address a2 evaluated from the end of a1.
	If the a1 is absent, . is used. If the a2 is absent, 1 is used.

	[a1]-[a2] is the address a2 evaluated in reverse from the start of a1.
	If the a1 is absent, . is used. If the a2 is absent, 1 is used.

	a1 a2 is the same as a1+a2; the + is inserted.

simple = "$" | "." | "#" digits | digits | "/" regexp [  "/"  ].
	$ is the empty string at the end of the text.
	. is the current address of the editor, called dot.
	#n is the empty string after rune number n. If n is absent then 1 is used.
	n is the nth line in the text. 0 is the string before the first full line.
	/ regexp / is the first match of the regular expression going forward.

	A regexp is an re1 regular expression delimited by / or a newline.
	(See https://godoc.org/github.com/eaburns/T/re1)
	Regexp matches wrap at the end (or beginning) of the text.
	The resulting match may straddle the starting point.

All operators are left-associative.

Commands

Commands print text or compute diffs on the text which later can be applied.

In the following, the literal "/" can be any non-space rune that replaces "/" consistently throughout the production. Such a rune acts as a user-chosen delimiter.

For any command that begin with an optional, leading address, if the address is elided, then dot is used instead.

A command is one of the following:

[ addr ] ( "a" | "c" | "i" ) "/"  [ text ] [ "/" ].
[ addr ] ( "a" | "c" | "i" ) "\n" lines of text "\n.\n".
	Appends a string after the address (a),
	changes the string at the address (c), or
	inserts a string before the address (i).

	The text can be supplied in one of two forms:

	The first form begins with a non-space rune, the delimiter.
	The text consists of all runes until the end of input,
	a non-escaped newline, or a non-escaped delimiter.
	Pairs of runes beginning with \ are called escapes.
	They are interpreted specially:
		\n is a newline
		\t is a tab
		\ followed by any other rune is that rune.
		If the rune is the delimiter, it is non-delimiting.
  		\ followed by no rune (end of input) is \.

	For example:
		#3 a/Hello, World!/
	appends the string "Hello, World!" after the 3rd rune.

	The second form begins with a newline and
	ends with a line containing only a period, ".".
	In this form, escapes are not interpreted; they are literal.
	This form is convenient for multi-line text.

	For example:
		#3 a
		Hello,
		World
		!
		.
	appends the string "Hello,\nWorld\n!" after the 3rd rune.

[ addr ] "d".
	Deletes the string at the address.

[ addr ] "t" addr.
	Copies the string from the first address to after the second.

[ addr ] "m" addr.
	Moves the string from the first address to after the second.

[ addr ] "p".
	Prints the string at the address.

[ addr ] "s" [ digits ] "/" regexp "/" [ substitution ] "/"  [ "g" ].
	Substitutes matches of a regexp within the address.
	As above, the regexp uses the re1 syntax.

	A number N after s indicates to substitute the Nth match
	of the regular expression in the address range.
	If n == 0, the first match is substituted.
	If the substitution is followed by the letter g,
	all matches in the address range are substituted.
	If both a number N and the letter g are present,
	the Nth match and all following  in the address range
	are substituted.

	Substitution text replaces matches of the regular expression.
	The substitution text is interpreted the same way as
	the delimited form of the a, c, and i commands, except that
	an escaped digit (0-9) is not interpreted as the digit itself
	but is substituted with text matched by the regexp.
	The digits 1-9 correspond to text matched by capturing groups
	numbered from left-to-right by order of their open parenthesis.
	The 0 is the entire match.

[ addr ] ( "x" | "y" ) "/" regexp "/" command.
	Executes a command for each match of the regular expression in the address.

	Dot is set either to each match of the regular expression (x)
	or to the strings before, between, and after the matches (y),
	and the command is executed.
	It is an error if the resulting edits are not in ascending order.

	Note, the command is only interpreted if there is a match,
	so a malformed command is not reported if there is no match.

[ addr ] ( "g" | "v" ) "/" regexp "/" command.
	Conditionally executes a command if a regular expression
	matches in the address.

	If the regular expression matches (g) or doesn't match (v)
	in the addressed string, dot is set to the address
	and the command is executed.
	It is an error if the resulting edits are not in ascending order.

	Note, the command is only interpreted if the condition is satisfied,
	so a malformed command is not reported if not.

[ addr ] ( "|" | "<" | ">" ) shell command.
	Pipes the addressed string to and/or from shell commands.

	The | form pipes the addressed string to standard input
	of a shell command and overwrites it with the
	the standard output of the command.
	The < and > forms are like the | form,
	but < only overwrites with the command's standard output,
	and > only pipes to the command's standard input.
	In all cases, the standard error of the command is printed.
	In the case of >, the standard output is also printed.

	The shell command is any text terminated by either
	the end of input or an un-escaped newline.
	The text is passed as the -c argument of
	the shell program from the SHELL environment variable.
	If SHELL is unset, /bin/sh is used.

[ addr ] "{" { "\n" command } [ "\n" ] [ "}" ].
	Performs a sequence of commands.

	Before performing each command, dot is set to the address.
	Commands do not see modifications made by each other.
	Each sees the original text, before any changes are made.
	It is an error if the resulting edits are not in ascending order.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Addr

func Addr(dot [2]int64, t string, ro rope.Rope) ([2]int64, error)

Addr computes an address using the given value for dot.

Types

type Diff

type Diff struct {
	// At is the byte address of the span changed.
	At [2]int64
	// Text is the text to which the span changed.
	// Text may be nil if the addressed string was deleted.
	Text rope.Rope
}

A Diff describes a single change to a contiguous span of bytes.

func (Diff) Apply

func (d Diff) Apply(ro rope.Rope) (rope.Rope, Diff)

Apply returns the result of applying the diff and a new Diff that will undo the change if applied to the returned rope.

func (Diff) TextLen

func (d Diff) TextLen() int64

TextLen is the length of Text; 0 if Text is nil.

func (Diff) Update

func (d Diff) Update(dot [2]int64) [2]int64

Update returns an updated dot accounting for the change of the diff. For example, if the diff added or deleted text before the dot, then dot is increased or decreased accordingly.

type Diffs

type Diffs []Diff

A Diffs is a sequence of Diffs.

func Edit

func Edit(dot [2]int64, t string, print io.Writer, ro rope.Rope) (Diffs, error)

Edit computes an edit on the rope using the given value for dot.

func (Diffs) Apply

func (ds Diffs) Apply(ro rope.Rope) (rope.Rope, Diffs)

Apply returns the result of applying the diffs and a new sequence of diffs that will undo the changes if applied to the returned rope.

func (Diffs) Update

func (ds Diffs) Update(dot [2]int64) [2]int64

Update returns an updated dot accounting for the changes of the diffs.

type NoCommandError

type NoCommandError struct {
	// At contains the evaluation of the address preceding the missing command.
	// An empty address is dot, so an empty edit results in a NoCommandError.
	// At is set to the value of dot.
	At [2]int64
}

NoCommandError is returned when there was no command to execute.

func (NoCommandError) Error

func (e NoCommandError) Error() string

Error returns the error string "no command".

Jump to

Keyboard shortcuts

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