Help us shape the future of Go! Take the 2026 Go Developer Survey

editor

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: MIT Imports: 27 Imported by: 0

README

editor - a text editor widget for Go

Go Version License CI Go Reference

A syntax-highlighting, multi-cursor text editor widget for Go — hosted by tcell, or by any surface you draw yourself.

editor descends from the femto/micro line of Go text editors and keeps their core: a line-array buffer, rune-based cursors, micro-compatible syntax grammars and colorschemes, and an event-based undo history. It has since been detached from its host widget toolkit into a standalone module: the only UI dependency is github.com/gdamore/tcell/v3, a View draws onto a five-method Screen interface that a tcell screen satisfies as it is, and everything the editor needs from its host is a rectangle, a draw call and an event.


Table of Contents


Features

Area Capabilities
Buffer Line-array text storage, file path, per-buffer settings, dirty tracking, large-file mode
Editing Insert or overwrite mode, tabs and indentation, indent/outdent, duplicate and move lines, smart paste, auto-indent
Cursors Multiple independent cursors, each with its own selection; spawn, remove and skip cursors
Undo / redo Exact undo and redo from recorded text deltas, with time-based grouping and a bounded history
Selection Character, word, line, paragraph, page and "to start/end" selections, with multi-cursor highlighting
Clipboard Copy, cut, paste, cut-line, with an in-process fallback when the platform has no clipboard
Highlighting micro-compatible YAML syntax grammars, resolved per file type, with regex rules per syntax group
Colorschemes micro color-link schemes, parsed into a tcell.Style per syntax group
Autocomplete Provider interface, popup list with details, inline ghost text
Search Literal or regular expression search and replace, with optional case sensitivity
Rendering Line numbers, cursor-line highlight, color column, whitespace markers, soft wrap, scrollbar, wide runes and combining characters
Hosting A five-method Screen interface, one HandleEvent entry point, mouse-action classification, input capture, focus handling
Embedded data Syntax grammars and colorschemes shipped in the runtime subpackage
Demo A complete tcell host written without any framework

Quick Start

A View on a tcell screen

Nothing stands between the editor and tcell: open a screen, give the view a rectangle, and forward events.

package main

import (
	"os"

	"github.com/gdamore/tcell/v3"
	"github.com/malivvan/editor"
	"github.com/malivvan/editor/runtime"
)

func main() {
	src, _ := os.ReadFile("main.go")

	buf := editor.NewBufferFromString(string(src), "main.go")
	view := editor.NewView(buf)
	view.SetRuntimeFiles(runtime.Files) // syntax highlighting + colorschemes

	screen, err := tcell.NewScreen()
	if err != nil {
		panic(err)
	}
	if err := screen.Init(); err != nil {
		panic(err)
	}
	defer screen.Fini()
	screen.EnableMouse()

	// Ctrl-Q is the host's business, not the editor's.
	quit := false
	view.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		if event.Key() == tcell.KeyCtrlQ {
			quit = true
			return nil
		}
		return event
	})

	layout := func() {
		width, height := screen.Size()
		view.SetRect(0, 0, width, height)
	}
	layout()

	for event := range screen.EventQ() {
		switch event.(type) {
		case *tcell.EventKey, *tcell.EventMouse:
			view.HandleEvent(event)
		case *tcell.EventResize:
			screen.Sync()
			layout()
		}

		view.Draw(screen)
		screen.Show()

		if quit {
			return
		}
	}
}

Calling SetRect is optional: a view that was never given a rectangle expands to fill the screen on the first Draw.

Syntax highlighting and colorschemes

The grammar is picked from the buffer's path. For a scratch buffer that has no path, name the file type explicitly:

buf := editor.NewBufferFromString(src, "") // no path to infer a grammar from
buf.Settings["filetype"] = "go"

view := editor.NewView(buf)
view.SetRuntimeFiles(runtime.Files)

if file := runtime.Files.FindFile(editor.RTColorscheme, "monokai"); file != nil {
	if data, err := file.Data(); err == nil {
		view.SetColorscheme(editor.ParseColorscheme(string(data)))
	}
}
Autocomplete

A provider turns the editing context into completion items; the view renders them as a popup, as inline ghost text, or both.

view.SetAutocompleteProvider(func(ctx editor.CompletionContext) []editor.CompletionItem {
	if ctx.Prefix == "" {
		return nil
	}
	return []editor.CompletionItem{
		{Label: "Println", InsertText: "Println", InlineText: `Println("hello")`, Detail: "fmt · func"},
		{Label: "Printf", InsertText: "Printf", Detail: "fmt · func"},
	}
})

if view.TriggerAutocomplete() {
	// The popup is open; the user can keep typing, pick with the mouse, or
	// press Enter/Escape.
}

Installation

go get github.com/malivvan/editor

The package requires Go 1.27 or later, and pulls in github.com/gdamore/tcell/v3, github.com/atotto/clipboard, github.com/mattn/go-runewidth and github.com/sergi/go-diff.


Core Concepts

Buffer

Buffer holds the text of one file (or of one scratch pad) as a line array, together with its Path, its Settings map, its syntax highlighter and its undo history.

buf := editor.NewBufferFromString("hello\n", "greeting.txt") // from a string
buf := editor.NewBuffer(reader, size, "main.go", cursorPos)  // from a reader

Reading the text back is line based (buf.Line(n), buf.Lines(0, buf.LinesNum())) or whole-buffer (buf.String(), buf.Len()), and buf.Modified() reports whether anything was edited since the buffer was opened. Text over editor.LargeFileThreshold (50 000 bytes) switches to a cheaper dirty-tracking mode automatically.

Cursor and Loc

A Loc is a rune position — Loc{X: 2, Y: 1} is the third rune of the second line — so ASCII, combining marks and emoji all count as a single step. Byte offsets and visual columns are derived from it:

buf := editor.NewBufferFromString("gööse\n", "")
buf.Line(0)                              // "gööse"
editor.ByteOffset(editor.Loc{X: 3}, buf) // byte offset of the fourth rune
buf.Cursor.GetVisualX()                  // screen column, tabs expanded

Cursor moves (Up, DownN, WordRight, MoveTo), selects (SelectWord, SelectLine, SetSelectionStart/SetSelectionEnd) and reports (HasSelection, GetSelection). The editor keeps a slice of cursors on the buffer; that is what makes multiple cursors work — each cursor replays an action and gets its own selection drawn.

View

View is the window onto a buffer, and the only type a host deals with:

Method Purpose
NewView(buf) Create a view; it starts focused.
SetRect(x, y, w, h) / Rect() Place the view on the screen.
Draw(screen) Render the buffer, the popup and the cursor.
HandleEvent(event) Feed a tcell.Event (key or mouse).
Focus() / Blur() / SetFocus(bool) / HasFocus() Control whether the terminal cursor is placed.
SetInputCapture(fn) Intercept key events before the editor sees them.
SetKeybindings(b) / GetKeybindings() Replace the key bindings.
SetColorscheme(c) / SetRuntimeFiles(rf) Style the text and resolve grammars.
SetAutocompleteProvider(p) / TriggerAutocomplete() Configure and open completion.
OpenBuffer(buf) Swap the buffer under the view.
ExecuteActions(actions) Run actions programmatically.
ScrollUp(n) / ScrollDown(n) / Relocate() Drive the viewport.

The view also carries the viewport state a host may want to display: Topline (the first visible line), Readonly, and Cursor.

Screen

The rendering surface is deliberately tiny, which is what keeps the editor portable:

type Screen interface {
	SetContent(x, y int, ch rune, comb []rune, style tcell.Style)
	Get(x, y int) (str string, style tcell.Style, width int)
	Size() (width, height int)
	ShowCursor(x, y int)
	HideCursor()
}

A tcell.Screen — or the tcell.Screen interface value itself — satisfies this without a wrapper, so view.Draw(screen) is all a tcell host needs. Anything else that can write characters to a grid, read them back and place a cursor can implement it too; the tests do exactly that to prove the point.

Events, key bindings and actions

HandleEvent is the single entry point. Key events are passed to the input capture, then to the autocomplete popup, and finally to the key bindings: a KeyBindings map from KeyDesc to a list of actions.

// A KeyDesc is a key code, optionally with modifiers and a rune; the action
// names are the keys of editor.BindingActionsMapping.
bindings := editor.NewKeyBindings(map[string]string{
	"AltUp":    "MoveLinesUp,MoveLinesUp", // run two actions in sequence
	"CtrlHome": "CursorStart",
	"Alt-c":    "UnbindKey", // drop a default binding
})
view.SetKeybindings(bindings)

Actions are ordinary methods on View ((*View).CursorUp, (*View).Undo, (*View).SelectAll, (*View).ToggleRuler, …), so anything a binding can do a host can also do directly.

Mouse

Raw mouse events are classified by the view itself — position changes become MouseMove, button changes become MouseLeftDown/MouseLeftUp and friends, and wheel events become MouseScroll* — and each action is applied in turn:

view.HandleEvent(event)                   // classify and apply
view.HandleMouse(event)                   // same thing, explicit
view.HandleMouseAction(MouseLeftDown, event) // when the host already knows

