summary refs log blame commit diff stats
path: root/config/bindings.go
blob: a19d4f35c7ff2182ed587848e2ca725c27137c9c (plain) (tree)
24dfc47 ^





pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
package msg

import (
	"errors"
	"time"

	"github.com/gdamore/tcell"

	"git.sr.ht/~sircmpwn/aerc/widgets"
	"git.sr.ht/~sircmpwn/aerc/worker/types"
)

func init() {
	register("delete", DeleteMessage)
	register("delete-message", DeleteMessage)
}

func DeleteMessage(aerc *widgets.Aerc, args []string) error {
	if len(args) != 1 {
		return errors.New("Usage: :delete")
	}

	widget := aerc.SelectedTab().(widgets.ProvidesMessage)
	acct := widget.SelectedAccount()
	if acct == nil {
		return errors.New("No account selected")
	}
	store := widget.Store()
	msg := widget.SelectedMessage()
	_, isMsgView := widget.(*widgets.MessageViewer)
	if isMsgView {
		aerc.RemoveTab(widget)
	}
	store.Next()
	acct.Messages().Scroll()
	store.Delete([]uint32{msg.Uid}, func(msg types.WorkerMessage) {
		switch msg := msg.(type) {
		case *types.Done:
			aerc.PushStatus("Messages deleted.", 10*time.Second)
		case *types.Error:
			aerc.PushStatus(" "+msg.Error.Error(), 10*time.Second).
				Color(tcell.ColorDefault, tcell.ColorRed)
		}
	})
	return nil
}
'alt'>

 









                                                                        

                                                    
                                                              







                                                                        
                                                   



                                                    





                                                                      
















                                                            
                                     

























                                                                                      
                                                              
                                
                                                                                




























                                                                       

                                                         
                                                             














































































































                                                                

                                                                                  





                                                               








                                                    
                                                    






















                                                    
 
package config

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/gdamore/tcell"
)

type KeyStroke struct {
	Key  tcell.Key
	Rune rune
}

type Binding struct {
	Output []KeyStroke
	Input  []KeyStroke
}

type KeyBindings struct {
	bindings []*Binding

	// If false, disable global keybindings in this context
	Globals bool
	// Which key opens the ex line (default is :)
	ExKey KeyStroke
}

const (
	BINDING_FOUND = iota
	BINDING_INCOMPLETE
	BINDING_NOT_FOUND
)

type BindingSearchResult int

func NewKeyBindings() *KeyBindings {
	return &KeyBindings{
		ExKey:   KeyStroke{tcell.KeyRune, ':'},
		Globals: true,
	}
}

func MergeBindings(bindings ...*KeyBindings) *KeyBindings {
	merged := NewKeyBindings()
	for _, b := range bindings {
		merged.bindings = append(merged.bindings, b.bindings...)
	}
	merged.ExKey = bindings[0].ExKey
	merged.Globals = bindings[0].Globals
	return merged
}

func (bindings *KeyBindings) Add(binding *Binding) {
	// TODO: Search for conflicts?
	bindings.bindings = append(bindings.bindings, binding)
}

func (bindings *KeyBindings) GetBinding(
	input []KeyStroke) (BindingSearchResult, []KeyStroke) {

	incomplete := false
	// TODO: This could probably be a sorted list to speed things up
	// TODO: Deal with bindings that share a prefix
	for _, binding := range bindings.bindings {
		if len(binding.Input) < len(input) {
			continue
		}
		for i, stroke := range input {
			if stroke.Key != binding.Input[i].Key {
				goto next
			}
			if stroke.Key == tcell.KeyRune &&
				stroke.Rune != binding.Input[i].Rune {

				goto next
			}
		}
		if len(binding.Input) != len(input) {
			incomplete = true
		} else {
			return BINDING_FOUND, binding.Output
		}
	next:
	}
	if incomplete {
		return BINDING_INCOMPLETE, nil
	}
	return BINDING_NOT_FOUND, nil
}

var (
	keyNames map[string]KeyStroke
)

func ParseKeyStrokes(keystrokes string) ([]KeyStroke, error) {
	var strokes []KeyStroke
	buf := bytes.NewBufferString(keystrokes)
	for {
		tok, _, err := buf.ReadRune()
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, err
		}
		// TODO: make it possible to bind to < or > themselves (and default to
		// switching accounts)
		switch tok {
		case '<':
			name, err := buf.ReadString(byte('>'))
			if err == io.EOF {
				return nil, errors.New("Expecting '>'")
			} else if err != nil {
				return nil, err
			} else if name == ">" {
				return nil, errors.New("Expected a key name")
			}
			name = name[:len(name)-1]
			if key, ok := keyNames[strings.ToLower(name)]; ok {
				strokes = append(strokes, key)
			} else {
				return nil, fmt.Errorf("Unknown key '%s'", name)
			}
		case '>':
			return nil, errors.New("Found '>' without '<'")
		default:
			strokes = append(strokes, KeyStroke{
				Key:  tcell.KeyRune,
				Rune: tok,
			})
		}
	}
	return strokes, nil
}

