package editorimport ()var (// validRegisterKeys - All valid register IDs (keys) for read/write Vim registers. // validRegisterKeys = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-\"". numRegisters = 10 alphaRegisters = 52)// Buffers is a list of registers in which to put yanked/cut contents.// These buffers technically are Vim registers with full functionality.typeBuffersstruct { num map[int][]rune// numbered registers (0-9) alpha map[rune][]rune// lettered registers ( a-z ) ro map[rune][]rune// read-only registers ( . % : ) waiting bool// The user wants to use a still unidentified register selected bool// We have identified the register, and acting on it. active rune// Any of the read/write registers ("/num/alpha) mutex *sync.Mutex}// NewBuffers is a required constructor to set up all the buffers/registers// for the shell, because it contains maps that must be correctly initialized.func () *Buffers {return &Buffers{num: make(map[int][]rune, numRegisters),alpha: make(map[rune][]rune, alphaRegisters),ro: map[rune][]rune{},mutex: &sync.Mutex{}, }}// SetActive sets the currently active register/buffer.// Valid values are letters (lower/upper), digits (1-9),// or read-only buffers ( . % : ).func ( *Buffers) ( rune) {deferfunc() {// We now have an active, identified register .waiting = false .selected = true }()// Numbered , := strconv.Atoi(string())if == nil && < 10 { .active = return }// Read-onlyif , := .ro[]; { .active = return }// Else, lettered .active = }// Get returns the contents of a given register.// If the rune is nil (rune(0)), it returns the value of the kill buffer (the " Vim register).// If the rune is an alphanumeric comprised in the valid register IDs, their content is returned.// If the register name is invalid, the function returns an empty rune slice.func ( *Buffers) ( rune) []rune {if == 0 {return .GetKill() } , := strconv.Atoi(string())if == nil {return .num[] }if , := .alpha[]; {return }if , := .ro[]; {return }returnnil}// Active returns the contents of the active buffer/register (or the kill// buffer if no active register is active), and resets the active register.func ( *Buffers) () []rune {defer .Reset()if !.waiting && !.selected {return .GetKill() }return .Get(.active)}// Pop rotates the kill ring and returns the new top.func ( *Buffers) () []rune {iflen(.num) == 0 {returnnil }// Reassign the kill buffer and // pop the first numbered register. := string(.num[0])delete(.num, 0)for := 0; < len(.num); ++ { .num[] = []rune(string(.num[+1]))delete(.num, +1) }return []rune()}// GetKill returns the contents of the kill buffer.func ( *Buffers) () []rune {iflen(.num) == 0 {returnnil }return .num[0]}// Write writes a slice to the currently active buffer, and/or to the kill one.// After the operation, the buffers are reset, eg. none is considered active.func ( *Buffers) ( ...rune) { := string()defer .Reset()iflen() == 0 || == "" {return }// Either write to the active register, or add to numbered ones.if .selected { .WriteTo(.active, []rune()...) } else { .writeNum(-1, []rune()) }}// WriteTo writes a slice directly to a target register.// If the register name is invalid, nothing is written anywhere.func ( *Buffers) ( rune, ...rune) { := string()iflen() == 0 || == "" {return }if == 0 { .writeNum(0, []rune())return }// If number register. , := strconv.Atoi(string())if > 0 && < 10 && != nil { .writeNum(, []rune())return }// If lettered register.ifunicode.IsLetter() { .writeAlpha(, []rune())return }}// IsSelected returns the name of the selected register, and// true if one is indeed selected, or the default one and false.func ( *Buffers) () ( string, bool) {returnstring(.active), .selected}// Reset forgets any active/pending buffer/register, but does not delete its contents.func ( *Buffers) () { .active = 0 .waiting = false .selected = false}// Complete returns the contents of all buffers as a structured list of completions.func ( *Buffers) () completion.Values { := make([]completion.Candidate, 0)// Alpha and numbered registers = append(, .completeNumRegs()...) = append(, .completeAlphaRegs()...)// Disable sorting, force list long and add hint. := completion.AddRaw()if .NoSort == nil { .NoSort = make(map[string]bool) } .NoSort["*"] = trueif .ListLong == nil { .ListLong = make(map[string]bool) } .ListLong["*"] = true// Registers Hint := color.Bold + color.FgBlue + "(registers)"iflen() == 0 { += " - empty -" } .Messages.Add()return}func ( *Buffers) ( int, []rune) {// No numbered register above 10if > numRegisters-1 {return }// Add to the stack with the specified registerif > 0 { .num[] = return }// No push to the stack if we are already using 9for := len(.num); > 0; -- {if == numRegisters { -- } .num[] = append([]rune{}, .num[-1]...) } .num[0] = append([]rune{}, ...)}func ( *Buffers) ( rune, []rune) { := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" := falsefor , := range {if == { = unicode.ToLower(.active) , := .alpha[]if { .alpha[] = append(.alpha[], ...) } else { .alpha[] = } = true } }if ! { .alpha[] = }}func ( *Buffers) () []completion.Candidate { := make([]completion.Candidate, 0) := color.Dim + "num ([0-9])" + color.Resetvar []intfor := range .num { = append(, ) }sort.Ints()for , := range { := .num[] := strings.ReplaceAll(string(), "\n", ` `) := completion.Candidate{Tag: ,Value: string(),Display: fmt.Sprintf("%s\"%d%s %s", color.Dim, , color.DimReset, ), } = append(, ) }return}func ( *Buffers) () []completion.Candidate { := make([]completion.Candidate, 0) := color.Dim + "alpha ([a-z], [A-Z])" + color.Resetvar []runefor := range .alpha { = append(, ) }sort.Slice(, func(, int) bool { return < })for , := range { := .alpha[] := strings.ReplaceAll(string(), "\n", ` `) := completion.Candidate{Tag: ,Value: string(),Display: fmt.Sprintf("%s\"%s%s %s", color.Dim, string(), color.DimReset, ), } = append(, ) }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.