akiyosi.goneovim/editor.go

328 lines
7.1 KiB
Go
Raw Normal View History

2017-03-14 01:52:44 +00:00
package gonvim
import (
"fmt"
"os"
2017-03-14 07:20:31 +00:00
"strconv"
"strings"
2017-03-14 01:52:44 +00:00
"sync"
"unsafe"
2017-03-16 10:38:16 +00:00
"github.com/dzhou121/neovim-fzf-shim/rplugin/go/fzf"
2017-03-14 01:52:44 +00:00
"github.com/dzhou121/ui"
"github.com/neovim/go-client/nvim"
)
var editor *Editor
// Highlight is
type Highlight struct {
foreground *RGBA
background *RGBA
}
// Char is
type Char struct {
char string
highlight Highlight
}
// Editor is the editor
type Editor struct {
2017-04-27 11:32:04 +01:00
nvim *nvim.Nvim
nvimAttached bool
mode string
font *Font
rows int
cols int
cursor *CursorHandler
Foreground RGBA
Background RGBA
window *ui.Window
area *ui.Area
areaHandler *AreaHandler
2017-04-28 07:05:32 +01:00
areaBox *ui.Box
2017-04-27 11:32:04 +01:00
close chan bool
popup *PopupMenu
finder *Finder
tabline *Tabline
width int
height int
tablineHeight int
selectedBg *RGBA
matchFg *RGBA
2017-03-14 01:52:44 +00:00
}
func initWindow(box *ui.Box, width, height int) *ui.Window {
window := ui.NewWindow("Gonvim", width, height, false)
window.SetChild(box)
window.OnClosing(func(*ui.Window) bool {
ui.Quit()
return true
})
window.OnContentSizeChanged(func(w *ui.Window, data unsafe.Pointer) bool {
2017-03-22 21:12:12 +00:00
if editor == nil {
2017-03-22 21:13:22 +00:00
return true
2017-03-22 21:12:12 +00:00
}
2017-03-14 01:52:44 +00:00
width, height = window.ContentSize()
2017-04-27 11:32:04 +01:00
height = height - editor.tablineHeight
2017-03-22 22:13:36 +00:00
if width == editor.width && height == editor.height {
2017-03-22 22:14:43 +00:00
return true
2017-03-22 22:13:36 +00:00
}
2017-03-14 07:20:31 +00:00
editor.width = width
editor.height = height
2017-04-28 07:05:32 +01:00
editor.areaBox.SetSize(width, height)
2017-03-14 01:52:44 +00:00
editor.area.SetSize(width, height)
2017-04-27 11:32:04 +01:00
editor.tabline.resize(width, editor.tablineHeight)
2017-03-14 07:20:31 +00:00
editor.resize()
2017-03-16 10:38:16 +00:00
editor.finder.rePosition()
2017-03-14 01:52:44 +00:00
return true
})
window.Show()
return window
}
// InitEditor inits the editor
func InitEditor() error {
if editor != nil {
return nil
}
width := 800
height := 600
2017-04-27 11:32:04 +01:00
tablineHeight := 34
2017-03-14 01:52:44 +00:00
ah := initArea()
2017-03-21 18:17:06 +00:00
cursor := &CursorHandler{}
cursorArea := ui.NewArea(cursor)
cursor.area = cursorArea
2017-03-14 01:52:44 +00:00
popupMenu := initPopupmenu()
2017-03-16 10:38:16 +00:00
finder := initFinder()
2017-04-27 11:32:04 +01:00
tabline := initTabline(width, tablineHeight)
2017-03-14 01:52:44 +00:00
box := ui.NewHorizontalBox()
2017-04-28 02:50:38 +01:00
areaBox := ui.NewHorizontalBox()
areaBox.Append(ah.area, false)
areaBox.Append(cursor.area, false)
areaBox.Append(popupMenu.box, false)
areaBox.Append(finder.box, false)
2017-04-27 11:32:04 +01:00
box.Append(tabline.box, false)
2017-04-28 02:50:38 +01:00
box.Append(areaBox, false)
2017-03-14 01:52:44 +00:00
2017-04-28 02:50:38 +01:00
areaBox.SetSize(width, height)
areaBox.SetPosition(0, tablineHeight)
2017-03-14 01:52:44 +00:00
ah.area.SetSize(width, height)
2017-04-27 11:32:04 +01:00
window := initWindow(box, width, height+tablineHeight)
2017-03-14 01:52:44 +00:00
neovim, err := nvim.NewEmbedded(&nvim.EmbedOptions{
Args: os.Args[1:],
})
if err != nil {
return err
}
2017-03-14 07:20:31 +00:00
font := initFont("", 14, 0)
2017-03-14 01:52:44 +00:00
editor = &Editor{
2017-04-27 11:32:04 +01:00
nvim: neovim,
nvimAttached: false,
window: window,
area: ah.area,
areaHandler: ah,
2017-04-28 07:05:32 +01:00
areaBox: areaBox,
2017-04-27 11:32:04 +01:00
mode: "normal",
close: make(chan bool),
cursor: cursor,
popup: popupMenu,
finder: finder,
tabline: tabline,
width: width,
height: height,
tablineHeight: tablineHeight,
font: font,
cols: 0,
rows: 0,
selectedBg: newRGBA(81, 154, 186, 0.5),
matchFg: newRGBA(81, 154, 186, 1),
2017-03-14 01:52:44 +00:00
}
2017-03-14 07:20:31 +00:00
editor.resize()
editor.handleNotification()
2017-03-16 10:38:16 +00:00
editor.finder.rePosition()
2017-03-14 01:52:44 +00:00
go func() {
neovim.Serve()
editor.close <- true
}()
o := make(map[string]interface{})
o["rgb"] = true
2017-04-27 11:32:04 +01:00
o["ext_popupmenu"] = true
o["ext_tabline"] = true
2017-03-14 07:20:31 +00:00
editor.nvim.AttachUI(editor.cols, editor.rows, o)
2017-03-14 07:26:11 +00:00
editor.nvim.Subscribe("Gui")
2017-03-14 07:20:31 +00:00
editor.nvim.Command("runtime plugin/nvim_gui_shim.vim")
editor.nvim.Command("runtime! ginit.vim")
2017-03-16 10:38:16 +00:00
fzf.RegisterPlugin(editor.nvim)
2017-03-14 01:52:44 +00:00
go func() {
<-editor.close
ui.Quit()
}()
return nil
}
2017-03-14 07:20:31 +00:00
func (e *Editor) handleNotification() {
2017-03-14 01:52:44 +00:00
ah := e.areaHandler
2017-03-14 07:20:31 +00:00
e.nvim.RegisterHandler("Gui", func(updates ...interface{}) {
event := updates[0].(string)
switch event {
case "Font":
e.guiFont(updates[1:])
case "Linespace":
e.guiLinespace(updates[1:])
2017-03-16 10:38:16 +00:00
case "finder_pattern":
e.finder.showPattern(updates[1:])
case "finder_pattern_pos":
e.finder.cursorPos(updates[1:])
case "finder_show_result":
e.finder.showResult(updates[1:])
case "finder_show":
e.finder.show()
case "finder_hide":
e.finder.hide()
case "finder_select":
e.finder.selectResult(updates[1:])
2017-03-14 07:20:31 +00:00
default:
fmt.Println("unhandled Gui event", event)
}
})
mutex := &sync.Mutex{}
2017-03-14 01:52:44 +00:00
e.nvim.RegisterHandler("redraw", func(updates ...[]interface{}) {
2017-03-14 07:20:31 +00:00
mutex.Lock()
2017-03-14 01:52:44 +00:00
for _, update := range updates {
event := update[0].(string)
args := update[1:]
switch event {
case "update_fg":
args := update[1].([]interface{})
editor.Foreground = calcColor(reflectToInt(args[0]))
case "update_bg":
args := update[1].([]interface{})
bg := calcColor(reflectToInt(args[0]))
editor.Background = bg
case "cursor_goto":
ah.cursorGoto(args)
case "put":
ah.put(args)
case "eol_clear":
ah.eolClear(args)
case "clear":
ah.clear(args)
case "resize":
ah.resize(args)
case "highlight_set":
ah.highlightSet(args)
case "set_scroll_region":
ah.setScrollRegion(args)
case "scroll":
ah.scroll(args)
case "mode_change":
ah.modeChange(args)
case "popupmenu_show":
editor.popup.show(args)
case "popupmenu_hide":
editor.popup.hide(args)
case "popupmenu_select":
editor.popup.selectItem(args)
2017-04-27 11:32:04 +01:00
case "tabline_update":
editor.tabline.update(args)
2017-03-14 01:52:44 +00:00
default:
fmt.Println("Unhandle event", event)
}
}
2017-03-14 07:20:31 +00:00
mutex.Unlock()
2017-03-14 01:52:44 +00:00
if !e.nvimAttached {
e.nvimAttached = true
}
drawCursor()
})
}
2017-03-14 07:20:31 +00:00
func (e *Editor) guiFont(args ...interface{}) {
fontArg := args[0].([]interface{})
parts := strings.Split(fontArg[0].(string), ":")
if len(parts) < 1 {
return
}
height := 14
for _, p := range parts[1:] {
if strings.HasPrefix(p, "h") {
var err error
height, err = strconv.Atoi(p[1:])
if err != nil {
return
}
}
}
e.font.change(parts[0], height)
e.resize()
}
func (e *Editor) guiLinespace(args ...interface{}) {
fontArg := args[0].([]interface{})
lineSpace, err := strconv.Atoi(fontArg[0].(string))
if err != nil {
return
}
e.font.changeLineSpace(lineSpace)
e.resize()
}
func (e *Editor) resize() {
width := e.width
height := e.height
cols := width / editor.font.width
rows := height / editor.font.lineHeight
oldCols := editor.cols
oldRows := editor.rows
2017-03-14 07:26:11 +00:00
editor.cols = cols
editor.rows = rows
if oldCols > 0 && oldRows > 0 {
editor.nvim.TryResizeUI(cols, rows)
2017-03-14 07:20:31 +00:00
}
}
2017-03-14 01:52:44 +00:00
func drawCursor() {
row := editor.areaHandler.cursor[0]
col := editor.areaHandler.cursor[1]
ui.QueueMain(func() {
2017-04-28 02:50:38 +01:00
editor.cursor.area.SetPosition(col*editor.font.width, row*editor.font.lineHeight)
2017-03-14 01:52:44 +00:00
})
mode := editor.mode
if mode == "normal" {
ui.QueueMain(func() {
2017-03-21 18:17:06 +00:00
editor.cursor.area.SetSize(editor.font.width, editor.font.lineHeight)
editor.cursor.bg = newRGBA(255, 255, 255, 0.5)
2017-03-14 01:52:44 +00:00
})
} else if mode == "insert" {
ui.QueueMain(func() {
2017-03-21 18:17:06 +00:00
editor.cursor.area.SetSize(1, editor.font.lineHeight)
editor.cursor.bg = newRGBA(255, 255, 255, 0.9)
2017-03-14 01:52:44 +00:00
})
}
}
func (hl *Highlight) copy() Highlight {
highlight := Highlight{}
if hl.foreground != nil {
highlight.foreground = hl.foreground.copy()
}
if hl.background != nil {
highlight.background = hl.background.copy()
}
return highlight
}