wicore

package
v0.0.0-...-b1976e4 Latest Latest
Warning

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

Go to latest
Published: Feb 28, 2017 License: Apache-2.0 Imports: 9 Imported by: 4

Documentation

Overview

Package wicore implements all the interfaces to be shared between the wi editor process and its plugins.

It is strongly versioned via the SHA-1 of its interface.

Overview graph of the Editor and its hierarchical tree. In addition to knowing all Window as a tree, it has a direct link to every documents. This is because a document buffer may be loaded but not have any view associated, or two Views (panels) may be viewing the same Document.

      +------+
      |Editor|-------------+--------+
      +------+             |        |
          |                |        v
          v                |   +--------+
      +------+             |   |Document|
      |Window|             |   +--------+
      +------+             |
         |                 |
   +-----+-------+         |
   |             |         |
   v             v         |
+------+     +------+      |
|Window|     |Window|      |
+------+     +------+      |
                |          |
                v          |
              +----+       |
              |View|       |
              +----+       |
                |          |
                v          |
            +--------+     |
            |Document|<----+
            +--------+

A View references Commands specific to this View, keyboard mapping specific to this View and potentially a Document. Many View do not have a Document associated, like Status, the Command View, etc.

           +----+
           |View|
           +----+
             |
    +--------+---+------------+
    |            |            |
    v            v            v
+--------+ +-----------+ +--------+
|Commands| |KeyBindings| |Document|
+--------+ +-----------+ +--------+
    |
    |   +-------+
    +-->|Command|
    |   +-------+
    |
    |   +-------+
    +-->|Command|
        +-------+

Objects living exclusively in wi main process:

  • Editor
  • Window

Objects that can be in either in the wi main process or implemented (and brokered to the main process) in a plugin process implement the Proxyable interface.

Index

Constants

View Source
const (
	Scanning       = FileType("Scanning")
	Code           = FileType("Code")   // All files that can be considered "source code" in its broadest meaning.
	CodeCFamily    = FileType("Code.C") // C covers all C derivatives.
	CodeCC         = FileType("Code.C.C")
	CodeCCSource   = FileType("Code.C.C.Source")
	CodeCCHeader   = FileType("Code.C.C.Header")
	CodeCCPP       = FileType("Code.C.C++")
	CodeCCPPSource = FileType("Code.C.C++.Source")
	CodeCCPPHeader = FileType("Code.C.C++.Header")
	CodeGo         = FileType("Code.Go")
)

New types can safely be defined by a plugin.

View Source
const NumberEvents = 12

NumberEvents is the number of known events.

Variables

View Source
var AliasFor = lang.Map{
	lang.En: "Alias for \"%s\".",
}

AliasFor describes that a command is an alias.

View Source
var AliasNotFound = lang.Map{
	lang.En: "\"%s\" is an alias to command \"%s\" but this command is not registered.",
}

AliasNotFound describes an alias to another command did not resolve.

View Source
var GotPanic <-chan interface{}

GotPanic must be listened to in the main thread to know if a panic() call occured in any goroutine running under Go().

Functions

func CalculateVersion

func CalculateVersion() string

CalculateVersion returns the hex string of the hash of the primary interfaces for this package.

It traverses the Editor type recursively, expanding all types referenced recursively. This data is used to generate an hash that represents the "version" of this interface.

func GetKeyBindingCommand

func GetKeyBindingCommand(e Editor, mode KeyboardMode, key key.Press) string

GetKeyBindingCommand traverses the Editor's Window tree to find a View that has the key binding in its Keyboard mapping.

func Go

func Go(name string, f func())

Go wraps a call to wrap any panic() call and pipe it to the main goroutine.

This permits clean shutdown, like terminal cleanup or plugin closure, when the program crashes.

func MakeReadWriteCloser

func MakeReadWriteCloser(reader io.ReadCloser, writer io.WriteCloser) io.ReadWriteCloser

MakeReadWriteCloser creates a io.ReadWriteCloser out of one io.ReadCloser and one io.WriteCloser.

func PositionOnScreen

func PositionOnScreen(w Window) raster.Rect

PositionOnScreen returns the exact position on screen of a Window.

func PostCommand

func PostCommand(e EventRegistry, callback func(), cmdName string, args ...string)

PostCommand appends a Command at the end of the queue. It is a shortcut to e.TriggerCommands(EnqueuedCommands{...}).