Clicking moves the cursor, dragging selects, double and triple clicks select a word or a line, the wheel scrolls, and clicking inside the autocomplete popup picks an item. Events outside the view's rectangle are ignored.

Input capture

SetInputCapture installs a function that sees every key event first and may swallow it (return nil), forward it, or replace it — the hook for shortcuts that must never reach the buffer:

view.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
	switch event.Key() {
	case tcell.KeyCtrlS:
		save(buf)
		return nil
	case tcell.KeyCtrlQ:
		quit = true
		return nil
	}
	return event
})
Colorschemes

A Colorscheme maps a syntax group ("keyword", "string", "cursor-line", …) to a tcell.Style. ParseColorscheme reads micro's format, so existing schemes work unchanged:

color-link default "#F8F8F2,#282828"
color-link keyword "#F92672"
color-link string  "#E6DB74"

Colorscheme.GetColor walks dotted group names ("constant.bool" falls back to "constant"), and StringToColor accepts the colour names and hex values the schemes use.

Runtime files

RuntimeFiles is a registry of loadable resources grouped by kind (editor.RTColorscheme, editor.RTSyntax). The runtime subpackage embeds a set of grammars and colorschemes and exposes them pre-built:

view.SetRuntimeFiles(runtime.Files)

for _, file := range runtime.Files.ListRuntimeFiles(editor.RTColorscheme) {
	fmt.Println(file.Name()) // "monokai", "solarized", …
}

Add your own with AddFile or AddFilesFromDirectory.

Settings

Settings live on the buffer, with the defaults from DefaultLocalSettings: tabsize, tabstospaces, softwrap, scrollmargin, scrollspeed, cursorline, ruler, colorcolumn, showwhitespace, indentchar, autoindent, keepautoindent, smartpaste, matchbrace, matchbraceleft, tabmovement, syntax, filetype, hidecursoronblur, maxundohistory, fastdirty, fileformat.

buf.Settings["ruler"] = false        // no line numbers
buf.Settings["softwrap"] = true
buf.Settings["tabsize"] = float64(2) // numbers are float64
buf.Settings["filetype"] = "go"      // pick a grammar explicitly

A missing or wrongly typed value is treated as unset (with a warning in the log) rather than panicking.

Autocomplete

Completion is a two-step affair: an AutocompleteProvider turns the editing context into candidates, and the view renders them.

type CompletionContext struct {
	Buffer                     *Buffer
	View                       *View
	Cursor, WordStart, WordEnd Loc
	Prefix, Word, Line         string
}

type CompletionItem struct {
	Label, InsertText, InlineText, Detail string
	ReplaceStart, ReplaceEnd              *Loc
}

InlineText is what makes ghost text possible — the rest of the word is drawn faded after the cursor. DefaultAutocompleteProvider suggests distinct words already present in the buffer; pass nil to SetAutocompleteProvider to switch completion off. The popup opens while typing, and TriggerAutocomplete opens it programmatically.

Undo and redo

Every edit is recorded as a TextEvent with the deltas needed to reverse it, so Undo and Redo restore the exact previous state. A single Undo keeps unwinding edits that were recorded within 500 ms of each other, so a burst of typing is undone in one step, and the history is trimmed to the buffer's maxundohistory setting (10 000 by default). The stack itself is available as editor.Stack if a host wants to persist it.

Search and replace

Search and replace work on literal text or regular expressions:

found, err := view.Search("func", false, true, true)     // down, case sensitive
count, err := view.ReplaceAll("foo", false, true, "bar") // literal, case sensitive

Buffer.FindNext returns the match as a [2]Loc range, and Buffer.ReplaceRegex does the same with capture groups.

Clipboard

Copy, cut and paste use github.com/atotto/clipboard. When the platform has no clipboard at all — or a Unix session has neither DISPLAY nor WAYLAND_DISPLAY — the editor keeps an in-process clipboard instead, so the bindings still work in a bare SSH session.


Default key bindings

Up:             CursorUp
Down:           CursorDown
Right:          CursorRight
Left:           CursorLeft
ShiftUp:        SelectUp
ShiftDown:      SelectDown
ShiftLeft:      SelectLeft
ShiftRight:     SelectRight
AltLeft:        WordLeft
AltRight:       WordRight
AltUp:          MoveLinesUp
AltDown:        MoveLinesDown
AltShiftRight:  SelectWordRight
AltShiftLeft:   SelectWordLeft
CtrlLeft:       StartOfLine
CtrlRight:      EndOfLine
CtrlShiftLeft:  SelectToStartOfLine
ShiftHome:      SelectToStartOfLine
CtrlShiftRight: SelectToEndOfLine
ShiftEnd:       SelectToEndOfLine
CtrlUp:         CursorStart
CtrlDown:       CursorEnd
CtrlShiftUp:    SelectToStart
CtrlShiftDown:  SelectToEnd
Alt-{:          ParagraphPrevious
Alt-}:          ParagraphNext
Enter:          InsertNewline
CtrlH:          Backspace
Backspace:      Backspace
OldBackspace:   Backspace
Alt-CtrlH:      DeleteWordLeft
Alt-Backspace:  DeleteWordLeft
Tab:            IndentSelection,InsertTab
Backtab:        OutdentSelection,OutdentLine
CtrlZ:          Undo
CtrlY:          Redo
CtrlC:          Copy
CtrlX:          Cut
CtrlK:          CutLine
CtrlD:          DuplicateLine
CtrlV:          Paste
CtrlA:          SelectAll
Home:           StartOfLine
End:            EndOfLine
CtrlHome:       CursorStart
CtrlEnd:        CursorEnd
PageUp:         CursorPageUp
PageDown:       CursorPageDown
CtrlR:          ToggleRuler
Delete:         Delete
Insert:         ToggleOverwriteMode
Alt-f:          WordRight
Alt-b:          WordLeft
Alt-a:          StartOfLine
Alt-e:          EndOfLine
Esc:            Escape
Alt-n:          SpawnMultiCursor
Alt-m:          SpawnMultiCursorSelect
Alt-p:          RemoveMultiCursor
Alt-c:          RemoveAllMultiCursors
Alt-x:          SkipMultiCursor

Demo

The demo directory is a complete host built on tcell alone: it opens the screen, paints its own frame and status bar with plain tcell calls, and hands every key and mouse event to a single editor.View.

go run ./demo            # edit the built-in sample buffer
go run ./demo main.go    # edit a real file
Keys Action
Ctrl-S Save the buffer (no-op with a message for the sample).
Ctrl-Q Quit.
F1 Toggle line numbers.
F2 Cycle through the embedded colorschemes.

Typing a word opens the autocomplete popup; clicking moves the cursor, and dragging selects text.


Development

make test          # go test ./...
make test-race     # go test -race ./...
make cover         # coverage report
make lint          # go vet + gofmt check
make demo          # compile the demo

The CI workflow (.github/workflows/ci.yml) runs build, vet, formatting and the full test suite on every push, with the race detector and coverage on Linux.


Documentation


License

MIT — see LICENSE, and LICENSE-THIRD-PARTY for the code and data that came from other projects.


Acknowledgments

editor is a re-assembly of work done by others, and the code here was previously shipped as the editor package of github.com/malivvan/cui. Credit belongs to:

  • github.com/pgavlin/femto — Pat Gavlin. The original femto text editor: the buffer, view, cursor and key-binding design this package still follows, and the origin of much of the editing logic.
  • github.com/sedwards2009/femto — Simon Edwards. The maintained fork that this package's editor code was actually vendored from (commit dbf9395), and where the original editor was kept current and carried onto more recent Go terminal libraries.
  • github.com/micro-editor/micro — Zachary Yedidia and contributors. The syntax grammar format, the colorschemes and much of the runtime data embedded in the runtime subpackage come from micro's runtime files.

The package is built on libraries that deserve the same credit: github.com/gdamore/tcell (the terminal library it renders through) and github.com/atotto/clipboard, github.com/mattn/go-runewidth, github.com/sergi/go-diff (the libraries it depends on).

Documentation

Overview

Package editor is a text editor widget for Go terminal applications.

It provides the parts an editor is made of — a line-array Buffer, locating Cursors, syntax-highlighted cells, an undo history, key bindings and an autocomplete popup — behind a View that renders itself onto a Screen and consumes tcell events. The editing core descends from the femto/micro line of Go text editors; the README carries the full attribution.

Hosting a View

A View is not tied to a toolkit. It draws onto the Screen interface, a five-method subset of tcell.Screen that a tcell screen satisfies as it is, and it takes tcell events:

view := editor.NewView(editor.NewBufferFromString(src, "main.go"))
view.SetRuntimeFiles(runtime.Files) // syntax highlighting, colorschemes
view.SetRect(1, 1, width-2, height-2)
view.Draw(screen)

for event := range screen.EventQ() {
	switch event.(type) {
	case *tcell.EventKey, *tcell.EventMouse:
		view.HandleEvent(event)
	case *tcell.EventResize:
		screen.Sync()
		view.SetRect(1, 1, newWidth-2, newHeight-2)
	}
	view.Draw(screen)
	screen.Show()
}

