femto

package
v0.0.0-...-17efaa7 Latest Latest
Warning

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

Go to latest
Published: Dec 16, 2021 License: BSD-3-Clause, MIT Imports: 17 Imported by: 0

README

femto, an editor component for tview

femto is a text editor component for tview. The vast majority of the code is derived from the micro editor.

Note The shape of the femto API is a work-in-progress, and should not be considered stable.

Default keybindings

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
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

Example Usage

The code below (also found in cmd/femto/femto.go) creates a tview application with a single full-screen editor that operates on one file at a time. Ctrl-s saves any edits; Ctrl-q quits.

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"github.com/gdamore/tcell"
	"femto"
	"femto/runtime"
	"github.com/Bios-Marcel/cordless/tview"
)

func saveBuffer(b *femto.Buffer, path string) error {
	return ioutil.WriteFile(path, []byte(b.String()), 0600)
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, "usage: femto [filename]\n")
		os.Exit(1)
	}
	path := os.Args[1]

	content, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatalf("could not read %v: %v", path, err)
	}

	var colorscheme femto.Colorscheme
	if monokai := runtime.Files.FindFile(femto.RTColorscheme, "monokai"); monokai != nil {
		if data, err := monokai.Data(); err == nil {
			colorscheme = femto.ParseColorscheme(string(data))
		}
	}

	app := tview.NewApplication()
	buffer := femto.NewBufferFromString(string(content), path)
	root := femto.NewView(buffer)
	root.SetRuntimeFiles(runtime.Files)
	root.SetColorscheme(colorscheme)
	root.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
		switch event.Key() {
		case tcell.KeyCtrlS:
			saveBuffer(buffer, path)
			return nil
		case tcell.KeyCtrlQ:
			app.Stop()
			return nil
		}
		return event
	})
	app.SetRoot(root, true)

	if err := app.Run(); err != nil {
		log.Fatalf("%v", err)
	}
}

Documentation

Index

Constants

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 LargeFileThreshold = 50000

Variables

This section is empty.

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 or not 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(color 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 or not 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) 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 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 or not 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) 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) 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) MergeCursors

func (b *Buffer) MergeCursors()

MergeCursors merges any cursors that are at the same position into one cursor

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) 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

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 or not 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) 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  string
	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, text 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 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 int64, reader io.Reader) *LineArray

NewLineArray returns a new line array from an array of bytes

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) 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) Split

func (la *LineArray) Split(pos Loc)

Split splits a line at a given position

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) string

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) 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 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

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

Jump to

Keyboard shortcuts

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