akiyosi.goneovim/editor.go

503 lines
12 KiB
Go
Raw Normal View History

2017-03-14 01:52:44 +00:00
package gonvim
import (
"fmt"
"os"
2017-05-12 04:07:54 +01:00
"runtime"
2017-03-14 07:20:31 +00:00
"strconv"
"strings"
2017-06-02 10:41:28 +01:00
"sync"
2017-03-14 01:52:44 +00:00
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/neovim/go-client/nvim"
2017-06-06 02:42:11 +01:00
"github.com/therecipe/qt/widgets"
2017-03-14 01:52:44 +00:00
)
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-06-08 02:35:58 +01:00
nvim *nvim.Nvim
nvimAttached bool
mode string
font *Font
smallerFont *Font
rows int
cols int
cursorNew *Cursor
Foreground *RGBA
Background *RGBA
special *RGBA
// window *ui.Window
screen *Screen
// areaBox *ui.Box
2017-05-10 07:28:44 +01:00
close chan bool
2017-06-12 09:15:08 +01:00
loc *Locpopup
2017-05-10 07:28:44 +01:00
popup *PopupMenu
finder *Finder
tabline *Tabline
statusline *Statusline
statuslineHeight int
width int
height int
tablineHeight int
selectedBg *RGBA
matchFg *RGBA
2017-06-02 10:41:28 +01:00
resizeMutex sync.Mutex
2017-03-14 01:52:44 +00:00
}
// InitEditor inits the editor
2017-06-08 02:35:58 +01:00
// func InitEditor() error {
// if editor != nil {
// return nil
// }
2017-06-02 10:41:28 +01:00
2017-06-08 02:35:58 +01:00
// fontFamily := ""
// switch runtime.GOOS {
// case "windows":
// fontFamily = "Consolas"
// case "darwin":
// fontFamily = "Courier New"
// default:
// fontFamily = "Monospace"
// }
// font := initFont(fontFamily, 14, 6)
2017-06-02 10:41:28 +01:00
2017-06-08 02:35:58 +01:00
// width := 800
// height := 600
// tablineHeight := 34
// statuslineHeight := 20
// screenHeight := height - tablineHeight - statuslineHeight
2017-03-21 18:17:06 +00:00
2017-06-08 02:35:58 +01:00
// screen := initScreen(width, screenHeight)
// cursor := initCursorBox(width, screenHeight)
// popupMenu := initPopupmenu()
// finder := initFinder()
// tabline := initTabline(width, tablineHeight)
// loc := initLocpopup()
// statusline := initStatusline(width, statuslineHeight)
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// box := ui.NewHorizontalBox()
// areaBox := ui.NewHorizontalBox()
// areaBox.Append(screen.box, false)
// areaBox.Append(cursor.box, false)
// areaBox.Append(loc.box, false)
// areaBox.Append(popupMenu.box, false)
// areaBox.Append(finder.box, false)
// box.Append(tabline.box, false)
// box.Append(areaBox, false)
// box.Append(statusline.box, false)
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// areaBox.SetSize(width, screenHeight)
// areaBox.SetPosition(0, tablineHeight)
// statusline.box.SetPosition(0, tablineHeight+screenHeight)
// window := initMainWindow(box, width, height)
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// neovim, err := nvim.NewEmbedded(&nvim.EmbedOptions{
// Args: os.Args[1:],
// })
// if err != nil {
// fmt.Println("nvim start error", err)
// ui.Quit()
// return err
// }
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// editor = &Editor{
// nvim: neovim,
// nvimAttached: false,
// window: window,
// screen: screen,
// areaBox: areaBox,
// mode: "normal",
// close: make(chan bool),
// cursor: cursor,
// popup: popupMenu,
// finder: finder,
// tabline: tabline,
// width: width,
// height: height,
// tablineHeight: tablineHeight,
// statusline: statusline,
// statuslineHeight: statuslineHeight,
// font: font,
// selectedBg: newRGBA(81, 154, 186, 0.5),
// matchFg: newRGBA(81, 154, 186, 1),
// }
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// editor.nvimResize()
// editor.handleNotification()
// editor.finder.rePosition()
// go func() {
// err := neovim.Serve()
// if err != nil {
// fmt.Println(err)
// }
// editor.close <- true
// }()
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// o := make(map[string]interface{})
// o["rgb"] = true
// o["ext_popupmenu"] = true
// o["ext_tabline"] = true
// err = editor.nvim.AttachUI(editor.cols, editor.rows, o)
// if err != nil {
// fmt.Println("nvim attach UI error", err)
// ui.Quit()
// return nil
// }
// editor.nvim.Subscribe("Gui")
// editor.nvim.Command("runtime plugin/nvim_gui_shim.vim")
// editor.nvim.Command("runtime! ginit.vim")
// editor.nvim.Command("let g:gonvim_running=1")
// fzf.RegisterPlugin(editor.nvim)
// locpopup.RegisterPlugin(editor.nvim)
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// go func() {
// <-editor.close
// ui.Quit()
// }()
2017-03-14 01:52:44 +00:00
2017-06-08 02:35:58 +01:00
// return nil
// }
2017-03-14 01:52:44 +00:00
2017-03-14 07:20:31 +00:00
func (e *Editor) handleNotification() {
e.nvim.RegisterHandler("Gui", func(updates ...interface{}) {
2017-05-11 06:18:54 +01:00
go e.handleRPCGui(updates...)
2017-03-14 07:20:31 +00:00
})
2017-03-14 01:52:44 +00:00
e.nvim.RegisterHandler("redraw", func(updates ...[]interface{}) {
2017-06-07 09:18:21 +01:00
e.screen.paintMutex.Lock()
2017-05-11 08:48:09 +01:00
e.handleRedraw(updates...)
2017-06-07 09:18:21 +01:00
e.screen.paintMutex.Unlock()
2017-05-11 06:18:54 +01:00
})
}
func (e *Editor) handleRPCGui(updates ...interface{}) {
event := updates[0].(string)
switch event {
case "Font":
e.guiFont(updates[1:])
case "Linespace":
e.guiLinespace(updates[1:])
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:])
case "locpopup_show":
2017-06-07 15:52:17 +01:00
// arg, ok := updates[1].(map[string]interface{})
// if !ok {
// return
// }
// e.cursor.locpopup.show(arg)
2017-05-11 06:18:54 +01:00
case "locpopup_hide":
2017-06-07 15:52:17 +01:00
// e.cursor.locpopup.hide()
2017-05-11 06:18:54 +01:00
case "signature_show":
2017-06-07 15:52:17 +01:00
// e.cursor.signature.show(updates[1:])
2017-05-11 06:18:54 +01:00
case "signature_pos":
2017-06-07 15:52:17 +01:00
// e.cursor.signature.pos(updates[1:])
2017-05-11 06:18:54 +01:00
case "signature_hide":
2017-06-07 15:52:17 +01:00
// e.cursor.signature.hide()
2017-05-11 06:18:54 +01:00
default:
fmt.Println("unhandled Gui event", event)
}
}
func (e *Editor) handleRedraw(updates ...[]interface{}) {
screen := e.screen
2017-05-16 07:16:53 +01:00
go screen.redrawWindows()
2017-05-11 06:18:54 +01:00
for _, update := range updates {
event := update[0].(string)
args := update[1:]
switch event {
case "update_fg":
args := update[1].([]interface{})
2017-05-25 06:17:31 +01:00
color := reflectToInt(args[0])
if color == -1 {
2017-06-02 10:53:27 +01:00
editor.Foreground = newRGBA(255, 255, 255, 1)
2017-05-25 06:17:31 +01:00
} else {
editor.Foreground = calcColor(reflectToInt(args[0]))
}
2017-05-11 06:18:54 +01:00
case "update_bg":
args := update[1].([]interface{})
2017-06-06 02:42:11 +01:00
screen.updateBg(args)
case "update_sp":
args := update[1].([]interface{})
color := reflectToInt(args[0])
if color == -1 {
editor.special = newRGBA(255, 255, 255, 1)
} else {
editor.special = calcColor(reflectToInt(args[0]))
}
2017-05-11 06:18:54 +01:00
case "cursor_goto":
screen.cursorGoto(args)
case "put":
screen.put(args)
case "eol_clear":
screen.eolClear(args)
case "clear":
screen.clear(args)
case "resize":
screen.resize(args)
case "highlight_set":
screen.highlightSet(args)
case "set_scroll_region":
screen.setScrollRegion(args)
case "scroll":
screen.scroll(args)
case "mode_change":
2017-05-16 07:16:53 +01:00
arg := update[len(update)-1].([]interface{})
2017-05-11 06:18:54 +01:00
editor.mode = arg[0].(string)
case "popupmenu_show":
editor.popup.show(args)
case "popupmenu_hide":
editor.popup.hide(args)
case "popupmenu_select":
editor.popup.selectItem(args)
case "tabline_update":
editor.tabline.update(args)
case "busy_start":
case "busy_stop":
2017-05-11 06:18:54 +01:00
default:
fmt.Println("Unhandle event", event)
2017-03-14 01:52:44 +00:00
}
2017-05-11 06:18:54 +01:00
}
screen.redraw()
2017-06-08 02:35:58 +01:00
// editor.cursor.draw()
2017-06-07 09:18:21 +01:00
editor.cursorNew.update()
2017-05-11 06:18:54 +01:00
if !e.nvimAttached {
e.nvimAttached = true
}
2017-06-12 09:15:08 +01:00
editor.statusline.mode.redraw()
2017-03-14 01:52:44 +00:00
}
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)
2017-06-07 11:31:10 +01:00
e.popup.updateFont(e.font)
2017-06-02 10:41:28 +01:00
e.resize(e.width, e.height)
2017-03-14 07:20:31 +00:00
}
func (e *Editor) guiLinespace(args ...interface{}) {
fontArg := args[0].([]interface{})
var lineSpace int
var err error
switch arg := fontArg[0].(type) {
case string:
lineSpace, err = strconv.Atoi(arg)
if err != nil {
return
}
case int32: // can't combine these in a type switch without compile error
lineSpace = int(arg)
case int64:
lineSpace = int(arg)
default:
2017-03-14 07:20:31 +00:00
return
}
e.font.changeLineSpace(lineSpace)
2017-06-02 10:41:28 +01:00
e.resize(e.width, e.height)
}
func (e *Editor) resize(width, height int) {
2017-06-08 02:35:58 +01:00
// ui.QueueMain(func() {
// e.resizeMutex.Lock()
// defer e.resizeMutex.Unlock()
// // e.tablineHeight = getTablineHeight(e.font)
// // e.statuslineHeight = getStatuslineHeight(e.font)
// // screenHeight := height - e.tablineHeight - e.statuslineHeight
// // e.width = width
// // e.height = height
// // e.areaBox.SetSize(width, screenHeight)
// // e.areaBox.SetPosition(0, e.tablineHeight)
// // e.screen.box.SetSize(width, screenHeight)
// // e.screen.setSize(width, screenHeight)
// // e.cursor.setSize(width, screenHeight)
// // e.tabline.resize(width, e.tablineHeight)
// // e.statusline.redraw(true)
// // e.statusline.box.SetSize(width, e.statuslineHeight)
// // e.statusline.setSize(width, e.statuslineHeight)
// // e.statusline.box.SetPosition(0, e.tablineHeight+screenHeight)
// // e.finder.rePosition()
// e.nvimResize()
// })
2017-03-14 07:20:31 +00:00
}
2017-06-02 10:41:28 +01:00
func (e *Editor) nvimResize() {
2017-06-07 09:18:21 +01:00
e.screen.paintMutex.Lock()
defer e.screen.paintMutex.Unlock()
2017-06-06 02:42:11 +01:00
width, height := e.screen.size()
2017-05-12 04:55:21 +01:00
// cols := width / editor.font.width
cols := int(float64(width) / editor.font.truewidth)
2017-03-14 07:20:31 +00:00
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 {
2017-05-31 08:57:12 +01:00
if cols != oldCols || rows != oldRows {
editor.nvim.TryResizeUI(cols, rows)
}
2017-03-14 07:20:31 +00:00
}
}
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
}
2017-06-06 02:42:11 +01:00
// InitEditorNew is
func InitEditorNew() {
2017-06-07 09:18:21 +01:00
app := widgets.NewQApplication(0, nil)
2017-06-06 02:42:11 +01:00
fontFamily := ""
switch runtime.GOOS {
case "windows":
fontFamily = "Consolas"
case "darwin":
fontFamily = "Courier New"
default:
fontFamily = "Monospace"
}
font := initFontNew(fontFamily, 14, 6)
width := 800
height := 600
//screenHeight := height - tablineHeight - statuslineHeight
//create a window
window := widgets.NewQMainWindow(nil, 0)
2017-06-06 07:21:17 +01:00
window.SetWindowTitle("Gonvim")
2017-06-06 02:42:11 +01:00
window.SetContentsMargins(0, 0, 0, 0)
window.SetMinimumSize2(width, height)
2017-06-09 11:32:32 +01:00
tabline := initTablineNew()
statusline := initStatuslineNew()
2017-06-06 02:42:11 +01:00
screen := initScreenNew()
2017-06-07 09:18:21 +01:00
cursor := initCursorNew()
cursor.widget.SetParent(screen.widget)
2017-06-07 11:31:10 +01:00
popup := initPopupmenuNew(font)
2017-06-07 11:24:42 +01:00
popup.widget.SetParent(screen.widget)
2017-06-08 11:46:09 +01:00
finder := initFinder()
finder.widget.SetParent(screen.widget)
2017-06-12 09:15:08 +01:00
loc := initLocpopup()
loc.widget.SetParent(screen.widget)
2017-06-06 07:21:17 +01:00
window.ConnectKeyPressEvent(screen.keyPress)
2017-06-06 02:42:11 +01:00
layout := widgets.NewQVBoxLayout()
widget := widgets.NewQWidget(nil, 0)
widget.SetContentsMargins(0, 0, 0, 0)
widget.SetLayout(layout)
2017-06-09 11:32:32 +01:00
layout.AddWidget(tabline.widget, 0, 0)
2017-06-06 02:42:11 +01:00
layout.AddWidget(screen.widget, 1, 0)
2017-06-09 11:32:32 +01:00
layout.AddWidget(statusline.widget, 0, 0)
2017-06-06 02:42:11 +01:00
layout.SetContentsMargins(0, 0, 0, 0)
2017-06-07 09:18:21 +01:00
layout.SetSpacing(0)
2017-06-06 02:42:11 +01:00
window.SetCentralWidget(widget)
neovim, err := nvim.NewEmbedded(&nvim.EmbedOptions{
Args: os.Args[1:],
})
if err != nil {
fmt.Println("nvim start error", err)
2017-06-07 09:18:21 +01:00
app.Quit()
2017-06-06 02:42:11 +01:00
return
}
editor = &Editor{
2017-06-09 11:32:32 +01:00
nvim: neovim,
nvimAttached: false,
screen: screen,
cursorNew: cursor,
mode: "normal",
close: make(chan bool),
popup: popup,
finder: finder,
2017-06-12 09:15:08 +01:00
loc: loc,
2017-06-09 11:32:32 +01:00
tabline: tabline,
width: width,
height: height,
statusline: statusline,
font: font,
selectedBg: newRGBA(81, 154, 186, 0.5),
matchFg: newRGBA(81, 154, 186, 1),
2017-06-06 02:42:11 +01:00
}
editor.nvimResize()
editor.handleNotification()
// editor.finder.rePosition()
go func() {
err := neovim.Serve()
if err != nil {
fmt.Println(err)
}
editor.close <- true
}()
o := make(map[string]interface{})
o["rgb"] = true
o["ext_popupmenu"] = true
o["ext_tabline"] = true
err = editor.nvim.AttachUI(editor.cols, editor.rows, o)
if err != nil {
fmt.Println("nvim attach UI error", err)
2017-06-07 09:18:21 +01:00
app.Quit()
2017-06-06 02:42:11 +01:00
return
}
editor.nvim.Subscribe("Gui")
editor.nvim.Command("runtime plugin/nvim_gui_shim.vim")
editor.nvim.Command("runtime! ginit.vim")
editor.nvim.Command("let g:gonvim_running=1")
2017-06-09 09:45:52 +01:00
fzf.RegisterPlugin(editor.nvim)
2017-06-12 09:15:08 +01:00
editor.statusline.subscribe()
editor.loc.subscribe()
2017-06-06 02:42:11 +01:00
go func() {
<-editor.close
2017-06-07 09:18:21 +01:00
app.Quit()
2017-06-06 02:42:11 +01:00
}()
window.Show()
widgets.QApplication_Exec()
}