Everything the host has to decide is where the view goes (SetRect), when it is drawn (Draw) and whether it holds the focus (Focus, Blur, SetFocus). The demo directory contains a complete host built exactly this way.

Buffers, cursors and views

Buffer stores the text — as a line array — together with the file's path, its local settings and its syntax highlighter. NewBufferFromString creates one from a string, NewBuffer from a reader plus an optional cursor position to restore.

Cursor holds a Loc, a rune-based {X, Y} position, its visual X offset and an optional selection. The editor keeps a list of them alive at once, which is how multiple cursors work: every cursor in the list replays an action and gets its own selection highlighted.

View owns the viewport around a buffer: Topline and the horizontal scroll offset, the colorscheme, the key bindings, the runtime files used for highlighting, and the autocomplete popup. OpenBuffer swaps the buffer under a view, ResetSelection and Relocate keep the cursor in sight.

Sorting out coordinates

Loc is a rune position, not a byte offset: Loc{X: 2, Y: 1} is the third rune of the second line, and ASCII, combining marks and emoji all count as one. Visual columns — what a tab or a wide character occupies on screen — are separate; GetVisualX, StringWidth and CellView are how the editor converts between the two.

Highlighting and colorschemes

The highlight subpackage implements micro-compatible syntax grammars: YAML files with a file-type header and a rule per syntax group. The runtime subpackage embeds a collection of those grammars along with the colorschemes that style them, and a view picks up both through SetRuntimeFiles. The grammar is chosen from the buffer's path, or from the buffer's "filetype" setting when there is no path to go by.

A Colorscheme maps a syntax group name to a tcell.Style, and ParseColorscheme reads micro's "color-link" statements, so existing schemes work unchanged.

Autocomplete

Completion is a two-step affair. An AutocompleteProvider turns the editing context — the word under the cursor, the buffer, the view — into CompletionItems, and the view renders them, either in a popup or as inline ghost text when CompletionItem.InlineText is set. DefaultAutocompleteProvider suggests words already present in the buffer; SetAutocompleteProvider replaces it and TriggerAutocomplete opens the popup programmatically.

Settings

Every buffer carries its own map of settings with the defaults from DefaultLocalSettings: tabsize, tabstospaces, softwrap, cursorline, ruler, showwhitespace, colorcolumn, scrollbar, scrollmargin, autoindent, smartpaste, syntax, filetype and friends. They are read and written through the map (buf.Settings["ruler"] = false), and a missing or wrongly typed value is treated as unset rather than fatal.

Events, keys and the mouse

HandleEvent is the single entry point: it routes key events to the input capture, then to the autocomplete popup, then to the key bindings, and it classifies mouse events into MouseActions before handing them to the same editing code. Hosts that already know which action a mouse event means can call HandleMouseAction directly, and hosts that need to see keys first install a function with SetInputCapture.

Key bindings map KeyDescs — a key code, optional modifiers and an optional rune — to a list of actions, which are plain methods on View. NewKeyBindings parses the familiar "Ctrl-S" style strings to build a custom set for SetKeybindings.

Undo, search and the clipboard

Edits go through an EventHandler that records them as text deltas, so Undo and Redo are exact. A single Undo keeps unwinding edits that were recorded within 500ms of each other, so a burst of typing is undone in one step, and the history is trimmed to the "maxundohistory" setting (10 000 by default). Search and ReplaceAll work on either literal text or regular expressions, with optional case sensitivity, through Buffer.FindNext.

Copy, cut and paste use github.com/atotto/clipboard, and fall back to an in-process clipboard when the platform has none (or when there is no X11 or Wayland session to talk to).

Thread safety

A View and its Buffer belong to the goroutine that owns the event loop; they are not safe for concurrent use. Rendering is no exception — Draw and HandleEvent should both run on that goroutine, which is also where the screen should be flushed.

Index

Constants

View Source
const (
	ActionCursorUp               = "CursorUp"
	ActionCursorDown             = "CursorDown"
	ActionCursorPageUp           = "CursorPageUp"
	ActionCursorPageDown         = "CursorPageDown"
	ActionCursorLeft             = "CursorLeft"
	ActionCursorRight            = "CursorRight"
	ActionCursorStart            = "CursorStart"
	ActionCursorEnd              = "CursorEnd"
	ActionSelectToStart          = "SelectToStart"
	ActionSelectToEnd            = "SelectToEnd"
	ActionSelectUp               = "SelectUp"
	ActionSelectDown             = "SelectDown"
	ActionSelectLeft             = "SelectLeft"
	ActionSelectRight            = "SelectRight"
	ActionWordRight              = "WordRight"
	ActionWordLeft               = "WordLeft"
	ActionSelectWordRight        = "SelectWordRight"
	ActionSelectWordLeft         = "SelectWordLeft"
	ActionDeleteWordRight        = "DeleteWordRight"
	ActionDeleteWordLeft         = "DeleteWordLeft"
	ActionSelectLine             = "SelectLine"
	ActionSelectToStartOfLine    = "SelectToStartOfLine"
	ActionSelectToEndOfLine      = "SelectToEndOfLine"
	ActionParagraphPrevious      = "ParagraphPrevious"
	ActionParagraphNext          = "ParagraphNext"
	ActionInsertNewline          = "InsertNewline"
	ActionInsertSpace            = "InsertSpace"
	ActionBackspace              = "Backspace"
	ActionDelete                 = "Delete"
	ActionInsertTab              = "InsertTab"
	ActionCenter                 = "Center"
	ActionUndo                   = "Undo"
	ActionRedo                   = "Redo"
	ActionCopy                   = "Copy"
	ActionCut                    = "Cut"
	ActionCutLine                = "CutLine"
	ActionDuplicateLine          = "DuplicateLine"
	ActionDeleteLine             = "DeleteLine"
	ActionMoveLinesUp            = "MoveLinesUp"
	ActionMoveLinesDown          = "MoveLinesDown"
	ActionIndentSelection        = "IndentSelection"
	ActionOutdentSelection       = "OutdentSelection"
	ActionOutdentLine            = "OutdentLine"
	ActionPaste                  = "Paste"
	ActionSelectAll              = "SelectAll"
	ActionStart                  = "Start"
	ActionEnd                    = "End"
	ActionPageUp                 = "PageUp"
	ActionPageDown               = "PageDown"
	ActionSelectPageUp           = "SelectPageUp"
	ActionSelectPageDown         = "SelectPageDown"
	ActionHalfPageUp             = "HalfPageUp"
	ActionHalfPageDown           = "HalfPageDown"
	ActionStartOfLine            = "StartOfLine"
	ActionEndOfLine              = "EndOfLine"
	ActionToggleRuler            = "ToggleRuler"
	ActionToggleOverwriteMode    = "ToggleOverwriteMode"
	ActionEscape                 = "Escape"
	ActionScrollUp               = "ScrollUp"
	ActionScrollDown             = "ScrollDown"
	ActionSpawnMultiCursor       = "SpawnMultiCursor"
	ActionSpawnMultiCursorSelect = "SpawnMultiCursorSelect"
	ActionRemoveMultiCursor      = "RemoveMultiCursor"
	ActionRemoveAllMultiCursors  = "RemoveAllMultiCursors"
	ActionSkipMultiCursor        = "SkipMultiCursor"
	ActionJumpToMatchingBrace    = "JumpToMatchingBrace"
	ActionInsertEnter            = "InsertEnter"
	ActionUnbindKey              = "UnbindKey"
)

Actions

View Source
const (

	// TextEventInsert represents an insertion event
	TextEventInsert = 1
	// TextEventRemove represents a deletion event
	TextEventRemove = -1
	// TextEventReplace represents a replace event
	TextEventReplace = 0
)
View Source
const (
	RTColorscheme = "colorscheme"
	RTSyntax      = "syntax"
)
View Source
const (
	MOUSE_BUTTON_MODE_SINGLE = iota
	MOUSE_BUTTON_MODE_DOUBLE
	MOUSE_BUTTON_MODE_TRIPLE
)
View Source
const DOUBLE_CLICK_INTERVAL = 500 * time.Millisecond
View Source
const LargeFileThreshold = 50000

Variables