Types

type BorderType

type BorderType int

BorderType defines the type of border for a Window.

const (
	// BorderNone means width is 0.
	BorderNone BorderType = iota
	// BorderSingle means width is 1.
	BorderSingle
	// BorderDouble means width is 1 despite its name, only the glyph is
	// different.
	BorderDouble
)

func (BorderType) String

func (i BorderType) String() string

type Command

type Command interface {
	// Name is the name of the command.
	Name() string
	// Handle executes the command.
	Handle(e EditorW, w Window, args ...string)
	// Category returns the category the command should be bucketed in, for help
	// documentation purpose.
	Category(e Editor, w Window) CommandCategory
	// ShortDesc returns a short description of the command in the language
	// requested.
	ShortDesc() string
	// LongDesc returns a long explanation of the command in the language
	// requested.
	LongDesc() string
}

Command describes a registered command that can be triggered directly at the command prompt, via a keybinding or a plugin.

A Command is immutable once created either by the editor process or by a plugin.

func GetCommand

func GetCommand(e Editor, w Window, cmdName string) Command

GetCommand traverses the Window hierarchy tree to find a View that has the command cmd in its Commands mapping. If Window is nil, it starts with the Editor's active Window.

type CommandAlias

type CommandAlias struct {
	NameValue    string
	CommandValue string
	ArgsValue    []string
}

CommandAlias references another command by its name. It's important to not bind directly to the Command reference, so that if a command is replaced by a plugin, that the replacement command is properly called by the alias.

func (*CommandAlias) Category

func (c *CommandAlias) Category(e Editor, w Window) CommandCategory

Category implements Command.

func (*CommandAlias) Handle

func (c *CommandAlias) Handle(e EditorW, w Window, args ...string)

Handle implements Command.

func (*CommandAlias) LongDesc

func (c *CommandAlias) LongDesc() string

LongDesc implements Command.

func (*CommandAlias) Name

func (c *CommandAlias) Name() string

Name implements Command.

func (*CommandAlias) ShortDesc

func (c *CommandAlias) ShortDesc() string

ShortDesc implements Command.

type CommandCategory

type CommandCategory int

CommandCategory is used to put commands into sections for help purposes.

const (
	// UnknownCategory means the command couldn't be categorized.
	UnknownCategory CommandCategory = iota
	// WindowCategory are commands relating to manipuling windows and UI in
	// general.
	WindowCategory
	// CommandsCategory are commands relating to manipulating commands, aliases,
	// keybindings.
	CommandsCategory
	// EditorCategory are commands relating to the editor lifetime.
	EditorCategory
	// DebugCategory are commands relating to debugging the app itself or plugins.
	DebugCategory
)

func (CommandCategory) String

func (i CommandCategory) String() string

type CommandHandler

type CommandHandler func(e EditorW, w Window, args ...string)

CommandHandler executes the command cmd on the Window w.

type CommandImpl

type CommandImpl struct {
	NameValue      string
	ExpectedArgs   int // If >= 0, the command will be aborted if the number of arguments is not exactly this value. Set to -1 to disable verification. On abort, an alert with the long description of the command is done.
	HandlerValue   CommandImplHandler
	CategoryValue  CommandCategory
	ShortDescValue lang.Map
	LongDescValue  lang.Map
}

CommandImpl is the boilerplate Command implementation.

func (*CommandImpl) Category

func (c *CommandImpl) Category(e Editor, w Window) CommandCategory

Category implements Command.

func (*CommandImpl) Handle

func (c *CommandImpl) Handle(e EditorW, w Window, args ...string)

Handle implements Command.

func (*CommandImpl) LongDesc

func (c *CommandImpl) LongDesc() string

LongDesc implements Command.

func (*CommandImpl) Name

func (c *CommandImpl) Name() string

Name implements Command.

func (*CommandImpl) ShortDesc

func (c *CommandImpl) ShortDesc() string

ShortDesc implements Command.

type CommandImplHandler

type CommandImplHandler func(c *CommandImpl, e EditorW, w Window, args ...string)

CommandImplHandler is the CommandHandler to use when coupled with CommandImpl.

type Commands

type Commands interface {
	// Get returns a command if registered, nil otherwise.
	Get(cmdName string) Command
	// GetNames() return the name of all the commands.
	GetNames() []string
}