func ParseBinding(input, output string) (*Binding, error) {
	in, err := ParseKeyStrokes(input)
	if err != nil {
		return nil, err
	}
	out, err := ParseKeyStrokes(output)
	if err != nil {
		return nil, err
	}
	return &Binding{
		Input:  in,
		Output: out,
	}, nil
}

func init() {
	keyNames = make(map[string]KeyStroke)
	keyNames["space"] = KeyStroke{tcell.KeyRune, ' '}
	keyNames["semicolon"] = KeyStroke{tcell.KeyRune, ';'}
	keyNames["enter"] = KeyStroke{tcell.KeyEnter, 0}
	keyNames["up"] = KeyStroke{tcell.KeyUp, 0}
	keyNames["down"] = KeyStroke{tcell.KeyDown, 0}
	keyNames["right"] = KeyStroke{tcell.KeyRight, 0}
	keyNames["left"] = KeyStroke{tcell.KeyLeft, 0}
	keyNames["upleft"] = KeyStroke{tcell.KeyUpLeft, 0}
	keyNames["upright"] = KeyStroke{tcell.KeyUpRight, 0}
	keyNames["downleft"] = KeyStroke{tcell.KeyDownLeft, 0}
	keyNames["downright"] = KeyStroke{tcell.KeyDownRight, 0}
	keyNames["center"] = KeyStroke{tcell.KeyCenter, 0}
	keyNames["pgup"] = KeyStroke{tcell.KeyPgUp, 0}
	keyNames["pgdn"] = KeyStroke{tcell.KeyPgDn, 0}
	keyNames["home"] = KeyStroke{tcell.KeyHome, 0}
	keyNames["end"] = KeyStroke{tcell.KeyEnd, 0}
	keyNames["insert"] = KeyStroke{tcell.KeyInsert, 0}
	keyNames["delete"] = KeyStroke{tcell.KeyDelete, 0}
	keyNames["help"] = KeyStroke{tcell.KeyHelp, 0}
	keyNames["exit"] = KeyStroke{tcell.KeyExit, 0}
	keyNames["clear"] = KeyStroke{tcell.KeyClear, 0}
	keyNames["cancel"] = KeyStroke{tcell.KeyCancel, 0}
	keyNames["print"] = KeyStroke{tcell.KeyPrint, 0}
	keyNames["pause"] = KeyStroke{tcell.KeyPause, 0}
	keyNames["backtab"] = KeyStroke{tcell.KeyBacktab, 0}
	keyNames["f1"] = KeyStroke{tcell.KeyF1, 0}
	keyNames["f2"] = KeyStroke{tcell.KeyF2, 0}
	keyNames["f3"] = KeyStroke{tcell.KeyF3, 0}
	keyNames["f4"] = KeyStroke{tcell.KeyF4, 0}
	keyNames["f5"] = KeyStroke{tcell.KeyF5, 0}
	keyNames["f6"] = KeyStroke{tcell.KeyF6, 0}
	keyNames["f7"] = KeyStroke{tcell.KeyF7, 0}
	keyNames["f8"] = KeyStroke{tcell.KeyF8, 0}
	keyNames["f9"] = KeyStroke{tcell.KeyF9, 0}
	keyNames["f10"] = KeyStroke{tcell.KeyF10, 0}
	keyNames["f11"] = KeyStroke{tcell.KeyF11, 0}
	keyNames["f12"] = KeyStroke{tcell.KeyF12, 0}
	keyNames["f13"] = KeyStroke{tcell.KeyF13, 0}
	keyNames["f14"] = KeyStroke{tcell.KeyF14, 0}
	keyNames["f15"] = KeyStroke{tcell.KeyF15, 0}
	keyNames["f16"] = KeyStroke{tcell.KeyF16, 0}
	keyNames["f17"] = KeyStroke{tcell.KeyF17, 0}
	keyNames["f18"] = KeyStroke{tcell.KeyF18, 0}
	keyNames["f19"] = KeyStroke{tcell.KeyF19, 0}
	keyNames["f20"] = KeyStroke{tcell.KeyF20, 0}
	keyNames["f21"] = KeyStroke{tcell.KeyF21, 0}
	keyNames["f22"] = KeyStroke{tcell.KeyF22, 0}
	keyNames["f23"] = KeyStroke{tcell.KeyF23, 0}
	keyNames["f24"] = KeyStroke{tcell.KeyF24, 0}
	keyNames["f25"] = KeyStroke{tcell.KeyF25, 0}
	keyNames["f26"] = KeyStroke{tcell.KeyF26, 0}
	keyNames["f27"] = KeyStroke{tcell.KeyF27, 0}
	keyNames["f28"] = KeyStroke{tcell.KeyF28, 0}
	keyNames["f29"] = KeyStroke{tcell.KeyF29, 0}
	keyNames["f30"] = KeyStroke{tcell.KeyF30, 0}
	keyNames["f31"] = KeyStroke{tcell.KeyF31, 0}
	keyNames["f32"] = KeyStroke{tcell.KeyF32, 0}
	keyNames["f33"] = KeyStroke{tcell.KeyF33, 0}
	keyNames["f34"] = KeyStroke{tcell.KeyF34, 0}
	keyNames["f35"] = KeyStroke{tcell.KeyF35, 0}
	keyNames["f36"] = KeyStroke{tcell.KeyF36, 0}
	keyNames["f37"] = KeyStroke{tcell.KeyF37, 0}
	keyNames["f38"] = KeyStroke{tcell.KeyF38, 0}
	keyNames["f39"] = KeyStroke{tcell.KeyF39, 0}
	keyNames["f40"] = KeyStroke{tcell.KeyF40, 0}
	keyNames["f41"] = KeyStroke{tcell.KeyF41, 0}
	keyNames["f42"] = KeyStroke{tcell.KeyF42, 0}
	keyNames["f43"] = KeyStroke{tcell.KeyF43, 0}
	keyNames["f44"] = KeyStroke{tcell.KeyF44, 0}
	keyNames["f45"] = KeyStroke{tcell.KeyF45, 0}
	keyNames["f46"] = KeyStroke{tcell.KeyF46, 0}
	keyNames["f47"] = KeyStroke{tcell.KeyF47, 0}
	keyNames["f48"] = KeyStroke{tcell.KeyF48, 0}
	keyNames["f49"] = KeyStroke{tcell.KeyF49, 0}
	keyNames["f50"] = KeyStroke{tcell.KeyF50, 0}
	keyNames["f51"] = KeyStroke{tcell.KeyF51, 0}
	keyNames["f52"] = KeyStroke{tcell.KeyF52, 0}
	keyNames["f53"] = KeyStroke{tcell.KeyF53, 0}
	keyNames["f54"] = KeyStroke{tcell.KeyF54, 0}
	keyNames["f55"] = KeyStroke{tcell.KeyF55, 0}
	keyNames["f56"] = KeyStroke{tcell.KeyF56, 0}
	keyNames["f57"] = KeyStroke{tcell.KeyF57, 0}
	keyNames["f58"] = KeyStroke{tcell.KeyF58, 0}
	keyNames["f59"] = KeyStroke{tcell.KeyF59, 0}
	keyNames["f60"] = KeyStroke{tcell.KeyF60, 0}
	keyNames["f61"] = KeyStroke{tcell.KeyF61, 0}
	keyNames["f62"] = KeyStroke{tcell.KeyF62, 0}
	keyNames["f63"] = KeyStroke{tcell.KeyF63, 0}
	keyNames["f64"] = KeyStroke{tcell.KeyF64, 0}
	keyNames["c-space"] = KeyStroke{tcell.KeyCtrlSpace, 0}
	keyNames["c-a"] = KeyStroke{tcell.KeyCtrlA, 0}
	keyNames["c-b"] = KeyStroke{tcell.KeyCtrlB, 0}
	keyNames["c-c"] = KeyStroke{tcell.KeyCtrlC, 0}
	keyNames["c-d"] = KeyStroke{tcell.KeyCtrlD, 0}
	keyNames["c-e"] = KeyStroke{tcell.KeyCtrlE, 0}
	keyNames["c-f"] = KeyStroke{tcell.KeyCtrlF, 0}
	keyNames["c-g"] = KeyStroke{tcell.KeyCtrlG, 0}
	keyNames["c-h"] = KeyStroke{tcell.KeyCtrlH, 0}
	keyNames["c-i"] = KeyStroke{tcell.KeyCtrlI, 0}
	keyNames["c-j"] = KeyStroke{tcell.KeyCtrlJ, 0}
	keyNames["c-k"] = KeyStroke{tcell.KeyCtrlK, 0}
	keyNames["c-l"] = KeyStroke{tcell.KeyCtrlL, 0}
	keyNames["c-m"] = KeyStroke{tcell.KeyCtrlM, 0}
	keyNames["c-n"] = KeyStroke{tcell.KeyCtrlN, 0}
	keyNames["c-o"] = KeyStroke{tcell.KeyCtrlO, 0}
	keyNames["c-p"] = KeyStroke{tcell.KeyCtrlP, 0}
	keyNames["c-q"] = KeyStroke{tcell.KeyCtrlQ, 0}
	keyNames["c-r"] = KeyStroke{tcell.KeyCtrlR, 0}
	keyNames["c-s"] = KeyStroke{tcell.KeyCtrlS, 0}
	keyNames["c-t"] = KeyStroke{tcell.KeyCtrlT, 0}
	keyNames["c-u"] = KeyStroke{tcell.KeyCtrlU, 0}
	keyNames["c-v"] = KeyStroke{tcell.KeyCtrlV, 0}
	keyNames["c-w"] = KeyStroke{tcell.KeyCtrlW, 0}
	keyNames["c-x"] = KeyStroke{tcell.KeyCtrlX, rune(tcell.KeyCAN)}
	keyNames["c-y"] = KeyStroke{tcell.KeyCtrlY, 0} // TODO: runes for the rest
	keyNames["c-z"] = KeyStroke{tcell.KeyCtrlZ, 0}
	keyNames["c-]"] = KeyStroke{tcell.KeyCtrlLeftSq, 0}
	keyNames["c-\\"] = KeyStroke{tcell.KeyCtrlBackslash, 0}
	keyNames["c-["] = KeyStroke{tcell.KeyCtrlRightSq, 0}
	keyNames["c-^"] = KeyStroke{tcell.KeyCtrlCarat, 0}
	keyNames["c-_"] = KeyStroke{tcell.KeyCtrlUnderscore, 0}
	keyNames["nul"] = KeyStroke{tcell.KeyNUL, 0}
	keyNames["soh"] = KeyStroke{tcell.KeySOH, 0}
	keyNames["stx"] = KeyStroke{tcell.KeySTX, 0}
	keyNames["etx"] = KeyStroke{tcell.KeyETX, 0}
	keyNames["eot"] = KeyStroke{tcell.KeyEOT, 0}
	keyNames["enq"] = KeyStroke{tcell.KeyENQ, 0}
	keyNames["ack"] = KeyStroke{tcell.KeyACK, 0}
	keyNames["bel"] = KeyStroke{tcell.KeyBEL, 0}
	keyNames["bs"] = KeyStroke{tcell.KeyBS, 0}
	keyNames["tab"] = KeyStroke{tcell.KeyTAB, 0}
	keyNames["lf"] = KeyStroke{tcell.KeyLF, 0}
	keyNames["vt"] = KeyStroke{tcell.KeyVT, 0}
	keyNames["ff"] = KeyStroke{tcell.KeyFF, 0}
	keyNames["cr"] = KeyStroke{tcell.KeyCR, 0}
	keyNames["so"] = KeyStroke{tcell.KeySO, 0}
	keyNames["si"] = KeyStroke{tcell.KeySI, 0}
	keyNames["dle"] = KeyStroke{tcell.KeyDLE, 0}
	keyNames["dc1"] = KeyStroke{tcell.KeyDC1, 0}
	keyNames["dc2"] = KeyStroke{tcell.KeyDC2, 0}
	keyNames["dc3"] = KeyStroke{tcell.KeyDC3, 0}
	keyNames["dc4"] = KeyStroke{tcell.KeyDC4, 0}
	keyNames["nak"] = KeyStroke{tcell.KeyNAK, 0}
	keyNames["syn"] = KeyStroke{tcell.KeySYN, 0}
	keyNames["etb"] = KeyStroke{tcell.KeyETB, 0}
	keyNames["can"] = KeyStroke{tcell.KeyCAN, 0}
	keyNames["em"] = KeyStroke{tcell.KeyEM, 0}
	keyNames["sub"] = KeyStroke{tcell.KeySUB, 0}
	keyNames["esc"] = KeyStroke{tcell.KeyESC, 0}
	keyNames["fs"] = KeyStroke{tcell.KeyFS, 0}
	keyNames["gs"] = KeyStroke{tcell.KeyGS, 0}
	keyNames["rs"] = KeyStroke{tcell.KeyRS, 0}
	keyNames["us"] = KeyStroke{tcell.KeyUS, 0}
	keyNames["del"] = KeyStroke{tcell.KeyDEL, 0}
}