akiyosi.goneovim/editor/editor.go

897 lines
23 KiB
Go
Raw Normal View History

2017-11-09 02:11:05 +00:00
package editor
2017-03-14 01:52:44 +00:00
import (
"fmt"
"io/ioutil"
2018-01-08 10:23:16 +00:00
"os"
"os/exec"
2018-01-08 10:23:16 +00:00
"path/filepath"
2017-05-12 04:07:54 +01:00
"runtime"
2018-01-08 10:23:16 +00:00
"strconv"
2017-03-14 07:20:31 +00:00
"strings"
2017-06-02 10:41:28 +01:00
"sync"
2017-03-14 01:52:44 +00:00
2019-03-13 11:50:52 +09:00
frameless "github.com/akiyosi/goqtframelesswindow"
2018-06-10 14:25:17 +09:00
clipb "github.com/atotto/clipboard"
2019-11-13 22:49:25 +09:00
"github.com/jessevdk/go-flags"
2019-11-19 00:32:34 +09:00
homedir "github.com/mitchellh/go-homedir"
2017-03-14 01:52:44 +00:00
"github.com/neovim/go-client/nvim"
2017-06-16 08:43:05 +01:00
"github.com/therecipe/qt/core"
2018-01-05 08:07:29 +00:00
"github.com/therecipe/qt/gui"
2017-06-06 02:42:11 +01:00
"github.com/therecipe/qt/widgets"
2017-03-14 01:52:44 +00:00
)
var editor *Editor
2019-10-22 22:50:56 +09:00
const (
2020-05-03 11:10:33 +09:00
GONEOVIMVERSION = "v0.4.6"
2020-01-13 22:05:04 +09:00
WorkspaceLen = 20
2019-10-22 22:50:56 +09:00
)
2018-12-27 21:03:21 +09:00
// ColorPalette is
2018-12-27 12:38:42 +09:00
type ColorPalette struct {
2019-06-12 22:14:48 +09:00
e *Editor
2019-06-12 21:58:35 +09:00
2018-12-31 16:43:04 +09:00
fg *RGBA
bg *RGBA
inactiveFg *RGBA
comment *RGBA
abyss *RGBA
matchFg *RGBA
selectedBg *RGBA
sideBarFg *RGBA
sideBarBg *RGBA
sideBarSelectedItemBg *RGBA
scrollBarFg *RGBA
scrollBarBg *RGBA
widgetFg *RGBA
widgetBg *RGBA
widgetInputArea *RGBA
minimapCurrentRegion *RGBA
2019-05-31 16:41:37 +09:00
windowSeparator *RGBA
2019-06-07 02:00:14 +09:00
indentGuide *RGBA
2018-12-27 12:38:42 +09:00
}
2019-06-30 19:35:25 +09:00
// NotifyButton is
type NotifyButton struct {
action func()
text string
}
2018-12-21 12:18:41 +09:00
// Notify is
2018-08-16 19:31:36 +09:00
type Notify struct {
level NotifyLevel
period int
2018-08-16 19:31:36 +09:00
message string
buttons []*NotifyButton
}
2019-11-13 22:49:25 +09:00
type Option struct {
Fullscreen bool `long:"fullscreen" description:"Open the window in fullscreen on startup"`
Maximized bool `long:"maximized" description:"Maximize the window on startup"`
Geometry string `long:"geometry" description:"Initial window geomtry [e.g. 800x600]"`
2019-11-19 00:32:34 +09:00
Server string `long:"server" description:"Remote session address"`
Nvim string `long:"nvim" description:"Excutable nvim path to attach"`
2019-11-13 22:49:25 +09:00
}
2017-03-14 01:52:44 +00:00
// Editor is the editor
type Editor struct {
2018-08-16 19:31:36 +09:00
signal *editorSignal
2018-08-15 17:44:53 +09:00
version string
app *widgets.QApplication
2019-06-12 21:58:35 +09:00
homeDir string
2019-11-13 22:49:25 +09:00
args []string
opts Option
2019-06-12 21:58:35 +09:00
2018-12-05 21:17:56 +09:00
notifyStartPos *core.QPoint
notificationWidth int
notify chan *Notify
guiInit chan bool
doneGuiInit bool
2018-08-15 17:44:53 +09:00
2018-01-08 10:23:16 +00:00
workspaces []*Workspace
active int
nvim *nvim.Nvim
window *frameless.QFramelessWindow
2019-10-20 18:13:56 +09:00
split *widgets.QSplitter
2018-01-08 10:23:16 +00:00
wsWidget *widgets.QWidget
wsSide *WorkspaceSide
2019-07-11 12:18:17 +09:00
sysTray *widgets.QSystemTrayIcon
2018-01-08 10:23:16 +00:00
2017-05-10 07:28:44 +01:00
statuslineHeight int
width int
height int
2018-11-08 18:10:12 +09:00
iconSize int
2017-05-10 07:28:44 +01:00
tablineHeight int
2018-01-08 10:23:16 +00:00
stop chan struct{}
stopOnce sync.Once
2018-01-05 08:07:29 +00:00
2020-03-22 23:21:40 +09:00
specialKeys map[core.Qt__Key]string
controlModifier core.Qt__KeyboardModifier
cmdModifier core.Qt__KeyboardModifier
keyControl core.Qt__Key
keyCmd core.Qt__Key
prefixToMapMetaKey string
2018-12-31 16:43:04 +09:00
config gonvimConfig
notifications []*Notification
2018-12-27 12:38:42 +09:00
isDisplayNotifications bool
2018-10-13 22:59:41 +09:00
2018-12-31 16:43:04 +09:00
isSetGuiColor bool
colors *ColorPalette
svgs map[string]*SvgXML
2019-09-29 00:17:37 +09:00
2019-09-15 23:09:46 +09:00
extFontFamily string
extFontSize int
2017-06-16 08:43:05 +01:00
}
type editorSignal struct {
core.QObject
2018-08-15 17:44:53 +09:00
_ func() `signal:"notifySignal"`
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()
}
2018-05-12 22:48:15 +09:00
highlight.bold = hl.bold
highlight.italic = hl.italic
2017-03-14 01:52:44 +00:00
return highlight
}
2017-06-06 02:42:11 +01:00
2017-11-09 02:11:05 +00:00
// InitEditor is
func InitEditor() {
2019-11-17 21:20:08 +09:00
// parse option
var opts Option
2019-11-19 00:32:34 +09:00
parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)
2019-11-17 21:20:08 +09:00
args, err := parser.ParseArgs(os.Args[1:])
if flagsErr, ok := err.(*flags.Error); ok {
switch flagsErr.Type {
case flags.ErrDuplicatedFlag:
case flags.ErrHelp:
fmt.Println(err)
os.Exit(1)
}
2019-11-13 22:49:25 +09:00
}
2019-06-12 21:58:35 +09:00
putEnv()
2019-05-18 23:57:02 +05:30
home, err := homedir.Dir()
if err != nil {
home = "~"
}
2019-06-12 21:58:35 +09:00
2018-01-05 08:07:29 +00:00
editor = &Editor{
2020-01-13 22:05:04 +09:00
version: GONEOVIMVERSION,
2018-11-29 00:53:20 +09:00
signal: NewEditorSignal(nil),
notify: make(chan *Notify, 10),
stop: make(chan struct{}),
guiInit: make(chan bool, 1),
2018-12-31 16:43:04 +09:00
config: newGonvimConfig(home),
2019-06-12 22:14:48 +09:00
homeDir: home,
2019-11-13 22:49:25 +09:00
args: args,
opts: opts,
2017-06-06 02:42:11 +01:00
}
2018-01-05 08:07:29 +00:00
e := editor
2019-06-12 21:58:35 +09:00
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
2019-11-24 12:52:15 +09:00
e.app = widgets.NewQApplication(len(os.Args), os.Args)
2018-12-29 15:40:57 +09:00
e.app.ConnectAboutToQuit(func() {
2019-06-12 21:58:35 +09:00
e.cleanup()
2018-12-29 15:40:57 +09:00
})
2019-05-09 23:22:43 +09:00
2019-06-12 21:58:35 +09:00
e.initFont()
2019-05-09 23:22:43 +09:00
e.initSVGS()
2019-06-12 21:58:35 +09:00
e.initColorPalette()
2019-05-09 23:22:43 +09:00
e.initNotifications()
2019-07-11 12:18:17 +09:00
e.initSysTray()
2019-03-02 21:40:40 +09:00
e.window = frameless.CreateQFramelessWindow(e.config.Editor.Transparent)
e.setWindowSizeFromOpts()
2018-12-29 15:40:57 +09:00
e.setWindowOptions()
2017-11-19 23:43:24 +09:00
2019-06-12 21:58:35 +09:00
l := widgets.NewQBoxLayout(widgets.QBoxLayout__RightToLeft, nil)
l.SetContentsMargins(0, 0, 0, 0)
l.SetSpacing(0)
2018-05-06 14:49:45 +09:00
2019-06-12 21:58:35 +09:00
e.window.SetupContent(l)
2019-05-14 12:56:46 +09:00
2018-01-05 08:07:29 +00:00
e.wsWidget = widgets.NewQWidget(nil, 0)
2019-01-29 18:04:31 +09:00
e.wsSide = newWorkspaceSide()
2019-10-16 19:41:37 +09:00
e.wsSide.newScrollArea()
2019-10-22 18:04:09 +09:00
e.wsSide.scrollarea.Hide()
2019-10-20 18:13:56 +09:00
e.newSplitter()
l.AddWidget(e.split, 1, 0)
2019-06-12 21:58:35 +09:00
2019-10-24 17:04:33 +09:00
e.initWorkspaces()
2019-06-12 21:58:35 +09:00
e.wsWidget.ConnectResizeEvent(func(event *gui.QResizeEvent) {
for _, ws := range e.workspaces {
ws.updateSize()
}
2019-01-29 18:04:31 +09:00
})
2019-06-12 21:58:35 +09:00
e.loadFileInDarwin()
go func() {
<-e.stop
if runtime.GOOS == "darwin" {
e.app.DisconnectEvent()
}
e.app.Quit()
}()
e.window.Show()
e.wsWidget.SetFocus2()
widgets.QApplication_Exec()
}
2019-10-20 18:13:56 +09:00
func (e *Editor) newSplitter() {
splitter := widgets.NewQSplitter2(core.Qt__Horizontal, nil)
splitter.SetStyleSheet("* {background-color: rgba(0, 0, 0, 0);}")
splitter.AddWidget(e.wsSide.scrollarea)
splitter.AddWidget(e.wsWidget)
splitter.SetSizes([]int{e.config.SideBar.Width, e.width - e.config.SideBar.Width})
splitter.SetStretchFactor(1, 100)
splitter.SetObjectName("splitter")
e.split = splitter
2019-10-22 18:04:09 +09:00
if editor.config.SideBar.Visible {
e.wsSide.show()
}
2019-10-20 18:13:56 +09:00
}
2019-06-12 21:58:35 +09:00
func (e *Editor) initWorkspaces() {
2018-10-11 21:37:36 +09:00
e.workspaces = []*Workspace{}
sessionExists := false
2019-11-21 01:01:51 +09:00
if e.config.Workspace.RestoreSession {
2019-10-22 22:50:56 +09:00
for i := 0; i <= WorkspaceLen; i++ {
2019-11-02 10:54:41 +09:00
path := filepath.Join(e.homeDir, ".goneovim", "sessions", strconv.Itoa(i)+".vim")
2019-06-12 21:58:35 +09:00
_, err := os.Stat(path)
if err != nil {
break
2018-10-11 21:37:36 +09:00
}
2019-06-12 21:58:35 +09:00
sessionExists = true
ws, err := newWorkspace(path)
if err != nil {
break
}
e.workspaces = append(e.workspaces, ws)
2018-10-11 21:37:36 +09:00
}
}
if !sessionExists {
ws, err := newWorkspace("")
if err != nil {
return
}
e.workspaces = append(e.workspaces, ws)
}
2019-06-12 17:05:51 +09:00
2019-06-12 21:58:35 +09:00
e.workspaceUpdate()
2019-05-29 00:09:39 +09:00
2019-02-01 20:31:46 +09:00
e.wsWidget.SetAttribute(core.Qt__WA_InputMethodEnabled, true)
e.wsWidget.ConnectInputMethodEvent(e.workspaces[e.active].InputMethodEvent)
e.wsWidget.ConnectInputMethodQuery(e.workspaces[e.active].InputMethodQuery)
2019-06-12 21:58:35 +09:00
}
2018-10-11 21:37:36 +09:00
2019-06-12 21:58:35 +09:00
func (e *Editor) loadFileInDarwin() {
if runtime.GOOS != "darwin" {
return
}
2018-10-11 21:37:36 +09:00
macosArg := ""
2019-06-12 21:58:35 +09:00
e.app.ConnectEvent(func(event *core.QEvent) bool {
switch event.Type() {
case core.QEvent__FileOpen:
2019-11-02 10:54:41 +09:00
// If goneovim not launched on finder (it is started in terminal)
2019-06-12 21:58:35 +09:00
if os.Getppid() != 1 {
2019-06-12 22:14:48 +09:00
return false
2019-06-12 21:58:35 +09:00
}
fileOpenEvent := gui.NewQFileOpenEventFromPointer(event.Pointer())
macosArg = fileOpenEvent.File()
2019-11-02 10:54:41 +09:00
goneovim := e.workspaces[e.active].nvim
2019-06-12 21:58:35 +09:00
isModified := ""
2019-11-02 10:54:41 +09:00
isModified, _ = goneovim.CommandOutput("echo &modified")
2019-06-12 21:58:35 +09:00
if isModified == "1" {
2019-11-02 10:54:41 +09:00
goneovim.Command(fmt.Sprintf(":tabe %s", macosArg))
2019-06-12 21:58:35 +09:00
} else {
2019-11-02 10:54:41 +09:00
goneovim.Command(fmt.Sprintf(":e %s", macosArg))
}
2018-05-25 01:00:23 +09:00
}
2019-06-12 21:58:35 +09:00
return true
})
e.window.ConnectCloseEvent(func(event *gui.QCloseEvent) {
e.app.DisconnectEvent()
event.Accept()
})
2018-01-05 08:07:29 +00:00
}
2018-12-29 17:31:44 +09:00
func (e *Editor) initNotifications() {
e.notifications = []*Notification{}
2019-06-12 21:58:35 +09:00
e.notificationWidth = e.config.Editor.Width * 2 / 3
2018-12-29 17:31:44 +09:00
e.notifyStartPos = core.NewQPoint2(e.width-e.notificationWidth-10, e.height-30)
e.signal.ConnectNotifySignal(func() {
notify := <-e.notify
if notify.message == "" {
return
}
if notify.buttons == nil {
e.popupNotification(notify.level, notify.period, notify.message)
} else {
e.popupNotification(notify.level, notify.period, notify.message, notifyOptionArg(notify.buttons))
}
})
}
2019-07-11 12:18:17 +09:00
func (e *Editor) initSysTray() {
if !e.config.Editor.DesktopNotifications {
return
}
2019-07-11 18:28:37 +09:00
pixmap := gui.NewQPixmap()
2019-07-12 00:28:27 +09:00
color := ""
size := 0.95
if runtime.GOOS == "darwin" {
2019-07-15 19:41:49 +09:00
color = "#434343"
2019-07-12 00:28:27 +09:00
size = 0.9
} else {
color = "#179A33"
}
svg := fmt.Sprintf(`<svg viewBox="0 0 128 128"><g transform="translate(2,3) scale(%f)"><path fill="%s" d="M72.6 80.5c.2.2.6.5.9.5h5.3c.3 0 .7-.3.9-.5l1.4-1.5c.2-.2.3-.4.3-.6l1.5-5.1c.1-.5 0-1-.3-1.3l-1.1-.9c-.2-.2-.6-.1-.9-.1h-4.8l-.2-.2-.1-.1c-.2 0-.4-.1-.6.1l-1.9 1.2c-.2 0-.3.5-.4.7l-1.6 4.9c-.2.5-.1 1.1.3 1.5l1.3 1.4zM73.4 106.9l-.4.1h-1.2l7.2-21.1c.2-.7-.1-1.5-.8-1.7l-.4-.1h-12.1c-.5.1-.9.5-1 1l-.7 2.5c-.2.7.3 1.3 1 1.5l.3-.1h1.8l-7.3 20.9c-.2.7.1 1.6.8 1.9l.4.3h11.2c.6 0 1.1-.5 1.3-1.1l.7-2.4c.3-.7-.1-1.5-.8-1.7zM126.5 87.2l-1.9-2.5v-.1c-.3-.3-.6-.6-1-.6h-7.2c-.4 0-.7.4-1 .6l-2 2.4h-3.1l-2.1-2.4v-.1c-.2-.3-.6-.5-1-.5h-4l20.2-20.2-22.6-22.4 20.2-20.8v-9l-2.8-3.6h-40.9l-3.3 3.5v2.9l-11.3-11.4-7.7 7.5-2.4-2.5h-40.4l-3.2 3.7v9.4l3 2.9h3v26.1l-14 14 14 14v32l5.2 2.9h11.6l9.1-9.5 21.6 21.6 14.5-14.5c.1.4.4.5.9.7l.4-.2h9.4c.6 0 1.1-.1 1.2-.6l.7-2c.2-.7-.1-1.3-.8-1.5l-.4.1h-.4l3.4-10.7 2.3-2.3h5l-5 15.9c-.2.7.2 1.1.9 1.4l.4-.2h9.1c.5 0 1-.1 1.2-.6l.8-1.8c.3-.7-.1-1.3-.7-1.6-.1-.1-.3 0-.5 0h-.4l4.2-13h6.1l-5.1 15.9c-.2.7.2 1.1.9 1.3l.4-.3h10c.5 0 1-.1 1.2-.6l.8-2c.3-.7-.1-1.3-.8-1.5-.1-.1-.3.1-.5.1h-.7l5.6-18.5c.2-.5.1-1.1-.1-1.4zm-63.8-82.3l11.3 11.3v4.7l3.4 4.1h1.6l-29 28v-28h3.3l2.7-4.2v-8.9l-.2-.3 6.9-6.7zm-59.8 59.2l12.1-12.1v24.2l-12.1-12.1zm38.9 38.3l58.4-60 21.4 21.5-20.2 20.2h-.1c-.3.1-.5.3-.7.5l-2.1 2.4h-2.9l-2.2-2.4c-.2-.3-.6-.6-1-.6h-8.8c-.6 0-1.1.4-1.3 1l-.8 2.5c-.2.7.1 1.3.8 1.6h1.5l-6.4 18.9-15.1 15.2-20.5-20.8z"></path></g></svg>`, size, color)
2019-07-11 18:28:37 +09:00
pixmap.LoadFromData2(core.NewQByteArray2(svg, len(svg)), "SVG", core.Qt__ColorOnly)
trayIcon := gui.NewQIcon2(pixmap)
2019-11-02 10:54:41 +09:00
image := filepath.Join(e.homeDir, ".goneovim", "trayicon.png")
if isFileExist(image) {
trayIcon = gui.NewQIcon5(image)
}
2019-07-11 12:18:17 +09:00
e.sysTray = widgets.NewQSystemTrayIcon2(trayIcon, e.app)
2019-07-11 15:47:36 +09:00
e.sysTray.Show()
2019-07-11 12:18:17 +09:00
}
2019-06-12 21:58:35 +09:00
func putEnv() {
if runtime.GOOS == "linux" {
exe, _ := os.Executable()
dir, _ := filepath.Split(exe)
_ = os.Setenv("LD_LIBRARY_PATH", dir+"lib")
_ = os.Setenv("QT_PLUGIN_PATH", dir+"plugins")
2019-11-23 00:28:26 +09:00
_ = os.Setenv("RESOURCE_NAME", "goneovim")
2019-06-12 21:58:35 +09:00
}
2019-12-07 13:19:58 +09:00
if runtime.GOOS == "darwin" {
shell := os.Getenv("SHELL")
if shell == "" {
shell = os.Getenv("/bin/bash")
}
cmd := exec.Command(shell, "-l", "-c", "env", "-i")
stdout, err := cmd.StdoutPipe()
if err != nil {
return
}
if err := cmd.Start(); err != nil {
2019-12-07 13:19:58 +09:00
return
}
output, err := ioutil.ReadAll(stdout)
if err != nil {
stdout.Close()
return
}
for _, b := range strings.Split(string(output), "\n") {
splits := strings.Split(b, "=")
if len(splits) > 1 {
_ = os.Setenv(splits[0], splits[1])
}
}
}
2019-11-02 10:30:06 +09:00
_ = os.Setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1")
2019-06-12 21:58:35 +09:00
}
func (e *Editor) initFont() {
2019-09-15 23:09:46 +09:00
e.extFontFamily = e.config.Editor.FontFamily
e.extFontSize = e.config.Editor.FontSize
if e.extFontFamily == "" {
switch runtime.GOOS {
case "windows":
e.extFontFamily = "Consolas"
case "darwin":
e.extFontFamily = "Monaco"
default:
e.extFontFamily = "Monospace"
}
}
if e.extFontSize <= 5 {
e.extFontSize = 13
}
e.app.SetFont(gui.NewQFont2(e.extFontFamily, e.extFontSize, 1, false), "QWidget")
e.app.SetFont(gui.NewQFont2(e.extFontFamily, e.extFontSize, 1, false), "QLabel")
2019-06-12 21:58:35 +09:00
}
func (e *Editor) pushNotification(level NotifyLevel, p int, message string, opt ...NotifyOptionArg) {
2018-08-16 19:31:36 +09:00
opts := NotifyOptions{}
for _, o := range opt {
o(&opts)
}
n := &Notify{
level: level,
period: p,
2018-08-16 19:31:36 +09:00
message: message,
buttons: opts.buttons,
}
e.notify <- n
e.signal.NotifySignal()
}
func (e *Editor) popupNotification(level NotifyLevel, p int, message string, opt ...NotifyOptionArg) {
notification := newNotification(level, p, message, opt...)
2018-08-15 17:44:53 +09:00
notification.widget.SetParent(e.window)
notification.widget.AdjustSize()
x := e.notifyStartPos.X()
y := e.notifyStartPos.Y() - notification.widget.Height() - 4
2018-08-15 17:44:53 +09:00
notification.widget.Move2(x, y)
e.notifyStartPos = core.NewQPoint2(x, y)
e.notifications = append(e.notifications, notification)
2018-08-15 17:44:53 +09:00
notification.show()
}
2019-06-12 21:58:35 +09:00
func (e *Editor) initColorPalette() {
rgbAccent := hexToRGBA(e.config.SideBar.AccentColor)
2018-12-28 01:40:33 +09:00
fg := newRGBA(180, 185, 190, 1)
bg := newRGBA(9, 13, 17, 1)
2019-06-12 21:58:35 +09:00
c := &ColorPalette{
e: e,
2018-12-31 16:43:04 +09:00
bg: bg,
fg: fg,
2018-12-28 15:46:52 +09:00
selectedBg: bg.brend(rgbAccent, 0.3),
2018-12-31 16:43:04 +09:00
matchFg: rgbAccent,
2018-12-27 12:38:42 +09:00
}
2019-06-12 21:58:35 +09:00
e.colors = c
e.colors.update()
2018-12-27 12:38:42 +09:00
}
2018-12-27 21:03:21 +09:00
func (c *ColorPalette) update() {
fg := c.fg
bg := c.bg
2019-06-12 21:58:35 +09:00
rgbAccent := hexToRGBA(c.e.config.SideBar.AccentColor)
2018-12-28 15:46:52 +09:00
c.selectedBg = bg.brend(rgbAccent, 0.3)
2019-03-20 22:41:06 +09:00
c.inactiveFg = warpColor(bg, -80)
c.comment = warpColor(fg, -80)
2018-12-28 01:40:33 +09:00
c.abyss = warpColor(bg, 5)
2019-03-20 22:41:06 +09:00
c.sideBarFg = warpColor(fg, -5)
c.sideBarBg = warpColor(bg, -5)
c.sideBarSelectedItemBg = warpColor(bg, -15)
c.scrollBarFg = warpColor(bg, -20)
2018-12-27 21:03:21 +09:00
c.scrollBarBg = bg
2019-03-20 22:41:06 +09:00
c.widgetFg = warpColor(fg, 5)
c.widgetBg = warpColor(bg, -10)
c.widgetInputArea = warpColor(bg, -30)
c.minimapCurrentRegion = warpColor(bg, 20)
2019-05-31 16:41:37 +09:00
c.windowSeparator = warpColor(bg, -40)
2019-10-29 21:53:26 +09:00
c.indentGuide = warpColor(bg, -30)
2018-12-27 21:03:21 +09:00
}
func (e *Editor) updateGUIColor() {
2019-01-01 18:34:51 +09:00
e.workspaces[e.active].updateWorkspaceColor()
2019-03-02 21:40:40 +09:00
2019-10-27 15:59:27 +09:00
// Do not use frameless drawing on linux
if runtime.GOOS == "linux" {
// e.window.Widget.SetStyleSheet(fmt.Sprintf(" * { background-color: rgba(%d, %d, %d, %f); }", e.colors.bg.R, e.colors.bg.G, e.colors.bg.B, e.config.Editor.Transparent))
2019-05-14 12:32:00 +09:00
e.window.TitleBar.Hide()
2019-10-27 15:59:27 +09:00
e.window.WindowWidget.SetStyleSheet(fmt.Sprintf(" #QFramelessWidget { background-color: rgba(%d, %d, %d, %f); border-radius: 0px;}", e.colors.bg.R, e.colors.bg.G, e.colors.bg.B, e.config.Editor.Transparent))
2019-05-14 12:32:00 +09:00
e.window.SetWindowFlag(core.Qt__FramelessWindowHint, false)
e.window.SetWindowFlag(core.Qt__NoDropShadowWindowHint, false)
e.window.Show()
2019-10-27 15:59:27 +09:00
} else {
e.window.SetupWidgetColor((uint16)(e.colors.bg.R), (uint16)(e.colors.bg.G), (uint16)(e.colors.bg.B))
e.window.SetupTitleColor((uint16)(e.colors.fg.R), (uint16)(e.colors.fg.G), (uint16)(e.colors.fg.B))
2019-05-09 23:22:43 +09:00
}
2018-12-28 01:40:33 +09:00
e.window.SetWindowOpacity(1.0)
2018-12-27 21:03:21 +09:00
}
2018-06-24 13:36:41 +09:00
func hexToRGBA(hex string) *RGBA {
format := "#%02x%02x%02x"
if len(hex) == 4 {
format = "#%1x%1x%1x"
}
var r, g, b uint8
n, err := fmt.Sscanf(hex, format, &r, &g, &b)
if err != nil {
return nil
}
if n != 3 {
return nil
}
rgba := &RGBA{
R: (int)(r),
G: (int)(g),
B: (int)(b),
A: 1,
}
return rgba
}
func (e *Editor) setWindowSizeFromOpts() {
if e.opts.Geometry == "" {
return
}
width, height := e.setWindowSize(e.opts.Geometry)
e.config.Editor.Width = width
e.config.Editor.Height = height
}
func (e *Editor) setWindowSize(s string) (int, int) {
var width, height int
var err error
width, err = strconv.Atoi(strings.SplitN(s, "x", 2)[0])
if err != nil || width < 400 {
width = 400
}
height, err = strconv.Atoi(strings.SplitN(s, "x", 2)[1])
if err != nil || height < 300 {
height = 300
}
return width, height
}
2018-12-29 15:40:57 +09:00
func (e *Editor) setWindowOptions() {
2019-11-02 10:54:41 +09:00
e.window.SetupTitle("goneovim")
e.window.SetupWidgetColor(0, 0, 0)
2018-12-29 17:31:44 +09:00
e.width = e.config.Editor.Width
e.height = e.config.Editor.Height
2020-03-15 13:47:40 +09:00
e.window.SetMinimumSize2(400, 300)
e.window.Resize2(e.width, e.height)
2018-12-29 15:40:57 +09:00
e.window.SetWindowOpacity(0.0)
e.initSpecialKeys()
e.window.ConnectKeyPressEvent(e.keyPress)
2020-03-22 22:51:13 +09:00
e.window.SetAttribute(core.Qt__WA_KeyCompression, false)
2018-12-29 15:40:57 +09:00
e.window.SetAcceptDrops(true)
if e.config.Editor.StartFullscreen || e.opts.Fullscreen {
2019-11-14 20:01:26 +09:00
e.window.ShowFullScreen()
} else if e.config.Editor.StartMaximizedWindow || e.opts.Maximized {
2019-11-14 20:01:26 +09:00
e.window.WindowMaximize()
}
2018-12-29 15:40:57 +09:00
}
2018-04-19 21:07:48 +09:00
func isFileExist(filename string) bool {
2018-04-30 16:58:26 +09:00
_, err := os.Stat(filename)
return err == nil
2018-04-19 21:07:48 +09:00
}
2018-06-13 21:08:02 +09:00
func (e *Editor) copyClipBoard() {
go func() {
var yankedText string
2018-06-16 10:15:40 +09:00
yankedText, _ = e.workspaces[e.active].nvim.CommandOutput("echo getreg()")
2018-06-13 21:08:02 +09:00
if yankedText != "" {
clipb.WriteAll(yankedText)
}
}()
2018-06-16 10:15:40 +09:00
2018-06-13 21:08:02 +09:00
}
2018-01-05 09:13:50 +00:00
func (e *Editor) workspaceNew() {
2018-12-28 13:53:55 +09:00
editor.isSetGuiColor = false
2018-01-11 06:11:34 +00:00
ws, err := newWorkspace("")
2018-01-05 09:13:50 +00:00
if err != nil {
return
}
2018-05-20 12:06:29 +09:00
2018-01-05 09:13:50 +00:00
e.workspaces = append(e.workspaces, nil)
2018-05-01 19:50:47 +09:00
e.active = len(e.workspaces) - 1
2018-01-05 09:13:50 +00:00
e.workspaces[e.active] = ws
2018-01-08 10:23:16 +00:00
e.workspaceUpdate()
}
func (e *Editor) workspaceSwitch(index int) {
index--
if index < 0 || index >= len(e.workspaces) {
return
}
e.active = index
2018-01-05 09:13:50 +00:00
e.workspaceUpdate()
}
func (e *Editor) workspaceNext() {
e.active++
if e.active >= len(e.workspaces) {
e.active = 0
}
e.workspaceUpdate()
}
2018-01-11 06:11:34 +00:00
func (e *Editor) workspacePrevious() {
e.active--
if e.active < 0 {
e.active = len(e.workspaces) - 1
}
e.workspaceUpdate()
}
2018-01-05 09:13:50 +00:00
func (e *Editor) workspaceUpdate() {
if e.wsSide == nil {
return
}
2018-01-05 09:13:50 +00:00
for i, ws := range e.workspaces {
if i == e.active {
ws.hide()
ws.show()
} else {
ws.hide()
}
}
2018-09-22 21:56:33 +09:00
for i := 0; i < len(e.wsSide.items) && i < len(e.workspaces); i++ {
2018-08-28 02:04:53 +09:00
e.wsSide.items[i].setSideItemLabel(i)
2018-04-30 16:39:39 +09:00
e.wsSide.items[i].setText(e.workspaces[i].cwdlabel)
2018-01-08 10:23:16 +00:00
e.wsSide.items[i].show()
}
for i := len(e.workspaces); i < len(e.wsSide.items); i++ {
e.wsSide.items[i].hide()
}
2018-01-05 09:13:50 +00:00
}
2018-01-05 08:07:29 +00:00
func (e *Editor) keyPress(event *gui.QKeyEvent) {
input := e.convertKey(event)
2018-01-05 08:07:29 +00:00
if input != "" {
2018-01-05 09:13:50 +00:00
e.workspaces[e.active].nvim.Input(input)
2017-06-06 02:42:11 +01:00
}
2018-01-05 08:07:29 +00:00
}
2017-06-06 02:42:11 +01:00
func (e *Editor) convertKey(event *gui.QKeyEvent) string {
text := event.Text()
key := event.Key()
mod := event.Modifiers()
2020-05-30 20:39:21 +09:00
// this is macmeta alternatively
if runtime.GOOS == "darwin" {
if editor.config.Editor.Macmeta {
if mod&core.Qt__AltModifier > 0 && mod&core.Qt__ShiftModifier > 0 {
text = string(key)
} else if mod&core.Qt__AltModifier > 0 && !(mod&core.Qt__ShiftModifier > 0) {
text = strings.ToLower(string(key))
}
}
}
2018-01-05 08:07:29 +00:00
if mod&core.Qt__KeypadModifier > 0 {
switch core.Qt__Key(key) {
case core.Qt__Key_Home:
return fmt.Sprintf("<%sHome>", e.modPrefix(mod))
case core.Qt__Key_End:
return fmt.Sprintf("<%sEnd>", e.modPrefix(mod))
case core.Qt__Key_PageUp:
return fmt.Sprintf("<%sPageUp>", e.modPrefix(mod))
case core.Qt__Key_PageDown:
return fmt.Sprintf("<%sPageDown>", e.modPrefix(mod))
case core.Qt__Key_Plus:
return fmt.Sprintf("<%sPlus>", e.modPrefix(mod))
case core.Qt__Key_Minus:
return fmt.Sprintf("<%sMinus>", e.modPrefix(mod))
case core.Qt__Key_multiply:
return fmt.Sprintf("<%sMultiply>", e.modPrefix(mod))
case core.Qt__Key_division:
return fmt.Sprintf("<%sDivide>", e.modPrefix(mod))
case core.Qt__Key_Enter:
return fmt.Sprintf("<%sEnter>", e.modPrefix(mod))
case core.Qt__Key_Period:
return fmt.Sprintf("<%sPoint>", e.modPrefix(mod))
case core.Qt__Key_0:
return fmt.Sprintf("<%s0>", e.modPrefix(mod))
case core.Qt__Key_1:
return fmt.Sprintf("<%s1>", e.modPrefix(mod))
case core.Qt__Key_2:
return fmt.Sprintf("<%s2>", e.modPrefix(mod))
case core.Qt__Key_3:
return fmt.Sprintf("<%s3>", e.modPrefix(mod))
case core.Qt__Key_4:
return fmt.Sprintf("<%s4>", e.modPrefix(mod))
case core.Qt__Key_5:
return fmt.Sprintf("<%s5>", e.modPrefix(mod))
case core.Qt__Key_6:
return fmt.Sprintf("<%s6>", e.modPrefix(mod))
case core.Qt__Key_7:
return fmt.Sprintf("<%s7>", e.modPrefix(mod))
case core.Qt__Key_8:
return fmt.Sprintf("<%s8>", e.modPrefix(mod))
case core.Qt__Key_9:
return fmt.Sprintf("<%s9>", e.modPrefix(mod))
}
}
2017-06-16 08:43:05 +01:00
2018-01-05 08:07:29 +00:00
if text == "<" {
2020-03-24 23:40:45 +09:00
// return "<lt>"
modNoShift := mod & ^core.Qt__ShiftModifier
return fmt.Sprintf("<%s%s>", e.modPrefix(modNoShift), "lt")
2017-06-06 02:42:11 +01:00
}
2018-01-05 08:07:29 +00:00
specialKey, ok := e.specialKeys[core.Qt__Key(key)]
if ok {
return fmt.Sprintf("<%s%s>", e.modPrefix(mod), specialKey)
}
2017-06-16 08:43:05 +01:00
2020-03-22 22:51:13 +09:00
if text == "\\" {
2018-01-05 08:07:29 +00:00
return fmt.Sprintf("<%s%s>", e.modPrefix(mod), "Bslash")
}
2017-06-16 08:43:05 +01:00
2018-01-05 08:07:29 +00:00
c := ""
2020-03-22 22:51:13 +09:00
if text == "" {
if key == int(core.Qt__Key_Alt ) ||
key == int(core.Qt__Key_AltGr ) ||
key == int(core.Qt__Key_CapsLock) ||
key == int(core.Qt__Key_Control ) ||
key == int(core.Qt__Key_Meta ) ||
key == int(core.Qt__Key_Shift ) ||
key == int(core.Qt__Key_Super_L ) ||
key == int(core.Qt__Key_Super_R ) {
2018-01-05 08:07:29 +00:00
return ""
2017-06-06 02:42:11 +01:00
}
2020-03-24 23:40:45 +09:00
text = string(key)
if !(mod&core.Qt__ShiftModifier > 0) {
2020-03-24 23:40:45 +09:00
text = strings.ToLower(text)
}
}
c = string(text)
if c == "" {
return ""
2018-01-05 08:07:29 +00:00
}
2020-03-22 22:51:13 +09:00
char := core.NewQChar11(c)
// Remove SHIFT
if char.Unicode() >= 0x80 || char.IsPrint() {
mod &= ^core.Qt__ShiftModifier
2019-10-31 23:06:47 +09:00
}
2020-03-22 22:51:13 +09:00
// Remove CTRL
if char.Unicode() < 0x20 {
mod &= ^e.controlModifier
2018-01-05 08:07:29 +00:00
}
2017-06-13 16:15:05 +01:00
2020-03-24 23:40:45 +09:00
if runtime.GOOS == "darwin" {
2020-03-22 22:51:13 +09:00
// Remove ALT/OPTION
if (char.Unicode() >= 0x80 && char.IsPrint()) {
mod &= ^core.Qt__AltModifier
2020-03-22 22:51:13 +09:00
}
2017-07-03 07:14:29 +01:00
}
2018-01-05 08:07:29 +00:00
prefix := e.modPrefix(mod)
if prefix != "" {
return fmt.Sprintf("<%s%s>", prefix, c)
}
return c
}
func (e *Editor) modPrefix(mod core.Qt__KeyboardModifier) string {
prefix := ""
if runtime.GOOS == "windows" {
2020-03-24 23:40:45 +09:00
if mod&e.controlModifier > 0 && !(mod&core.Qt__AltModifier > 0) {
prefix += "C-"
}
if mod&core.Qt__ShiftModifier > 0 {
prefix += "S-"
}
2020-03-24 23:40:45 +09:00
if mod&core.Qt__AltModifier > 0 && !(mod&e.controlModifier > 0) {
prefix += e.prefixToMapMetaKey
}
} else {
2018-01-05 08:07:29 +00:00
if mod&e.cmdModifier > 0 {
prefix += "D-"
2017-07-03 07:14:29 +01:00
}
if mod&e.controlModifier > 0 {
2020-03-22 22:51:13 +09:00
prefix += "C-"
}
if mod&core.Qt__ShiftModifier > 0 {
prefix += "S-"
}
if mod&core.Qt__AltModifier > 0 {
2020-03-22 23:21:40 +09:00
prefix += e.prefixToMapMetaKey
2020-03-22 22:51:13 +09:00
}
2018-01-05 08:07:29 +00:00
}
return prefix
}
func (e *Editor) initSpecialKeys() {
e.specialKeys = map[core.Qt__Key]string{}
e.specialKeys[core.Qt__Key_Up] = "Up"
e.specialKeys[core.Qt__Key_Down] = "Down"
e.specialKeys[core.Qt__Key_Left] = "Left"
e.specialKeys[core.Qt__Key_Right] = "Right"
e.specialKeys[core.Qt__Key_F1] = "F1"
e.specialKeys[core.Qt__Key_F2] = "F2"
e.specialKeys[core.Qt__Key_F3] = "F3"
e.specialKeys[core.Qt__Key_F4] = "F4"
e.specialKeys[core.Qt__Key_F5] = "F5"
e.specialKeys[core.Qt__Key_F6] = "F6"
e.specialKeys[core.Qt__Key_F7] = "F7"
e.specialKeys[core.Qt__Key_F8] = "F8"
e.specialKeys[core.Qt__Key_F9] = "F9"
e.specialKeys[core.Qt__Key_F10] = "F10"
e.specialKeys[core.Qt__Key_F11] = "F11"
e.specialKeys[core.Qt__Key_F12] = "F12"
e.specialKeys[core.Qt__Key_F13] = "F13"
e.specialKeys[core.Qt__Key_F14] = "F14"
e.specialKeys[core.Qt__Key_F15] = "F15"
e.specialKeys[core.Qt__Key_F16] = "F16"
e.specialKeys[core.Qt__Key_F17] = "F17"
e.specialKeys[core.Qt__Key_F18] = "F18"
e.specialKeys[core.Qt__Key_F19] = "F19"
e.specialKeys[core.Qt__Key_F20] = "F20"
e.specialKeys[core.Qt__Key_F21] = "F21"
e.specialKeys[core.Qt__Key_F22] = "F22"
e.specialKeys[core.Qt__Key_F23] = "F23"
e.specialKeys[core.Qt__Key_F24] = "F24"
e.specialKeys[core.Qt__Key_Backspace] = "BS"
2020-03-22 22:51:13 +09:00
e.specialKeys[core.Qt__Key_Delete] = "Del"
e.specialKeys[core.Qt__Key_Insert] = "Insert"
e.specialKeys[core.Qt__Key_Home] = "Home"
e.specialKeys[core.Qt__Key_End] = "End"
e.specialKeys[core.Qt__Key_PageUp] = "PageUp"
e.specialKeys[core.Qt__Key_PageDown] = "PageDown"
e.specialKeys[core.Qt__Key_Return] = "Enter"
e.specialKeys[core.Qt__Key_Enter] = "Enter"
e.specialKeys[core.Qt__Key_Tab] = "Tab"
e.specialKeys[core.Qt__Key_Backtab] = "Tab"
e.specialKeys[core.Qt__Key_Escape] = "Esc"
2018-01-05 08:07:29 +00:00
e.specialKeys[core.Qt__Key_Backslash] = "Bslash"
2020-03-22 22:51:13 +09:00
e.specialKeys[core.Qt__Key_Space] = "Space"
2018-01-05 08:07:29 +00:00
if runtime.GOOS == "darwin" {
2018-01-05 08:07:29 +00:00
e.controlModifier = core.Qt__MetaModifier
e.cmdModifier = core.Qt__ControlModifier
e.keyControl = core.Qt__Key_Meta
e.keyCmd = core.Qt__Key_Control
} else if runtime.GOOS == "windows" {
e.controlModifier = core.Qt__ControlModifier
e.cmdModifier = (core.Qt__KeyboardModifier)(0)
e.keyControl = core.Qt__Key_Control
e.keyCmd = (core.Qt__Key)(0)
2018-01-05 08:07:29 +00:00
} else {
e.controlModifier = core.Qt__ControlModifier
e.cmdModifier = core.Qt__MetaModifier
2018-01-05 08:07:29 +00:00
e.keyControl = core.Qt__Key_Control
e.keyCmd = core.Qt__Key_Meta
2018-01-05 08:07:29 +00:00
}
2020-03-24 23:40:45 +09:00
e.prefixToMapMetaKey = "A-"
2017-06-06 02:42:11 +01:00
}
2018-01-08 10:23:16 +00:00
func (e *Editor) close() {
e.stopOnce.Do(func() {
close(e.stop)
})
}
func (e *Editor) cleanup() {
home, err := homedir.Dir()
if err != nil {
return
}
2019-11-02 10:54:41 +09:00
sessions := filepath.Join(home, ".goneovim", "sessions")
2018-01-08 10:23:16 +00:00
os.RemoveAll(sessions)
os.MkdirAll(sessions, 0755)
2018-01-11 06:11:34 +00:00
select {
case <-e.stop:
return
default:
}
2018-01-08 10:23:16 +00:00
for i, ws := range e.workspaces {
sessionPath := filepath.Join(sessions, strconv.Itoa(i)+".vim")
fmt.Println(sessionPath)
fmt.Println(ws.nvim.Command("mksession " + sessionPath))
fmt.Println("mksession finished")
}
}