Commands stores the known commands. This is where plugins can add new commands. Each View contains its own Commands.

type CommandsW

type CommandsW interface {
	Commands

	// Register registers a command so it can be executed later. In practice
	// commands should normally be registered on startup. Returns false if a
	// command was already registered and was lost.
	Register(cmd Command) bool
}

CommandsW is the writable version of Commands.

type DockingType

type DockingType int

DockingType defines the relative position of a Window relative to its parent.

const (
	// DockingUnknown is an invalid value.
	DockingUnknown DockingType = iota

	DockingFill
	// DockingFloating means the Window is not constrained by the parent window
	// size and location.
	DockingFloating

	DockingLeft
	DockingRight
	DockingTop
	DockingBottom
)

Available docking options.

func StringToDockingType

func StringToDockingType(s string) DockingType

StringToDockingType converts a string back to a DockingType.

func (DockingType) String

func (i DockingType) String() string

type Document

type Document interface {
	fmt.Stringer
	io.Closer
	Proxyable

	// RenderInto renders a view of a document.
	//
	// TODO(maruel): Likely return a new Buffer instance instead, for RPC
	// friendlyness. To be decided.
	RenderInto(buffer *raster.Buffer, view View, offsetColumn, offsetLine int)
	// FileType returns the file type as determined by the scanners.
	FileType() FileType
	// IsDirty is true if the content should be saved before quitting.
	IsDirty() bool
}

Document represents an open document. It can be accessed by zero, one or multiple View. For example the document may not be visible at all as a 'back buffer', may be loaded in a View or in multiple View, each having their own coloring and cursor position.

type Editor

type Editor interface {
	Proxyable
	EventRegistry

	// ActiveWindow returns the current active Window.
	ActiveWindow() Window
	// ViewFactoryNames return the name of all the view factories.
	ViewFactoryNames() []string
	// AllDocuments returns all the active documents. Some of them may not be in
	// a View.
	AllDocuments() []Document
	// AllPlugins returns details about all the loaded plugins.
	AllPlugins() []PluginDetails
	// KeyboardMode is global to the editor. It matches vim behavior. For example
	// in a 2-window setup while in insert mode, using Ctrl-O, Ctrl-W, Down will
	// move to the next window but will stay in insert mode.
	//
	// Technically, each View could have their own KeyboardMode but in practice
	// it just creates a cognitive overhead without much benefit.
	KeyboardMode() KeyboardMode
	// Version returns the version number of this build of wi.
	Version() string
}

Editor is the output device and the main process context. It shows the root window which covers the whole screen estate.

type EditorDetails

type EditorDetails struct {
	ID      string
	Version string
}

EditorDetails is sent over the wire to plugins.

type EditorW

type EditorW interface {
	Editor

	// ExecuteCommand executes a command now. This is only meant to run a command
	// reentrantly; e.g. running a command triggers another one. This usually
	// happens for key binding, command aliases, when a command triggers an error.
	//
	// TODO(maruel): Remove?
	ExecuteCommand(w Window, cmdName string, args ...string)
	// RegisterViewFactory makes a new view available by name.
	RegisterViewFactory(name string, viewFactory ViewFactory) bool
}

EditorW is the writable version of Editor.

type EnqueuedCommands

type EnqueuedCommands struct {
	Commands [][]string
	Callback func()
}

EnqueuedCommands is used internally to dispatch commands through EventRegistry.

type EventListener

type EventListener interface {
	io.Closer
}

EventListener is to be used to cancel an event listener.

type EventRegistry

type EventRegistry interface {
	EventTrigger

	RegisterCommands(callback func(cmds EnqueuedCommands)) EventListener
	RegisterDocumentCreated(callback func(doc Document)) EventListener
	RegisterDocumentCursorMoved(callback func(doc Document, col, row int)) EventListener
	RegisterEditorKeyboardModeChanged(callback func(mode KeyboardMode)) EventListener
	RegisterEditorLanguage(callback func(l lang.Language)) EventListener
	RegisterTerminalKeyPressed(callback func(k key.Press)) EventListener
	RegisterTerminalMetaKeyPressed(callback func(k key.Press)) EventListener
	RegisterTerminalResized(callback func()) EventListener
	RegisterViewActivated(callback func(view View)) EventListener
	RegisterViewCreated(callback func(view View)) EventListener
	RegisterWindowCreated(callback func(window Window)) EventListener
	RegisterWindowResized(callback func(window Window)) EventListener
}