View Source
var BindingActionsMapping = map[string]func(*View) bool{
	ActionCursorUp:               (*View).CursorUp,
	ActionCursorDown:             (*View).CursorDown,
	ActionCursorPageUp:           (*View).CursorPageUp,
	ActionCursorPageDown:         (*View).CursorPageDown,
	ActionCursorLeft:             (*View).CursorLeft,
	ActionCursorRight:            (*View).CursorRight,
	ActionCursorStart:            (*View).CursorStart,
	ActionCursorEnd:              (*View).CursorEnd,
	ActionSelectToStart:          (*View).SelectToStart,
	ActionSelectToEnd:            (*View).SelectToEnd,
	ActionSelectUp:               (*View).SelectUp,
	ActionSelectDown:             (*View).SelectDown,
	ActionSelectLeft:             (*View).SelectLeft,
	ActionSelectRight:            (*View).SelectRight,
	ActionWordRight:              (*View).WordRight,
	ActionWordLeft:               (*View).WordLeft,
	ActionSelectWordRight:        (*View).SelectWordRight,
	ActionSelectWordLeft:         (*View).SelectWordLeft,
	ActionDeleteWordRight:        (*View).DeleteWordRight,
	ActionDeleteWordLeft:         (*View).DeleteWordLeft,
	ActionSelectLine:             (*View).SelectLine,
	ActionSelectToStartOfLine:    (*View).SelectToStartOfLine,
	ActionSelectToEndOfLine:      (*View).SelectToEndOfLine,
	ActionParagraphPrevious:      (*View).ParagraphPrevious,
	ActionParagraphNext:          (*View).ParagraphNext,
	ActionInsertNewline:          (*View).InsertNewline,
	ActionInsertSpace:            (*View).InsertSpace,
	ActionBackspace:              (*View).Backspace,
	ActionDelete:                 (*View).Delete,
	ActionInsertTab:              (*View).InsertTab,
	ActionCenter:                 (*View).Center,
	ActionUndo:                   (*View).Undo,
	ActionRedo:                   (*View).Redo,
	ActionCopy:                   (*View).Copy,
	ActionCut:                    (*View).Cut,
	ActionCutLine:                (*View).CutLine,
	ActionDuplicateLine:          (*View).DuplicateLine,
	ActionDeleteLine:             (*View).DeleteLine,
	ActionMoveLinesUp:            (*View).MoveLinesUp,
	ActionMoveLinesDown:          (*View).MoveLinesDown,
	ActionIndentSelection:        (*View).IndentSelection,
	ActionOutdentSelection:       (*View).OutdentSelection,
	ActionOutdentLine:            (*View).OutdentLine,
	ActionPaste:                  (*View).Paste,
	ActionSelectAll:              (*View).SelectAll,
	ActionStart:                  (*View).Start,
	ActionEnd:                    (*View).End,
	ActionPageUp:                 (*View).PageUp,
	ActionPageDown:               (*View).PageDown,
	ActionSelectPageUp:           (*View).SelectPageUp,
	ActionSelectPageDown:         (*View).SelectPageDown,
	ActionHalfPageUp:             (*View).HalfPageUp,
	ActionHalfPageDown:           (*View).HalfPageDown,
	ActionStartOfLine:            (*View).StartOfLine,
	ActionEndOfLine:              (*View).EndOfLine,
	ActionToggleRuler:            (*View).ToggleRuler,
	ActionToggleOverwriteMode:    (*View).ToggleOverwriteMode,
	ActionEscape:                 (*View).Escape,
	ActionScrollUp:               (*View).ScrollUpAction,
	ActionScrollDown:             (*View).ScrollDownAction,
	ActionSpawnMultiCursor:       (*View).SpawnMultiCursor,
	ActionSpawnMultiCursorSelect: (*View).SpawnMultiCursorSelect,
	ActionRemoveMultiCursor:      (*View).RemoveMultiCursor,
	ActionRemoveAllMultiCursors:  (*View).RemoveAllMultiCursors,
	ActionSkipMultiCursor:        (*View).SkipMultiCursor,
	ActionJumpToMatchingBrace:    (*View).JumpToMatchingBrace,
	ActionInsertEnter:            (*View).InsertNewline,
}
View Source
var BindingKeysToTcellMapping = map[string]tcell.Key{}/* 120 elements not displayed */

Functions

func Abs

func Abs(n int) int

Abs is a simple absolute value function for ints

func ByteOffset

func ByteOffset(pos Loc, buf *Buffer) int

ByteOffset is just like ToCharPos except it counts bytes instead of runes

func CommonSubstring

func CommonSubstring(arr ...string) string

CommonSubstring gets a common substring among the inputs

func Contains

func Contains(list []string, a string) bool

Contains returns whether a string array contains a given string

func Count

func Count(s string) int

Count returns the length of a string in runes This is exactly equivalent to utf8.RuneCountInString(), just less characters

func DefaultLocalSettings

func DefaultLocalSettings() map[string]interface{}

DefaultLocalSettings returns the default local settings Note that filetype is a local only option

func Diff

func Diff(a, b Loc, buf *Buffer) int

Diff returns the distance between two locations

func EscapePath

func EscapePath(path string) string

EscapePath replaces every path separator in a given path with a %

func ExecuteTextEvent

func ExecuteTextEvent(t *TextEvent, buf *Buffer)

ExecuteTextEvent runs a text event

func FSize

func FSize(f *os.File) int64

FSize gets the size of a file

func FuncName

func FuncName(i interface{}) string

FuncName returns the full name of a given function object

func GetColor

func GetColor(color string) tcell.Style

GetColor takes in a syntax group and returns the colorscheme's style for that group

func GetColor256

func GetColor256(c int) tcell.Color

GetColor256 returns the tcell color for a number between 0 and 255

func GetLeadingWhitespace

func GetLeadingWhitespace(str string) string

GetLeadingWhitespace returns the leading whitespace of the given string

func GetModTime

func GetModTime(path string) (time.Time, bool)

GetModTime returns the last modification time for a given file It also returns a boolean if there was a problem accessing the file

func GetPathAndCursorPosition

func GetPathAndCursorPosition(path string) (string, []string)

GetPathAndCursorPosition returns a filename without everything following a `:` This is used for opening files like util.go:10:5 to specify a line and column Special cases like Windows Absolute path (C:\myfile.txt:10:5) are handled correctly.

func InBounds

func InBounds(pos Loc, buf *Buffer) bool

InBounds returns whether the given location is a valid character position in the given buffer

func Insert

func Insert(str string, pos int, value string) string

Insert makes a simple insert into a string at the given position

func IsSpaces

func IsSpaces(str []byte) bool

IsSpaces checks if a given string is only spaces

func IsSpacesOrTabs

func IsSpacesOrTabs(str string) bool

IsSpacesOrTabs checks if a given string contains only spaces and tabs

func IsStrWhitespace

func IsStrWhitespace(str string) bool

IsStrWhitespace returns true if the given string is all whitespace

func IsWhitespace

func IsWhitespace(c rune) bool

IsWhitespace returns true if the given rune is a space, tab, or newline

func IsWordChar

func IsWordChar(str string) bool

IsWordChar returns whether the string is a 'word character' If it is a unicode character, then it does not match Word characters are defined as [A-Za-z0-9_]

func MakeRelative

func MakeRelative(path, base string) (string, error)

MakeRelative will attempt to make a relative path between path and base

func Max

func Max(a, b int) int

Max takes the max of two ints

func Min

func Min(a, b int) int

Min takes the min of two ints

func NumOccurrences

func NumOccurrences(s string, c byte) int

NumOccurrences counts the number of occurrences of a byte in a string

func ParseBool

func ParseBool(str string) (bool, error)

ParseBool is almost exactly like strconv.ParseBool, except it also accepts 'on' and 'off' as 'true' and 'false' respectively

func SetDefaultColorscheme

func SetDefaultColorscheme(scheme Colorscheme)

SetDefaultColorscheme sets the current default colorscheme for new Views.

func ShortFuncName

func ShortFuncName(i interface{}) string

ShortFuncName returns the name only of a given function object

func Spaces

func Spaces(n int) string

Spaces returns a string with n spaces

func StringToColor

func StringToColor(str string) tcell.Color

StringToColor returns a tcell color from a string representation of a color We accept either bright... or light... to mean the brighter version of a color

func StringToStyle

func StringToStyle(str string, defaultStyle tcell.Style) tcell.Style

StringToStyle returns a style from a string The strings must be in the format "extra foregroundcolor,backgroundcolor" The 'extra' can be bold, reverse, or underline

func StringWidth

func StringWidth(str string, tabsize int) int

StringWidth returns the width of a string where tabs count as `tabsize` width

func ToCharPos

func ToCharPos(start Loc, buf *Buffer) int

ToCharPos converts from an x, y position to a character position

func UndoTextEvent

func UndoTextEvent(t *TextEvent, buf *Buffer)

UndoTextEvent undoes a text event

func WidthOfLargeRunes

func WidthOfLargeRunes(str string, tabsize int) int

WidthOfLargeRunes searches all the runes in a string and counts up all the widths of runes that have a width larger than 1 (this also counts tabs as `tabsize` width)

Types

type AutocompleteProvider

type AutocompleteProvider func(ctx CompletionContext) []CompletionItem

AutocompleteProvider returns completion candidates for the current context.

type Buffer

type Buffer struct {
	// The eventhandler for undo/redo
	*EventHandler
	// This stores all the text in the buffer as an array of lines
	*LineArray

	// The path to the loaded file, if any
	Path string

	Cursor Cursor

	// Whether the buffer has been modified since it was opened
	IsModified bool

	// NumLines is the number of lines in the buffer
	NumLines int

	// Buffer local settings
	Settings map[string]interface{}
	// contains filtered or unexported fields
}

Buffer stores the text for files that are loaded into the text editor It uses a rope to efficiently store the string and contains some simple functions for saving and wrapper functions for modifying the rope

func NewBuffer

func NewBuffer(reader io.Reader, size int64, path string, cursorPosition []string) *Buffer

NewBuffer creates a new buffer from a given reader

func NewBufferFromString

func NewBufferFromString(text, path string) *Buffer

NewBufferFromString creates a new buffer containing the given string

func (*Buffer) ClearMatches

func (b *Buffer) ClearMatches()

ClearMatches clears all of the syntax highlighting for this buffer

func (*Buffer) End

func (b *Buffer) End() Loc

End returns the location of the last character in the buffer

func (*Buffer) FileType

func (b *Buffer) FileType() string

FileType returns the buffer's filetype

func (*Buffer) FindMatchingBrace

func (b *Buffer) FindMatchingBrace(braceType [2]rune, start Loc) Loc

FindMatchingBrace returns the location in the buffer of the matching bracket It is given a brace type containing the open and closing character, (for example '{' and '}') as well as the location to match from

func (*Buffer) FindNext

func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, useRegex bool, caseSensitive bool) ([2]Loc, bool, error)

FindNext finds the next occurrence of a given string in the buffer It returns the start and end location of the match (if found) and a boolean indicating if it was found May also return an error if the search regex is invalid

func (*Buffer) GetName

func (b *Buffer) GetName() string

GetName returns the name that should be displayed in the statusline for this buffer

func (*Buffer) IndentString

func (b *Buffer) IndentString() string

IndentString returns a string representing one level of indentation

func (*Buffer) Len

func (b *Buffer) Len() (n int)

Len gives the length of the buffer

func (*Buffer) Line

func (b *Buffer) Line(n int) string

Line returns a single line

func (*Buffer) LineBytes

func (b *Buffer) LineBytes(n int) []byte

LineBytes returns a single line as an array of runes

func (*Buffer) LineRunes

func (b *Buffer) LineRunes(n int) []rune

LineRunes returns a single line as an array of runes

func (*Buffer) Lines

func (b *Buffer) Lines(start, end int) []string

Lines returns an array of strings containing the lines from start to end

func (*Buffer) LinesNum

func (b *Buffer) LinesNum() int

LinesNum returns the number of lines in the buffer

func (*Buffer) MarkDirty

func (b *Buffer) MarkDirty(lineN int)

MarkDirty marks a line as needing match invalidation on the next Draw.

func (*Buffer) MergeCursors

func (b *Buffer) MergeCursors()

MergeCursors merges any cursors that are at the same position into one cursor. Uses sort + single-pass scan (O(k log k)) instead of the previous O(k²) nested loop.

func (*Buffer) Modified

func (b *Buffer) Modified() bool

Modified returns if this buffer has been modified since being opened

func (*Buffer) MoveLinesDown

func (b *Buffer) MoveLinesDown(start int, end int)

MoveLinesDown moves the range of lines down one row

func (*Buffer) MoveLinesUp

func (b *Buffer) MoveLinesUp(start int, end int)

MoveLinesUp moves the range of lines up one row

func (*Buffer) ReplaceRegex

func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, replace []byte, captureGroups bool) (int, int)

ReplaceRegex replaces all occurrences of 'search' with 'replace' in the given area and returns the number of replacements made and the number of characters added or removed on the last line of the range

func (*Buffer) RuneAt

func (b *Buffer) RuneAt(loc Loc) rune

RuneAt returns the rune at a given location in the buffer

func (*Buffer) Start

func (b *Buffer) Start() Loc

Start returns the location of the first character in the buffer

func (*Buffer) UpdateCursors

func (b *Buffer) UpdateCursors()

UpdateCursors updates all the cursors indicies

type CellView

type CellView struct {
	// contains filtered or unexported fields
}

func (*CellView) Draw

func (c *CellView) Draw(buf *Buffer, colorscheme Colorscheme, top, height, left, width int)

type Char

type Char struct {
	// contains filtered or unexported fields
}

type Colorscheme

type Colorscheme map[string]tcell.Style

Colorscheme is a map from string to style -- it represents a colorscheme

func ParseColorscheme

func ParseColorscheme(text string) Colorscheme

ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object Colorschemes are made up of color-link statements linking a color group to a list of colors For example, color-link keyword (blue,red) makes all keywords have a blue foreground and red background

func (Colorscheme) GetColor

func (colorscheme Colorscheme) GetColor(color string) tcell.Style

GetColor takes in a syntax group and returns the colorscheme's style for that group

func (Colorscheme) GetDefault

func (colorscheme Colorscheme) GetDefault() tcell.Style

type CompletionContext

type CompletionContext struct {
	Buffer    *Buffer
	View      *View
	Cursor    Loc
	WordStart Loc
	WordEnd   Loc
	Prefix    string
	Word      string
	Line      string
}

CompletionContext describes the editor state for autocomplete providers.

type CompletionItem

type CompletionItem struct {
	Label        string
	InsertText   string
	InlineText   string
	Detail       string
	ReplaceStart *Loc
	ReplaceEnd   *Loc
}

CompletionItem represents one autocomplete candidate.

func DefaultAutocompleteProvider

func DefaultAutocompleteProvider(ctx CompletionContext) []CompletionItem

DefaultAutocompleteProvider suggests distinct words from the current buffer.

type Cursor

type Cursor struct {
	Loc

	// Last cursor x position
	LastVisualX int

	// The current selection as a range of character numbers (inclusive)
	CurSelection [2]Loc
	// The original selection as a range of character numbers
	// This is used for line and word selection where it is necessary
	// to know what the original selection was
	OrigSelection [2]Loc

	// Which cursor index is this (for multiple cursors)
	Num int
	// contains filtered or unexported fields
}

The Cursor struct stores the location of the cursor in the view The complicated part about the cursor is storing its location. The cursor must be displayed at an x, y location, but since the buffer uses a rope to store text, to insert text we must have an index. It is also simpler to use character indicies for other tasks such as selection.

func (*Cursor) AddLineToSelection

func (c *Cursor) AddLineToSelection()

AddLineToSelection adds the current line to the selection

func (*Cursor) AddWordToSelection

func (c *Cursor) AddWordToSelection()

AddWordToSelection adds the word the cursor is currently on to the selection

func (*Cursor) CopySelection

func (c *Cursor) CopySelection(target string)

CopySelection copies the user's selection to either "primary" or "clipboard"

func (*Cursor) DeleteSelection

func (c *Cursor) DeleteSelection()

DeleteSelection deletes the currently selected text

func (*Cursor) Down

func (c *Cursor) Down()

Down moves the cursor down one line (if possible)

func (*Cursor) DownN

func (c *Cursor) DownN(amount int)

DownN moves the cursor down N lines (if possible)

func (*Cursor) End

func (c *Cursor) End()

End moves the cursor to the end of the line it is on

func (*Cursor) GetCharPosInLine

func (c *Cursor) GetCharPosInLine(lineNum, visualPos int) int

GetCharPosInLine gets the char position of a visual x y coordinate (this is necessary because tabs are 1 char but 4 visual spaces)

func (*Cursor) GetSelection

func (c *Cursor) GetSelection() string

GetSelection returns the cursor's selection

func (*Cursor) GetVisualX

func (c *Cursor) GetVisualX() int

GetVisualX returns the x value of the cursor in visual spaces

func (*Cursor) Goto

func (c *Cursor) Goto(b Cursor)

Goto puts the cursor at the given cursor's location and gives the current cursor its selection too

func (*Cursor) GotoLoc

func (c *Cursor) GotoLoc(l Loc)

GotoLoc puts the cursor at the given cursor's location and gives the current cursor its selection too

func (*Cursor) HasSelection

func (c *Cursor) HasSelection() bool

HasSelection returns whether the user has selected anything

func (*Cursor) Left

func (c *Cursor) Left()

Left moves the cursor left one cell (if possible) or to the previous line if it is at the beginning

func (*Cursor) MoveTo

func (c *Cursor) MoveTo(loc Loc)

func (*Cursor) Relocate

func (c *Cursor) Relocate()

Relocate makes sure that the cursor is inside the bounds of the buffer If it isn't, it moves it to be within the buffer's lines

func (*Cursor) ResetSelection

func (c *Cursor) ResetSelection()

ResetSelection resets the user's selection

func (*Cursor) Right

func (c *Cursor) Right()

Right moves the cursor right one cell (if possible) or to the next line if it is at the end

func (*Cursor) RuneUnder

func (c *Cursor) RuneUnder(x int) rune

RuneUnder returns the rune under the given x position

func (*Cursor) SelectLine

func (c *Cursor) SelectLine()

SelectLine selects the current line

func (*Cursor) SelectTo

func (c *Cursor) SelectTo(loc Loc)

SelectTo selects from the current cursor location to the given location

func (*Cursor) SelectWord

func (c *Cursor) SelectWord()

SelectWord selects the word the cursor is currently on

func (*Cursor) SetSelectionEnd

func (c *Cursor) SetSelectionEnd(pos Loc)

SetSelectionEnd sets the end of the selection

func (*Cursor) SetSelectionStart

func (c *Cursor) SetSelectionStart(pos Loc)

SetSelectionStart sets the start of the selection

func (*Cursor) Start

func (c *Cursor) Start()

Start moves the cursor to the start of the line it is on

func (*Cursor) StartOfText

func (c *Cursor) StartOfText()

StartOfText moves the cursor to the first non-whitespace rune of the line it is on