EventRegistry permits to register callbacks that are called on events.

Warning: This interface is automatically generated.

type EventTrigger

type EventTrigger interface {
	// TriggerCommands dispatches one or multiple commands to the current active
	// listener. Normally, it's the View contained to the active Window. Using
	// this function guarantees that all the commands will be executed in order
	// without commands interfering.
	//
	// `callback` is called synchronously after the command is executed.
	TriggerCommands(cmds EnqueuedCommands)
	TriggerDocumentCreated(doc Document)
	TriggerDocumentCursorMoved(doc Document, col, row int)
	TriggerEditorKeyboardModeChanged(mode KeyboardMode)
	TriggerEditorLanguage(l lang.Language)
	TriggerTerminalKeyPressed(k key.Press)
	TriggerTerminalMetaKeyPressed(k key.Press)
	TriggerTerminalResized()
	TriggerViewActivated(view View)
	TriggerViewCreated(view View)
	TriggerWindowCreated(window Window)
	TriggerWindowResized(window Window)
}

EventTrigger declares the valid events that can be triggered.

Do not use this interface directly, use the automatically-generated interface EventRegistry instead.

type FileType

type FileType string

FileType is the type as determined by the scanner. It uses a hierarchical categorization of file formats.

func (FileType) Base

func (f FileType) Base() FileType

Base returns the base file type for this file type

type KeyBindings

type KeyBindings interface {
	// Get returns a command if registered, nil otherwise.
	Get(mode KeyboardMode, key key.Press) string
	// GetAssigned returns all the assigned keys for this mode.
	GetAssigned(mode KeyboardMode) []key.Press
}

KeyBindings stores the mapping between keyboard entry and commands. This includes what can be considered "macros" as much as casual things like arrow keys.

TODO(maruel): Right now there's two ways to add bindings, either through calls or through commands. Prefer one over the other.

type KeyBindingsW

type KeyBindingsW interface {
	KeyBindings

	// Set registers a keyboard mapping. In practice keyboard mappings
	// should normally be registered on startup. Returns false if a key mapping
	// was already registered and was lost. Set cmdName to "" to remove a key
	// binding.
	Set(mode KeyboardMode, key key.Press, cmdName string) bool
}

KeyBindingsW is the writable version of KeyBindings.

type KeyboardMode

type KeyboardMode int

KeyboardMode defines the keyboard mapping (input mode) to use.

Unlike vim, there's no Command-line and Ex modes. It's unnecessary because the command window is a Window on its own, instead of a additional input mode on the current Window.

TODO(maruel): vim also has visual/select which will be necessary.

const (
	// Normal is the mode where typing letters results in commands, not
	// content editing.
	Normal KeyboardMode = iota + 1
	// Insert is the mode where typing letters results in content, not
	// commands.
	Insert
	// AllMode is to bind keys independent of the current mode. It is useful for
	// function keys, Ctrl-<letter>, arrow keys, etc.
	AllMode
)

func (KeyboardMode) String

func (i KeyboardMode) String() string

type MultiCloser

type MultiCloser []io.Closer

MultiCloser closes multiple io.Closer at once.

func (MultiCloser) Close

func (m MultiCloser) Close() (err error)

Close implements io.Closer.

type Plugin

type Plugin interface {
	io.Closer
	fmt.Stringer

	// Details returns the plugin details for UI purposes. It's the first
	// function called and it is called synchronously. wicore/plugin provides a
	// trivial implementation.
	Details() PluginDetails

	// Init is called to do slower initialization part and is called
	// asynchronously as the editor process is started. When this function is
	// called, events are already registered and can fire simultaneously. It's up
	// to the plugin to handle these events properly.
	Init(e Editor)
}

Plugin is a simplified interface that represents a live plugin process. It's the high level object.

Communication flow goes this way:

Editor -> Plugin -> internal.PluginRPC -> net/rpc -> <process boundary> -> net/rpc -> internal.PluginRPC -> Plugin

The Plugin implementation in the editor process is a stub. Execution eventually flows up to the plugin process' Plugin instance.

type PluginDetails

type PluginDetails struct {
	Name        string
	Description string
}