func (*Cursor) StoreVisualX

func (c *Cursor) StoreVisualX()

StoreVisualX stores the current visual x value in the cursor

func (*Cursor) Up

func (c *Cursor) Up()

Up moves the cursor up one line (if possible)

func (*Cursor) UpN

func (c *Cursor) UpN(amount int)

UpN moves the cursor up N lines (if possible)

func (*Cursor) WordLeft

func (c *Cursor) WordLeft()

WordLeft moves the cursor one word to the left

func (*Cursor) WordRight

func (c *Cursor) WordRight()

WordRight moves the cursor one word to the right

type Delta

type Delta struct {
	Text  []byte
	Start Loc
	End   Loc
}

A Delta is a change to the buffer

type Element

type Element struct {
	Value *TextEvent
	Next  *Element
}

An Element which is stored in the Stack

type EventHandler

type EventHandler struct {
	UndoStack *Stack
	RedoStack *Stack
	// contains filtered or unexported fields
}

EventHandler executes text manipulations and allows undoing and redoing

func NewEventHandler

func NewEventHandler(buf *Buffer) *EventHandler

NewEventHandler returns a new EventHandler

func (*EventHandler) ApplyDiff

func (eh *EventHandler) ApplyDiff(new string)

ApplyDiff takes a string and runs the necessary insertion and deletion events to make the buffer equal to that string This means that we can transform the buffer into any string and still preserve undo/redo through insert and delete events

func (*EventHandler) Execute

func (eh *EventHandler) Execute(t *TextEvent)

Execute a textevent and add it to the undo stack

func (*EventHandler) Insert

func (eh *EventHandler) Insert(start Loc, textStr string)

Insert creates an insert text event and executes it

func (*EventHandler) MultipleReplace

func (eh *EventHandler) MultipleReplace(deltas []Delta)

MultipleReplace creates an multiple insertions executes them

func (*EventHandler) Redo

func (eh *EventHandler) Redo()

Redo the first event in the redo stack

func (*EventHandler) RedoOneEvent

func (eh *EventHandler) RedoOneEvent()

RedoOneEvent redoes one event

func (*EventHandler) Remove

func (eh *EventHandler) Remove(start, end Loc)

Remove creates a remove text event and executes it

func (*EventHandler) Replace

func (eh *EventHandler) Replace(start, end Loc, replace string)

Replace deletes from start to end and replaces it with the given string

func (*EventHandler) Undo

func (eh *EventHandler) Undo()

Undo the first event in the undo stack

func (*EventHandler) UndoOneEvent

func (eh *EventHandler) UndoOneEvent()

UndoOneEvent undoes one event

type KeyBindings

type KeyBindings map[KeyDesc][]func(*View) bool

KeyBindings associates key presses with view actions.

var DefaultKeyBindings KeyBindings

func NewKeyBindings

func NewKeyBindings(bindings map[string]string) KeyBindings

NewKeyBindings returns a new set of keybindings from the given set of binding descriptions.

func (KeyBindings) BindKey

func (bindings KeyBindings) BindKey(key string, actions string) KeyBindings

BindKey binds a key to a list of actions. If the key is not found or if any action is not found, this function has no effect.

func (KeyBindings) BindKeys

func (bindings KeyBindings) BindKeys(keys map[string]string) KeyBindings

BindKeys binds a set of keys to actions.

type KeyDesc

type KeyDesc struct {
	KeyCode   tcell.Key
	Modifiers tcell.ModMask
	R         rune
}

KeyDesc holds the data for a keypress (keycode + modifiers)

func NewKeyDesc

func NewKeyDesc(k string) (b KeyDesc, ok bool)

NewKeyDesc will find binding Key 'b' using string 'k'

type Line

type Line struct {
	// contains filtered or unexported fields
}

A Line contains the data in bytes as well as a highlight state, match and a flag for whether the highlighting needs to be updated

func Append

func Append(slice []Line, data ...Line) []Line

Append efficiently appends lines together It allocates an additional 10000 lines if the original estimate is incorrect

type LineArray

type LineArray struct {
	// contains filtered or unexported fields
}

A LineArray simply stores and array of lines and makes it easy to insert and delete in it

func NewLineArray

func NewLineArray(size uint64, reader io.Reader) (*LineArray, int)

NewLineArray returns a new line array from an array of bytes and the detected line ending format.

func (*LineArray) Bytes

func (la *LineArray) Bytes(useCrlf bool) []byte

Bytes returns the string that should be written to disk when the line array is saved

func (*LineArray) DeleteByte

func (la *LineArray) DeleteByte(pos Loc)

DeleteByte deletes the byte at a position

func (*LineArray) DeleteFromStart

func (la *LineArray) DeleteFromStart(pos Loc)

DeleteFromStart deletes from the start of a line to the position

func (*LineArray) DeleteLine

func (la *LineArray) DeleteLine(y int)

DeleteLine deletes the line number

func (*LineArray) DeleteToEnd

func (la *LineArray) DeleteToEnd(pos Loc)

DeleteToEnd deletes from the end of a line to the position

func (*LineArray) JoinLines

func (la *LineArray) JoinLines(a, b int)

JoinLines joins the two lines a and b

func (*LineArray) Match

func (la *LineArray) Match(lineN int) highlight.LineMatch

Match retrieves the match for the given line number

func (*LineArray) NewlineBelow

func (la *LineArray) NewlineBelow(y int)

NewlineBelow adds a newline below the given line number

func (*LineArray) SaveString

func (la *LineArray) SaveString(useCrlf bool) string

SaveString returns the string that should be written to disk when the line array is saved It is the same as string but uses crlf or lf line endings depending

func (*LineArray) SetMatch

func (la *LineArray) SetMatch(lineN int, m highlight.LineMatch)

SetMatch sets the match at the given line number

func (*LineArray) SetState

func (la *LineArray) SetState(lineN int, s highlight.State)

SetState sets the highlight state at the given line number

func (*LineArray) Split

func (la *LineArray) Split(pos Loc)

Split splits a line at a given position

func (*LineArray) State

func (la *LineArray) State(lineN int) highlight.State

State gets the highlight state for the given line number

func (*LineArray) String

func (la *LineArray) String() string

Returns the String representation of the LineArray

func (*LineArray) Substr

func (la *LineArray) Substr(start, end Loc) []byte

Substr returns the string representation between two locations

type Loc

type Loc struct {
	X, Y int
}

Loc stores a location

func FromCharPos

func FromCharPos(loc int, buf *Buffer) Loc

FromCharPos converts from a character position to an x, y position

func (Loc) Clamp

func (l Loc) Clamp(start, end Loc) Loc

Clamp clamps a loc between start and end

func (Loc) GreaterEqual

func (l Loc) GreaterEqual(b Loc) bool

GreaterEqual returns true if b is greater than or equal to b

func (Loc) GreaterThan

func (l Loc) GreaterThan(b Loc) bool

GreaterThan returns true if b is bigger

func (Loc) LessEqual

func (l Loc) LessEqual(b Loc) bool

LessEqual returns true if b is less than or equal to b

func (Loc) LessThan

func (l Loc) LessThan(b Loc) bool

LessThan returns true if b is smaller

func (Loc) Move

func (l Loc) Move(n int, buf *Buffer) Loc

Move moves the cursor n characters to the left or right It moves the cursor left if n is negative

type MouseAction

type MouseAction int16

MouseAction is the logical action a mouse event represents.

View derives these actions from raw tcell mouse events (see View.HandleMouse); a host that keeps its own input layer may instead call View.HandleMouseAction directly with the action it already knows.

const (
	MouseMove MouseAction = iota
	MouseLeftDown
	MouseLeftUp
	MouseMiddleDown
	MouseMiddleUp
	MouseRightDown
	MouseRightUp
	MouseScrollUp
	MouseScrollDown
	MouseScrollLeft
	MouseScrollRight
)

Mouse actions recognized by the editor.

There are no click or double click actions: the editor tells consecutive clicks apart itself, from the time between the down and the up events (see DOUBLE_CLICK_INTERVAL).

type RuntimeFile

type RuntimeFile interface {
	// Name returns a name of the file without paths or extensions
	Name() string
	// Data returns the content of the file.
	Data() ([]byte, error)
}

RuntimeFile allows the program to read runtime data like colorschemes or syntax files

type RuntimeFiles

type RuntimeFiles struct {
	// contains filtered or unexported fields
}

RuntimeFiles tracks a set of runtime files.

func NewRuntimeFiles

func NewRuntimeFiles(fs http.FileSystem) *RuntimeFiles

NewRuntimeFiles creates a new set of runtime files from the colorscheme and syntax files present in the given http.Filesystme. Colorschemes should be located under "/colorschemes" and must end with a "micro" extension. Syntax files should be located under "/syntax" and must end with a "yaml" extension.

func (*RuntimeFiles) AddFile

func (rfs *RuntimeFiles) AddFile(fileType string, file RuntimeFile)

AddRuntimeFile registers a file for the given filetype

func (*RuntimeFiles) AddFilesFromDirectory

func (rfs *RuntimeFiles) AddFilesFromDirectory(fs http.FileSystem, fileType, directory, pattern string)