PluginDetails is details for a plugin.

type Proxyable

type Proxyable interface {
	// ID represents the unique object id. The IDs must be unique through the
	// process lifetime of the editor.
	ID() string
}

Proxyable represents an object that can be proxied to a plugin.

type View

type View interface {
	fmt.Stringer
	io.Closer
	Proxyable

	// Commands returns the commands registered for this specific view. For
	// example a text window will have commands specific to the file type
	// enabled.
	Commands() Commands
	// KeyBindings returns the key bindings registered for this specific key. For
	// example the 'command' view has different behavior on up/down arrow keys
	// than a text editor view.
	KeyBindings() KeyBindings
	// Title is View's title, which can be the current file name or any other
	// relevant detail.
	Title() string
	// IsDisabled returns false if the View can be activated to receive user
	// inputs at all.
	IsDisabled() bool
	// Buffer returns the display buffer for this Window.
	Buffer() *raster.Buffer
	// NaturalSize returns the natural size of the content. It can be -1 for as
	// long/large as possible, 0 if indeterminate. The return value of this
	// function is not affected by SetSize().
	NaturalSize() (width, height int)
	// DefaultFormat returns the default coloring for this View. If this View has
	// an CellFormat.Empty()==true format, it will uses whatever parent Window's
	// View DefaultFormat().
	DefaultFormat() raster.CellFormat
}

View is content presented in a Window. For example it can be a TextBuffer or a command box. View define the key binding and commands supported so it responds to user input.

type ViewFactory

type ViewFactory func(e Editor, id int, args ...string) ViewW

ViewFactory returns a new View.

type ViewW

type ViewW interface {
	View

	// CommandsW returns the writeable interface of Commands.
	CommandsW() CommandsW
	// KeyBindingsW returns the writeable interface of KeyBindings.
	KeyBindingsW() KeyBindingsW
	// SetSize resets the View Buffer size.
	SetSize(x, y int)
	// OnAttach is called by the Window after it was attached.
	// TODO(maruel): Maybe split in ViewFull?
	OnAttach(w Window)
}

ViewW is the writable version of View.

type Window

type Window interface {
	fmt.Stringer
	Proxyable

	// Parent returns the parent Window.
	Parent() Window
	// ChildrenWindows returns a copy of the slice of children windows.
	ChildrenWindows() []Window
	// Rect returns the position based on the parent Window area, except if
	// Docking() is DockingFloating.
	Rect() raster.Rect
	// Docking returns where this Window is docked relative to the parent Window.
	// A DockingFloating window is effectively starting a new independent Rect.
	Docking() DockingType
	// View returns the View contained by this Window. There is exactly one.
	View() View
}

Window is a View container. It defines the position, Z-ordering via hierarchy and decoration. It can have multiple child windows. The child windows are not bounded by the parent window if DockingFloating is used. The Window itself doesn't interact with the user, since it only has a non-client area (the border). All the client area is covered by the View.

Split view is not supported. A 4-way merge setup can be created with the following Window setup as 4 child Window of the root Window:

+-----------+-----------+------------+
|  Remote   |Merge Base*|   Local    |
|DockingLeft|DockingFill|DockingRight|
|           |           |            |
+-----------+-----------+------------+
|              Result                |
|           DockingBottom            |
|                                    |
+------------------------------------+

* The Merge Base View can be either:

  • The root Window's View that is constained.
  • A child Window set as DockingFill. In this case, the root Window View is not visible.

The end result is that this use case doesn't require any "split" support. Further subdivision can be done via Window containment.

The Window interface exists for synchronous query but modifications (creation, closing, moving) are done asynchronously via commands. A set of privileged commands starting with the prefix "window_" can modify Window instances, designating the actual Window by its .ID() method.

func RootWindow

func RootWindow(w Window) Window

RootWindow returns the root Window when given any Window in the tree.

Directories

Path Synopsis
Package colors declare constants and functions to simplify color management.
Package colors declare constants and functions to simplify color management.
Package key implements generic key definition.
Package key implements generic key definition.
Package lang handles localization of language UI.
Package lang handles localization of language UI.
Package plugin implements the common code to implement a wi plugin.
Package plugin implements the common code to implement a wi plugin.
Package raster implements text buffering.
Package raster implements text buffering.

Jump to

Keyboard shortcuts

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