AddFilesFromDirectory registers each file from the given directory for the filetype which matches the file-pattern

func (RuntimeFiles) FindFile

func (rfs RuntimeFiles) FindFile(fileType, name string) RuntimeFile

FindFile finds a runtime file of the given filetype and name will return nil if no file was found

func (RuntimeFiles) ListRuntimeFiles

func (rfs RuntimeFiles) ListRuntimeFiles(fileType string) []RuntimeFile

ListRuntimeFiles lists all known runtime files for the given filetype

type Screen

type Screen interface {
	// SetContent writes ch with the combining runes comb and the given style
	// to the cell at x, y. Coordinates outside the surface are ignored.
	SetContent(x, y int, ch rune, comb []rune, style tcell.Style)

	// Get returns the contents of the cell at x, y: its string, its style and
	// its width in cells. The editor uses it to read back the character that
	// sits under an additional cursor, and the style of the cell just before
	// the cursor, which the ghost text of the autocomplete blends into.
	Get(x, y int) (str string, style tcell.Style, width int)

	// Size returns the width and height of the surface in cells.
	Size() (width, height int)

	// ShowCursor places the terminal cursor at x, y.
	ShowCursor(x, y int)

	// HideCursor hides the terminal cursor.
	HideCursor()
}

Screen is the rendering surface the editor draws onto.

It is a deliberately small subset of tcell.Screen, so a tcell screen — or the tcell.Screen interface value itself — satisfies it as it is. A host that renders somewhere else (an in-memory grid, a network client, an image) can implement these five methods and get the same output as a terminal.

type ScrollBar

type ScrollBar struct {
	// contains filtered or unexported fields
}

ScrollBar represents an optional scrollbar that can be used

func (*ScrollBar) Display

func (sb *ScrollBar) Display(screen Screen)

Display shows the scrollbar

type Stack

type Stack struct {
	Top  *Element
	Size int
}

Stack is a simple implementation of a LIFO stack for text events

func (*Stack) Len

func (s *Stack) Len() int

Len returns the stack's length

func (*Stack) Peek

func (s *Stack) Peek() *TextEvent

Peek returns the top element of the stack without removing it

func (*Stack) Pop

func (s *Stack) Pop() (value *TextEvent)

Pop removes the top element from the stack and returns its value If the stack is empty, return nil

func (*Stack) Push

func (s *Stack) Push(value *TextEvent)

Push a new element onto the stack

func (*Stack) Trim

func (s *Stack) Trim(max int)

Trim removes the oldest elements so that the stack contains at most max elements. It walks from the top to the (max)th element and cuts the tail.

type TextEvent

type TextEvent struct {
	C Cursor

	EventType int
	Deltas    []Delta
	Time      time.Time
}

TextEvent holds data for a manipulation on some text that can be undone

type View

type View struct {
	// A pointer to the buffer's cursor for ease of access
	Cursor *Cursor

	// The topmost line, used for vertical scrolling
	Topline int

	// Specifies whether this view is readonly
	Readonly bool

	// The buffer
	Buf *Buffer
	// contains filtered or unexported fields
}

View is a window onto a Buffer. It owns the viewport (scrolling, soft wrap, line numbers), the cursor set, the key bindings, the colorscheme and the optional autocomplete popup.

A View draws itself onto a Screen, which is a small subset of tcell.Screen — a tcell screen satisfies it as it is — and consumes tcell events. It has no opinion on how it is hosted: the same View can be the only thing on a tcell screen (see the demo), a pane of a larger application, or the source of a buffer that is rendered to an image.

func NewView

func NewView(buf *Buffer) *View

NewView returns a new view with the specified buffer.

The view is focused from the start; call Blur to take the focus away. Its rectangle is empty until SetRect is called, which makes Draw fall back to filling the whole screen.

func (*View) Backspace

func (v *View) Backspace() bool

Backspace deletes the previous character

func (*View) Blur

func (v *View) Blur()

Blur takes the focus away from the view.

func (*View) Bottomline

func (v *View) Bottomline() int

Bottomline returns the line number of the lowest line in the view You might think that this is obviously just v.Topline + v.height but if softwrap is enabled things get complicated since one buffer line can take up multiple lines in the view

func (*View) Center

func (v *View) Center() bool

Center centers the view on the cursor

func (*View) Copy

func (v *View) Copy() bool

Copy the selection to the system clipboard

func (*View) CursorDown

func (v *View) CursorDown() bool

CursorDown moves the cursor down

func (*View) CursorEnd

func (v *View) CursorEnd() bool

CursorEnd moves the cursor to the end of the buffer

func (*View) CursorLeft

func (v *View) CursorLeft() bool

CursorLeft moves the cursor left

func (*View) CursorPageDown

func (v *View) CursorPageDown() bool

CursorPageDown places the cursor a page up

func (*View) CursorPageUp

func (v *View) CursorPageUp() bool

CursorPageUp places the cursor a page up

func (*View) CursorRight

func (v *View) CursorRight() bool

CursorRight moves the cursor right

func (*View) CursorStart

func (v *View) CursorStart() bool

CursorStart moves the cursor to the start of the buffer

func (*View) CursorUp

func (v *View) CursorUp() bool

CursorUp moves the cursor up

func (*View) Cut

func (v *View) Cut() bool

Cut the selection to the system clipboard

func (*View) CutLine

func (v *View) CutLine() bool

CutLine cuts the current line to the clipboard

func (*View) Delete

func (v *View) Delete() bool

Delete deletes the next character

func (*View) DeleteLine

func (v *View) DeleteLine() bool

DeleteLine deletes the current line

func (*View) DeleteWordLeft

func (v *View) DeleteWordLeft() bool

DeleteWordLeft deletes the word to the left of the cursor

func (*View) DeleteWordRight

func (v *View) DeleteWordRight() bool

DeleteWordRight deletes the word to the right of the cursor

func (*View) Draw

func (v *View) Draw(screen Screen)

Draw renders the view and the cursor onto the screen.

If SetRect was never called, the view expands to fill the whole screen.

func (*View) DuplicateLine

func (v *View) DuplicateLine() bool

DuplicateLine duplicates the current line or selection

func (*View) End

func (v *View) End() bool

End moves the viewport to the end of the buffer

func (*View) EndOfLine

func (v *View) EndOfLine() bool

EndOfLine moves the cursor to the end of the line

func (*View) Escape

func (v *View) Escape() bool

Escape leaves current mode

func (*View) ExecuteActions

func (v *View) ExecuteActions(actions []func(*View) bool) bool

Execute actions executes the supplied actions

func (*View) Focus

func (v *View) Focus()

Focus gives the view focus, which makes it place the terminal cursor.

func (*View) GetInputCapture

func (v *View) GetInputCapture() func(event *tcell.EventKey) *tcell.EventKey

GetInputCapture returns the function installed with SetInputCapture, or nil.

func (*View) GetKeybindings

func (v *View) GetKeybindings() KeyBindings

GetKeyBindings gets the keybindings for this view.

func (*View) HalfPageDown

func (v *View) HalfPageDown() bool

HalfPageDown scrolls the view down half a page

func (*View) HalfPageUp

func (v *View) HalfPageUp() bool

HalfPageUp scrolls the view up half a page

func (*View) HandleEvent

func (v *View) HandleEvent(event tcell.Event) bool

HandleEvent handles an event passed by the main loop. It reports whether the editor consumed the event.

Key events go through the input capture (see SetInputCapture), then the autocomplete popup and finally the key bindings. Mouse events are classified into actions and offered to HandleMouseAction. Any other event is ignored.

func (*View) HandleMouse

func (v *View) HandleMouse(event *tcell.EventMouse) bool

HandleMouse derives the logical mouse actions (move, button and wheel events) from a raw tcell mouse event and applies them to the view. It reports whether the view consumed the event.

func (*View) HandleMouseAction

func (v *View) HandleMouseAction(action MouseAction, event *tcell.EventMouse) bool

HandleMouseAction handles one already-classified mouse action. It reports whether the view consumed the action.

Actions whose position falls outside the view's rectangle are ignored.

func (*View) HasFocus

func (v *View) HasFocus() bool

HasFocus returns whether the view currently has focus.

func (*View) IndentSelection

func (v *View) IndentSelection() bool

IndentSelection indents the current selection

func (*View) InsertNewline

func (v *View) InsertNewline() bool

InsertNewline inserts a newline plus possible some whitespace if autoindent is on

func (*View) InsertSpace

func (v *View) InsertSpace() bool

InsertSpace inserts a space

func (*View) InsertTab

func (v *View) InsertTab() bool

InsertTab inserts a tab or spaces

func (*View) IsOverwriteMode

func (v *View) IsOverwriteMode() bool

True if the view is in overwrite mode, false if in insert mode.

func (*View) JumpToMatchingBrace

func (v *View) JumpToMatchingBrace() bool

JumpToMatchingBrace moves the cursor to the matching brace if it is currently on a brace

func (*View) MouseLeftDown

func (v *View) MouseLeftDown(e *tcell.EventMouse)

MouseLeftDown handles a press of the primary button: it moves the cursor to the position the event points at, and turns a second or third press in quick succession into a word or line selection. It also arms dragging, which MouseMove then extends.

Most hosts do not call this directly; HandleMouse derives the action and calls it.

func (*View) MouseLeftUp

func (v *View) MouseLeftUp(e *tcell.EventMouse)

MouseLeftUp handles the release of the primary button, ending a drag and remembering the time so that the next press can be recognized as a double click.

func (*View) MouseMove

func (v *View) MouseMove(e *tcell.EventMouse)

MouseMove handles a pointer movement: while the primary button is held down it extends the selection the press started, and it does nothing otherwise.

func (*View) MoveLinesDown

func (v *View) MoveLinesDown() bool

MoveLinesDown moves down the current line or selected lines if any

func (*View) MoveLinesUp

func (v *View) MoveLinesUp() bool

MoveLinesUp moves up the current line or selected lines if any

func (*View) OpenBuffer

func (v *View) OpenBuffer(buf *Buffer)

OpenBuffer opens a new buffer in this view. This resets the topline, event handler and cursor.

func (*View) OutdentLine

func (v *View) OutdentLine() bool

OutdentLine moves the current line back one indentation

func (*View) OutdentSelection

func (v *View) OutdentSelection() bool

OutdentSelection takes the current selection and moves it back one indent level

func (*View) PageDown

func (v *View) PageDown() bool

PageDown scrolls the view down a page

func (*View) PageUp

func (v *View) PageUp() bool

PageUp scrolls the view up a page

func (*View) ParagraphNext

func (v *View) ParagraphNext() bool

ParagraphNext moves the cursor to the next empty line, or end of the buffer if there's none

func (*View) ParagraphPrevious

func (v *View) ParagraphPrevious() bool

ParagraphPrevious moves the cursor to the previous empty line, or beginning of the buffer if there's none

func (*View) Paste

func (v *View) Paste() bool

Paste whatever is in the system clipboard into the buffer Delete and paste if the user has a selection

func (*View) Rect

func (v *View) Rect() (x, y, width, height int)

Rect returns the area the view occupies on the screen.

func (*View) Redo

func (v *View) Redo() bool

Redo redoes the last action

func (*View) Relocate

func (v *View) Relocate() bool

Relocate moves the view window so that the cursor is in view This is useful if the user has scrolled far away, and then starts typing

func (*View) RemoveAllMultiCursors

func (v *View) RemoveAllMultiCursors() bool

RemoveAllMultiCursors removes all cursors except the base cursor

func (*View) RemoveMultiCursor

func (v *View) RemoveMultiCursor() bool

RemoveMultiCursor removes the latest multiple cursor

func (*View) ReplaceAll

func (v *View) ReplaceAll(str string, useRegex bool, caseSensitive bool, replaceText string) (int, error)

Replace all occurrences of str with replaceText in the entire buffer

Returns the number of replacements made and an error if the regex is invalid

func (*View) Retab

func (v *View) Retab() bool

Retab changes all tabs to spaces or all spaces to tabs depending on the user's settings. Changes go through the EventHandler so they are undoable and cursor positions are updated correctly.

func (*View) ScrollDown

func (v *View) ScrollDown(n int)

ScrollDown scrolls the view down n lines (if possible)

func (*View) ScrollDownAction

func (v *View) ScrollDownAction() bool

ScrollDownAction scrolls the view up

func (*View) ScrollUp

func (v *View) ScrollUp(n int)

ScrollUp scrolls the view up n lines (if possible)

func (*View) ScrollUpAction

func (v *View) ScrollUpAction() bool

ScrollUpAction scrolls the view up

func (*View) Search

func (v *View) Search(str string, useRegex bool, caseSensitive bool, searchDown bool) (bool, error)

Search for a string/regex and select it

Returns true,nil if the string was found, false,nil if not found, and false,error on error.

func (*View) SelectAll

func (v *View) SelectAll() bool

SelectAll selects the entire buffer

func (*View) SelectDown

func (v *View) SelectDown() bool

SelectDown selects down one line

func (*View) SelectLeft

func (v *View) SelectLeft() bool

SelectLeft selects the character to the left of the cursor

func (*View) SelectLine

func (v *View) SelectLine() bool

SelectLine selects the entire current line

func (*View) SelectPageDown

func (v *View) SelectPageDown() bool

SelectPageDown selects down one page

func (*View) SelectPageUp

func (v *View) SelectPageUp() bool

SelectPageUp selects up one page

func (*View) SelectRight

func (v *View) SelectRight() bool

SelectRight selects the character to the right of the cursor

func (*View) SelectToEnd

func (v *View) SelectToEnd() bool

SelectToEnd selects the text from the cursor to the end of the buffer

func (*View) SelectToEndOfLine

func (v *View) SelectToEndOfLine() bool

SelectToEndOfLine selects to the end of the current line

func (*View) SelectToStart

func (v *View) SelectToStart() bool

SelectToStart selects the text from the cursor to the start of the buffer

func (*View) SelectToStartOfLine

func (v *View) SelectToStartOfLine() bool

SelectToStartOfLine selects to the start of the current line

func (*View) SelectUp

func (v *View) SelectUp() bool

SelectUp selects up one line

func (*View) SelectWordLeft

func (v *View) SelectWordLeft() bool

SelectWordLeft selects the word to the left of the cursor

func (*View) SelectWordRight

func (v *View) SelectWordRight() bool

SelectWordRight selects the word to the right of the cursor

func (*View) SetAutocompleteProvider

func (v *View) SetAutocompleteProvider(provider AutocompleteProvider)

SetAutocompleteProvider configures how this view produces completion items. Passing nil disables autocomplete.

func (*View) SetColorscheme

func (v *View) SetColorscheme(colorscheme Colorscheme)

SetColorscheme sets the colorscheme for this view.

func (*View) SetCursor

func (v *View) SetCursor(c *Cursor) bool

SetCursor sets the view's and buffer's cursor

func (*View) SetFocus

func (v *View) SetFocus(focus bool)

SetFocus sets the focus state of the view.

func (*View) SetInputCapture

func (v *View) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *View

SetInputCapture installs a function which receives key events before the view handles them. The function can forward the event (or a different one) by returning it; returning nil swallows the event.

Providing a nil function removes a previously installed capture.

func (*View) SetKeybindings

func (v *View) SetKeybindings(bindings KeyBindings)

SetKeybindings sets the keybindings for this view.

func (*View) SetRect

func (v *View) SetRect(x, y, width, height int)

SetRect sets the area the view occupies on the screen.

func (*View) SetRuntimeFiles

func (v *View) SetRuntimeFiles(runtimeFiles *RuntimeFiles)

SetRuntimeFiles sets the runtime files for this view.

func (*View) SkipMultiCursor

func (v *View) SkipMultiCursor() bool

SkipMultiCursor moves the current multiple cursor to the next available position

func (*View) SpawnMultiCursor

func (v *View) SpawnMultiCursor() bool

SpawnMultiCursor creates a new multiple cursor at the next occurrence of the current selection or current word

func (*View) SpawnMultiCursorSelect

func (v *View) SpawnMultiCursorSelect() bool

SpawnMultiCursorSelect adds a cursor at the beginning of each line of a selection

func (*View) Start

func (v *View) Start() bool

Start moves the viewport to the start of the buffer

func (*View) StartOfLine

func (v *View) StartOfLine() bool

StartOfLine moves the cursor to the start of the line

func (*View) ToggleOverwriteMode

func (v *View) ToggleOverwriteMode() bool

ToggleOverwriteMode lets the user toggle the text overwrite mode

func (*View) ToggleRuler

func (v *View) ToggleRuler() bool

ToggleRuler turns line numbers off and on

func (*View) TriggerAutocomplete

func (v *View) TriggerAutocomplete() bool

TriggerAutocomplete opens or refreshes the autocomplete popup at the current cursor.

func (*View) Undo

func (v *View) Undo() bool

Undo undoes the last action

func (*View) WordLeft

func (v *View) WordLeft() bool

WordLeft moves the cursor one word to the left

func (*View) WordRight

func (v *View) WordRight() bool

WordRight moves the cursor one word to the right

Directories

Path Synopsis
Package main is a showcase of github.com/malivvan/editor hosted by tcell directly: no widget toolkit, no application framework, no layout engine.
Package main is a showcase of github.com/malivvan/editor hosted by tcell directly: no widget toolkit, no application framework, no layout engine.
Package highlight is the syntax highlighter behind the editor.
Package highlight is the syntax highlighter behind the editor.
Package runtime embeds the syntax definitions and colorschemes the editor ships with, and hands them to a view as a ready-made set of runtime files:
Package runtime embeds the syntax definitions and colorschemes the editor ships with, and hands them to a view as a ready-made set of runtime files:
files/syntax command
Package util holds the small helpers the editor shares between its files: clamping, converting between byte indices and rune indices, and — in unicode.go — everything that has to do with characters built from more than one code point.
Package util holds the small helpers the editor shares between its files: clamping, converting between byte indices and rune indices, and — in unicode.go — everything that has to do with characters built from more than one code point.

Jump to

Keyboard shortcuts

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