akiyosi.goneovim/editor/editor.go

1312 lines
35 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"
"log"
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"
"time"
2021-07-25 22:35:17 +09:00
"unicode"
2017-03-14 01:52:44 +00:00
"github.com/akiyosi/goneovim/util"
2019-03-13 11:50:52 +09:00
frameless "github.com/akiyosi/goqtframelesswindow"
clipb "github.com/atotto/clipboard"
2019-11-19 00:32:34 +09:00
homedir "github.com/mitchellh/go-homedir"
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
)
2021-08-06 23:13:30 +09:00
var Version string
2017-03-14 01:52:44 +00:00
var editor *Editor
2019-10-22 22:50:56 +09:00
const (
2021-08-06 23:13:30 +09:00
WORKSPACELEN = 10
2019-10-22 22:50:56 +09:00
)
2020-12-12 01:39:52 +09:00
type editorSignal struct {
core.QObject
_ func() `signal:"notifySignal"`
_ func() `signal:"sidebarSignal"`
}
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 {
message string
buttons []*NotifyButton
2021-12-10 21:24:04 +09:00
level NotifyLevel
period int
2018-08-16 19:31:36 +09:00
}
type Options struct {
2022-04-19 11:49:35 +09:00
Geometry string `long:"geometry" description:"Initial window geomtry [e.g. --geometry=800x600]"`
Server string `long:"server" description:"Remote session address [e.g. --server=host:3456]"`
Ssh string `long:"ssh" description:"Attaching to a remote nvim via ssh. Default port is 22. [e.g. --ssh=user@host:port]"`
Nvim string `long:"nvim" description:"Excutable nvim path to attach [e.g. --nvim=/path/to/nvim]"`
Debug string `long:"debug" description:"Run debug mode with debug.log(default) file [e.g. --debug=/path/to/my-debug.log]" optional:"yes" optional-value:"debug.log"`
Fullscreen bool `long:"fullscreen" description:"Open the window in fullscreen on startup"`
Maximized bool `long:"maximized" description:"Maximize the window on startup"`
Exttabline bool `long:"exttabline" description:"Externalize the tabline"`
Extcmdline bool `long:"extcmdline" description:"Externalize the cmdline"`
Extmessages bool `long:"extmessages" description:"Externalize the messages. Sets --extcmdline implicitly"`
Extpopupmenu bool `long:"extpopupmenu" description:"Externalize the popupmenu"`
Version bool `long:"version" description:"Print Goneovim version"`
Wsl *string `long:"wsl" description:"Attach to nvim process in wsl environment with distribution(default) [e.g. --wsl=Ubuntu]" optional:"yes" optional-value:""`
2019-11-13 22:49:25 +09:00
}
2017-03-14 01:52:44 +00:00
// Editor is the editor
type Editor struct {
2022-03-01 14:30:47 +09:00
stop chan int
2021-12-10 21:24:04 +09:00
signal *editorSignal
app *widgets.QApplication
font *Font
widget *widgets.QWidget
splitter *widgets.QSplitter
window *frameless.QFramelessWindow
specialKeys map[core.Qt__Key]string
svgs map[string]*SvgXML
notifyStartPos *core.QPoint
colors *ColorPalette
notify chan *Notify
cbChan chan *string
sysTray *widgets.QSystemTrayIcon
side *WorkspaceSide
savedGeometry *core.QByteArray
2021-12-10 21:24:04 +09:00
prefixToMapMetaKey string
macAppArg string
extFontFamily string
configDir string
homeDir string
version string
2018-12-31 16:43:04 +09:00
config gonvimConfig
2021-12-10 21:24:04 +09:00
opts Options
2018-12-31 16:43:04 +09:00
notifications []*Notification
2021-12-10 21:24:04 +09:00
workspaces []*Workspace
args []string
ppid int
keyControl core.Qt__Key
keyCmd core.Qt__Key
width int
active int
startuptime int64
iconSize int
height int
extFontSize int
notificationWidth int
stopOnce sync.Once
muMetaKey sync.Mutex
isSetGuiColor bool
2018-12-27 12:38:42 +09:00
isDisplayNotifications bool
2021-12-10 21:24:04 +09:00
isKeyAutoRepeating bool
sessionExists bool
isWindowResized bool
2017-06-16 08:43:05 +01: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()
}
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
2021-08-06 23:13:30 +09:00
func InitEditor(options Options, args []string) {
// startup time
startuptime := time.Now().UnixNano() / 1000
// create editor struct
editor = &Editor{
2021-08-06 23:13:30 +09:00
version: Version,
args: args,
opts: options,
startuptime: startuptime,
}
e := editor
// log
var file *os.File
var err error
2021-01-25 23:24:53 +09:00
if e.opts.Debug != "" {
file, err = os.OpenFile(e.opts.Debug, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
2021-01-25 23:24:53 +09:00
fmt.Println(err)
os.Exit(1)
}
log.SetOutput(file)
log.SetFlags(log.LstdFlags | log.Lmicroseconds)
}
e.putLog("--- GONEOVIM STARTING ---")
2020-12-04 23:14:06 +09:00
e.signal = NewEditorSignal(nil)
2022-03-01 14:30:47 +09:00
e.stop = make(chan int)
e.notify = make(chan *Notify, 10)
e.cbChan = make(chan *string, 240)
2020-08-01 14:22:34 +09:00
// detect home dir
home, err := homedir.Dir()
if err != nil {
home = "~"
}
e.putLog("detecting home directory path")
2020-12-04 23:14:06 +09:00
configDir, config := newConfig(home)
e.config = config
2021-12-10 21:24:04 +09:00
if e.opts.Exttabline {
e.config.Editor.ExtTabline = true
}
if e.opts.Extcmdline {
e.config.Editor.ExtCmdline = true
}
if e.opts.Extpopupmenu {
e.config.Editor.ExtPopupmenu = true
}
if e.opts.Extmessages {
e.config.Editor.ExtMessages = true
e.config.Editor.ExtCmdline = true
}
e.homeDir = home
e.configDir = configDir
e.putLog("reading config")
2020-08-01 14:22:34 +09:00
// application
e.putLog("start generating the application")
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)
2020-10-05 23:02:44 +09:00
e.ppid = os.Getppid()
e.putLog("finished generating the application")
2020-12-27 21:32:52 +09:00
// put shell environment
// TODO: This process runs on a Unix-like OS, but it is very slow. I want to improve it.
e.setEnv()
e.putLog("setting environment variable")
2020-08-01 14:22:34 +09:00
// set application working directory path
2022-04-23 01:31:11 +09:00
// TODO: This process is problematic and needs a better way to set up CWD
// * https://github.com/akiyosi/goneovim/issues/43
// * https://github.com/akiyosi/goneovim/issues/337
// * https://github.com/akiyosi/goneovim/issues/325
// e.setAppDirPath(home)
e.putLog("set working directory path")
2020-12-24 23:45:33 +09:00
e.extFontFamily = e.config.Editor.FontFamily
e.extFontSize = e.config.Editor.FontSize
2020-12-05 14:36:12 +09:00
fontGenAsync := make(chan *Font, 2)
go func() {
font := initFontNew(
editor.extFontFamily,
float64(editor.extFontSize),
0,
2021-11-30 23:15:52 +09:00
e.config.Editor.Letterspace,
2020-12-05 14:36:12 +09:00
)
fontGenAsync <- font
}()
2021-02-09 22:26:24 +09:00
e.setFont()
e.putLog("initializing font")
2020-12-11 21:59:47 +09:00
e.initSVGS()
e.putLog("initializing svg images")
2020-12-11 21:59:47 +09:00
e.initColorPalette()
e.putLog("initializing color palette")
2020-12-11 21:59:47 +09:00
e.initNotifications()
e.putLog("initializing notification UI")
2020-12-11 21:59:47 +09:00
e.initSysTray()
2020-08-01 14:22:34 +09:00
// application main window
// e.window = widgets.NewQMainWindow(nil, 0)
e.putLog("start preparing the application window.")
isframeless := e.config.Editor.BorderlessWindow
e.window = frameless.CreateQFramelessWindow(e.config.Editor.Transparent, isframeless)
e.window.SetupBorderSize(e.config.Editor.Margin)
e.window.SetupWindowGap(e.config.Editor.Gap)
2020-12-24 23:45:33 +09:00
e.setWindowSizeFromOpts()
e.showWindow()
2018-12-29 15:40:57 +09:00
e.setWindowOptions()
2020-12-24 01:07:16 +09:00
e.putLog("finished preparing the application window.")
2020-08-01 14:22:34 +09:00
// window layout
2019-06-12 21:58:35 +09:00
l := widgets.NewQBoxLayout(widgets.QBoxLayout__RightToLeft, nil)
l.SetContentsMargins(0, 0, 0, 0)
l.SetSpacing(0)
e.window.SetupContent(l)
2019-05-14 12:56:46 +09:00
2020-08-01 14:22:34 +09:00
// window content
2020-12-04 23:14:06 +09:00
e.widget = widgets.NewQWidget(nil, 0)
2019-10-20 18:13:56 +09:00
e.newSplitter()
2020-12-11 21:59:47 +09:00
e.splitter.InsertWidget(1, e.widget)
2020-08-28 00:54:52 +09:00
l.AddWidget(e.splitter, 1, 0)
e.putLog("window layout done")
2020-12-05 14:36:12 +09:00
e.font = <-fontGenAsync
e.putLog("done calculating the width of the font.")
2020-12-05 14:36:12 +09:00
2020-08-01 14:22:34 +09:00
// neovim workspaces
2019-10-24 17:04:33 +09:00
e.initWorkspaces()
e.putLog("done initialazing workspaces")
2019-10-24 17:04:33 +09:00
2020-10-05 23:02:44 +09:00
e.connectAppSignals()
2020-12-12 01:39:52 +09:00
e.signal.ConnectSidebarSignal(func() {
if e.side != nil {
2020-12-15 00:41:02 +09:00
return
}
2021-02-01 22:30:09 +09:00
e.putLog("create workspace sidebar")
e.side = newWorkspaceSide()
e.side.newScrollArea()
e.side.scrollarea.Hide()
e.side.scrollarea.SetWidget(e.side.widget)
e.splitter.InsertWidget(0, e.side.scrollarea)
side := e.side
2020-12-15 00:41:02 +09:00
if e.config.SideBar.Visible {
side.show()
}
2020-12-12 01:39:52 +09:00
})
// When an application is closed with the Close button
2020-10-05 23:02:44 +09:00
e.window.ConnectCloseEvent(func(event *gui.QCloseEvent) {
e.putLog("The application was closed outside of Neovim's commands, such as the Close button.")
e.cleanup()
e.saveAppWindowState()
if runtime.GOOS == "darwin" {
e.app.DisconnectEvent()
}
2020-10-05 23:02:44 +09:00
event.Accept()
})
2019-06-12 21:58:35 +09:00
2020-08-01 14:22:34 +09:00
// runs goroutine to detect stop events and quit the application
2019-06-12 21:58:35 +09:00
go func() {
2022-03-01 14:30:47 +09:00
ret := <-e.stop
close(e.stop)
e.putLog("The application was quitted with the exit of Neovim.")
2019-06-12 21:58:35 +09:00
if runtime.GOOS == "darwin" {
e.app.DisconnectEvent()
}
e.saveAppWindowState()
2022-03-01 14:30:47 +09:00
// e.app.Quit()
os.Exit(ret)
2019-06-12 21:58:35 +09:00
}()
// launch thread to copy text to the clipboard in darwin
if runtime.GOOS == "darwin" {
if e.config.Editor.Clipboard {
go func() {
for {
select {
case <-e.stop:
return
default:
text := <-e.cbChan
e.app.Clipboard().SetText(*text, gui.QClipboard__Clipboard)
}
}
}()
}
}
e.putLog("done connecting UI siganal")
2020-12-12 01:39:52 +09:00
e.widget.SetFocus2()
e.putLog("focused UI")
2021-08-27 23:17:25 +09:00
e.addDockMenu()
2020-07-12 01:20:22 +09:00
2019-06-12 21:58:35 +09:00
widgets.QApplication_Exec()
}
func (e *Editor) putLog(v ...interface{}) {
2021-01-25 23:24:53 +09:00
if e.opts.Debug == "" {
return
2020-12-04 23:14:06 +09:00
}
log.Println(
fmt.Sprintf("%07.3f", float64(time.Now().UnixNano()/1000-e.startuptime)/1000),
2022-01-13 17:57:38 +09:00
strings.TrimRight(strings.TrimLeft(fmt.Sprintf("%v", v), "["), "]"),
)
2020-12-04 23:14:06 +09:00
}
2021-08-27 23:17:25 +09:00
// addDockMenu add the action menu for app in the Dock.
func (e *Editor) addDockMenu() {
if runtime.GOOS != "darwin" {
return
}
appExecutable := core.QCoreApplication_ApplicationFilePath()
menu := widgets.NewQMenu(nil)
action1 := menu.AddAction("New Instance")
action1.ConnectTriggered(func(checked bool) {
go func() {
cmd := exec.Command(appExecutable)
cmd.Start()
}()
})
action2 := menu.AddAction("New Instance with -u NONE")
action2.ConnectTriggered(func(checked bool) {
go func() {
cmd := exec.Command(appExecutable, "-u", "NONE")
cmd.Start()
}()
})
for key, string := range e.config.Editor.DockmenuActions {
action := menu.AddAction(key)
strSlice := strings.Split(string, " ")
action.ConnectTriggered(func(checked bool) {
go func() {
cmd := exec.Command(appExecutable, strSlice...)
cmd.Start()
}()
})
}
menu.SetAsDockMenu()
}
2020-08-01 14:22:34 +09:00
// setAppDirPath
2020-10-05 23:02:44 +09:00
// Set the current working directory of the application to the HOME directory in darwin, linux.
2020-08-01 14:22:34 +09:00
// If this process is not executed, CWD is set to the root directory, and
// nvim plugins called as descendants of the application will not work due to lack of permission.
// e.g. #122
2020-10-05 23:02:44 +09:00
func (e *Editor) setAppDirPath(home string) {
if runtime.GOOS == "windows" {
return
}
if runtime.GOOS == "darwin" {
if !(e.ppid == 1 && e.macAppArg == "") {
return
}
}
if runtime.GOOS == "linux" {
if e.ppid != 1 {
return
}
}
2020-08-01 14:22:34 +09:00
path := core.QCoreApplication_ApplicationDirPath()
absHome, err := util.ExpandTildeToHomeDirectory(home)
if err == nil {
if path != absHome {
qdir := core.NewQDir2(path)
qdir.SetCurrent(absHome)
}
}
}
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.SetStretchFactor(1, 100)
splitter.SetObjectName("splitter")
2020-08-28 00:54:52 +09:00
e.splitter = splitter
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{}
2019-11-21 01:01:51 +09:00
if e.config.Workspace.RestoreSession {
for i := 0; i <= WORKSPACELEN; i++ {
path := filepath.Join(e.configDir, "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
}
e.sessionExists = true
2019-06-12 21:58:35 +09:00
ws, err := newWorkspace(path)
if err != nil {
break
}
e.workspaces = append(e.workspaces, ws)
ws.widget.SetParent(e.widget)
2018-10-11 21:37:36 +09:00
}
}
if !e.sessionExists {
2018-10-11 21:37:36 +09:00
ws, err := newWorkspace("")
if err != nil {
return
}
e.workspaces = append(e.workspaces, ws)
ws.widget.SetParent(e.widget)
2018-10-11 21:37:36 +09:00
}
2019-06-12 21:58:35 +09:00
}
2018-10-11 21:37:36 +09:00
2020-10-05 23:02:44 +09:00
func (e *Editor) connectAppSignals() {
if e.app == nil {
return
}
2019-06-12 21:58:35 +09:00
if runtime.GOOS != "darwin" {
return
}
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)
2020-10-05 23:02:44 +09:00
if e.ppid != 1 {
2019-06-12 22:14:48 +09:00
return false
2019-06-12 21:58:35 +09:00
}
fileOpenEvent := gui.NewQFileOpenEventFromPointer(event.Pointer())
2020-10-05 23:02:44 +09:00
e.macAppArg = fileOpenEvent.File()
e.loadFileInDarwin()
2018-05-25 01:00:23 +09:00
}
2019-06-12 21:58:35 +09:00
return true
})
2020-10-05 23:02:44 +09:00
}
func (e *Editor) resizeMainWindow() {
cws := e.workspaces[e.active]
windowWidth, windowHeight := cws.updateSize()
if !editor.config.Editor.WindowGeometryBasedOnFontmetrics {
return
}
// quantization of window geometry with font metrics as the smallest unit of change.
geometry := editor.window.Geometry()
width := geometry.Width()
height := geometry.Height()
if !(width == windowWidth && height == windowHeight) {
e.window.Resize2(
windowWidth,
windowHeight,
)
}
}
2020-10-05 23:02:44 +09:00
func (e *Editor) loadFileInDarwin() {
if runtime.GOOS != "darwin" {
return
}
goneovim := e.workspaces[e.active].nvim
isModified := ""
isModified, _ = goneovim.CommandOutput("echo &modified")
if isModified == "1" {
goneovim.Command(fmt.Sprintf(":tabe %s", e.macAppArg))
} else {
goneovim.Command(fmt.Sprintf("%s %s", e.config.Editor.FileOpenCmd, e.macAppArg))
2020-10-05 23:02:44 +09:00
}
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)
image := filepath.Join(e.configDir, "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()
e.putLog("initialize system tray")
2019-07-11 12:18:17 +09:00
}
2020-12-27 21:32:52 +09:00
func (e *Editor) setEnv() {
// For Linux
2019-06-12 21:58:35 +09:00
if runtime.GOOS == "linux" {
// // It was not a necessary process to export the following environment variables.
// exe, _ := os.Executable()
// dir, _ := filepath.Split(exe)
// _ = os.Setenv("LD_LIBRARY_PATH", dir+"lib")
// _ = os.Setenv("QT_PLUGIN_PATH", dir+"plugins")
// _ = os.Setenv("RESOURCE_NAME", "goneovim")
2019-06-12 21:58:35 +09:00
}
// If the OS is MacOS and the application is launched from an .app
2020-12-27 21:32:52 +09:00
if runtime.GOOS == "darwin" && e.ppid == 1 {
2019-12-07 13:19:58 +09:00
shell := os.Getenv("SHELL")
if shell == "" {
shell = os.Getenv("/bin/bash")
}
2020-12-28 18:43:54 +09:00
cmd := exec.Command(shell, "-l", "-c", "env", "-i")
// cmd := exec.Command("printenv")
2019-12-07 13:19:58 +09:00
stdout, err := cmd.StdoutPipe()
if err != nil {
2021-02-01 22:30:09 +09:00
e.putLog(err)
2019-12-07 13:19:58 +09:00
return
}
if err := cmd.Start(); err != nil {
2021-02-01 22:30:09 +09:00
e.putLog(err)
2019-12-07 13:19:58 +09:00
return
}
output, err := ioutil.ReadAll(stdout)
if err != nil {
2021-02-01 22:30:09 +09:00
e.putLog(err)
2019-12-07 13:19:58 +09:00
stdout.Close()
return
}
for _, b := range strings.Split(string(output), "\n") {
splits := strings.SplitN(b, "=", 2)
2019-12-07 13:19:58 +09:00
if len(splits) > 1 {
_ = os.Setenv(splits[0], splits[1])
}
}
}
// For Windows
// https://github.com/equalsraf/neovim-qt/issues/391
if runtime.GOOS == "windows" {
_ = os.Setenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1")
}
2019-06-12 21:58:35 +09:00
}
2021-02-09 22:26:24 +09:00
func (e *Editor) setFont() {
2019-09-15 23:09:46 +09:00
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) {
a := NotifyOptions{}
2018-08-16 19:31:36 +09:00
for _, o := range opt {
o(&a)
2018-08-16 19:31:36 +09:00
}
n := &Notify{
level: level,
period: p,
2018-08-16 19:31:36 +09:00
message: message,
buttons: a.buttons,
2018-08-16 19:31:36 +09:00
}
e.notify <- n
e.signal.NotifySignal()
}
func (e *Editor) popupNotification(level NotifyLevel, p int, message string, opt ...NotifyOptionArg) {
2020-08-10 23:19:00 +09:00
e.updateNotificationPos()
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
c.selectedBg = bg.brend(hexToRGBA(c.e.config.SideBar.AccentColor), 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)
if c.e.config.Editor.WindowSeparatorColor != "" {
c.windowSeparator = hexToRGBA(c.e.config.Editor.WindowSeparatorColor)
} else if c.e.config.Editor.WindowSeparatorTheme == "light" && c.e.config.Editor.WindowSeparatorColor == "" {
if fg.R < 250 && fg.G < 250 && fg.B < 250 {
c.windowSeparator = warpColor(fg, 10)
} else {
c.windowSeparator = warpColor(fg, -10)
}
} else if c.e.config.Editor.WindowSeparatorTheme == "dark" && c.e.config.Editor.WindowSeparatorColor == "" {
if bg.R > 10 && bg.G > 10 && bg.B > 10 {
c.windowSeparator = warpColor(bg, 10)
} else {
c.windowSeparator = warpColor(bg, -10)
}
}
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() {
e.putLog("start updating UI color")
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" {
2020-12-12 01:39:52 +09:00
e.window.TitleBar.Hide()
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))
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 {
2020-12-12 01:39:52 +09:00
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
}
2020-08-10 23:19:00 +09:00
// e.window.SetWindowOpacity(1.0)
e.putLog("finished updating UI color")
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 < 40 {
width = 40
}
height, err = strconv.Atoi(strings.SplitN(s, "x", 2)[1])
if err != nil || height < 30 {
height = 30
}
return width, height
}
func (e *Editor) restoreWindow() (isRestoreGeometry, isRestoreState bool) {
if !e.config.Editor.RestoreWindowGeometry {
return
}
settings := core.NewQSettings("neovim", "goneovim", nil)
geometry := settings.Value("geometry", core.NewQVariant13(core.NewQByteArray()))
state := settings.Value("windowState", core.NewQVariant13(core.NewQByteArray()))
geometryBA := geometry.ToByteArray()
stateBA := state.ToByteArray()
if geometryBA.Length() != 0 {
e.window.RestoreGeometry(geometryBA)
isRestoreGeometry = true
}
if stateBA.Length() != 0 {
e.window.RestoreState(stateBA, 0)
isRestoreState = true
}
return
}
2018-12-29 15:40:57 +09:00
func (e *Editor) setWindowOptions() {
2020-12-12 01:39:52 +09:00
e.window.SetupTitle("Neovim")
e.window.SetMinimumSize2(40, 30)
2020-12-12 01:39:52 +09:00
e.initSpecialKeys()
2018-12-29 15:40:57 +09:00
e.window.ConnectKeyPressEvent(e.keyPress)
e.window.ConnectKeyReleaseEvent(e.keyRelease)
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)
}
2020-08-12 00:02:45 +09:00
func (e *Editor) showWindow() {
e.width = e.config.Editor.Width
e.height = e.config.Editor.Height
isRestoreGeometry, isRestoreState := e.restoreWindow()
// If command line options are given, they take priority.
if e.opts.Fullscreen || e.opts.Maximized {
if e.opts.Fullscreen {
e.window.WindowFullScreen()
} else if e.opts.Maximized {
e.window.WindowMaximize()
}
} else {
if !isRestoreGeometry {
e.window.Resize2(e.width, e.height)
}
if !isRestoreState {
if e.config.Editor.StartFullscreen {
e.window.WindowFullScreen()
} else if e.config.Editor.StartMaximizedWindow {
e.window.WindowMaximize()
}
}
}
2022-04-19 11:49:35 +09:00
if e.opts.Ssh == "" || e.opts.Wsl == nil {
e.window.Show()
}
2020-08-12 00:02:45 +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() {
2020-08-23 14:59:22 +09:00
var yankedText string
yankedText, _ = e.workspaces[e.active].nvim.CommandOutput("echo getreg()")
if yankedText != "" {
if runtime.GOOS != "darwin" {
clipb.WriteAll(yankedText)
} else {
e.cbChan <- &yankedText
}
2020-08-23 14:59:22 +09:00
}
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() {
2021-05-13 23:52:40 +09:00
if len(e.workspaces) == WORKSPACELEN {
return
}
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
}
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.side == nil {
return
}
2018-01-05 09:13:50 +00:00
for i, ws := range e.workspaces {
if i == e.active {
2021-05-05 10:31:34 +09:00
ws.hide()
2018-01-05 09:13:50 +00:00
ws.show()
} else {
ws.hide()
}
}
for i := 0; i < len(e.side.items) && i < len(e.workspaces); i++ {
2021-05-08 01:58:26 +09:00
if e.side.items[i] == nil {
continue
}
2021-05-08 08:42:19 +09:00
if e.side.items[i].label.Text() == "" {
e.workspaces[i].setCwd(e.workspaces[i].cwdlabel)
}
e.side.items[i].setSideItemLabel(i)
2021-05-05 10:31:34 +09:00
// e.side.items[i].setText(e.workspaces[i].cwdlabel)
e.side.items[i].show()
2018-01-08 10:23:16 +00:00
}
for i := len(e.workspaces); i < len(e.side.items); i++ {
2021-05-08 01:58:26 +09:00
if e.side.items[i] == nil {
continue
}
e.side.items[i].hide()
2018-01-08 10:23:16 +00:00
}
2018-01-05 09:13:50 +00:00
}
func (e *Editor) keyRelease(event *gui.QKeyEvent) {
if !e.isKeyAutoRepeating {
return
}
2021-12-28 02:18:15 +09:00
if editor.config.Editor.SmoothScroll {
ws := e.workspaces[e.active]
win, ok := ws.screen.getWindow(ws.cursor.gridid)
if !ok {
return
}
if win.scrollPixels2 != 0 {
return
}
win.grabScreenSnapshot(win.Rect())
2021-12-28 02:18:15 +09:00
}
e.isKeyAutoRepeating = false
}
2018-01-05 08:07:29 +00:00
func (e *Editor) keyPress(event *gui.QKeyEvent) {
ws := e.workspaces[e.active]
2021-12-28 02:18:15 +09:00
if !e.isKeyAutoRepeating {
ws.getSnapshot()
}
input := e.convertKey(event)
if event.IsAutoRepeat() {
e.isKeyAutoRepeating = true
}
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
2021-07-25 22:35:17 +09:00
func keyToText(key int, mod core.Qt__KeyboardModifier) string {
text := string(rune(key))
if !(mod&core.Qt__ShiftModifier > 0) {
text = strings.ToLower(text)
}
return text
}
2022-04-02 14:31:56 +09:00
// controlModifier is
func controlModifier() (controlModifier core.Qt__KeyboardModifier) {
if runtime.GOOS == "windows" {
controlModifier = core.Qt__ControlModifier
}
if runtime.GOOS == "linux" {
controlModifier = core.Qt__ControlModifier
}
2021-07-25 22:35:17 +09:00
if runtime.GOOS == "darwin" {
controlModifier = core.Qt__MetaModifier
}
2022-04-02 14:31:56 +09:00
return
2021-07-25 22:35:17 +09:00
}
2022-04-02 14:31:56 +09:00
// cmdModifier is
func cmdModifier() (cmdModifier core.Qt__KeyboardModifier) {
2021-07-25 22:35:17 +09:00
if runtime.GOOS == "windows" {
cmdModifier = core.Qt__NoModifier
}
if runtime.GOOS == "linux" {
cmdModifier = core.Qt__MetaModifier
}
2022-04-02 14:31:56 +09:00
if runtime.GOOS == "darwin" {
cmdModifier = core.Qt__ControlModifier
}
2021-07-25 22:35:17 +09:00
2022-04-02 14:31:56 +09:00
return
2021-07-25 22:35:17 +09:00
}
2021-07-30 12:01:15 +09:00
func isAsciiCharRequiringAlt(key int, mod core.Qt__KeyboardModifier, c rune) bool {
// Ignore all key events where Alt is not pressed
if !(mod&core.Qt__AltModifier > 0) {
return false
}
// These low-ascii characters may require AltModifier on MacOS
if (c == '[' && key != int(core.Qt__Key_BracketLeft)) ||
(c == ']' && key != int(core.Qt__Key_BracketRight)) ||
(c == '{' && key != int(core.Qt__Key_BraceLeft)) ||
(c == '}' && key != int(core.Qt__Key_BraceRight)) ||
(c == '|' && key != int(core.Qt__Key_Bar)) ||
(c == '~' && key != int(core.Qt__Key_AsciiTilde)) ||
(c == '@' && key != int(core.Qt__Key_At)) {
return true
}
return false
}
func (e *Editor) convertKey(event *gui.QKeyEvent) string {
text := event.Text()
key := event.Key()
mod := event.Modifiers()
2022-04-02 14:31:56 +09:00
if e.opts.Debug != "" {
e.putLog("key input:", fmt.Sprintf("%s, %d, %v", text, key, mod))
}
2020-05-30 20:39:21 +09:00
// this is macmeta alternatively
2021-08-29 16:01:00 +09:00
if e.config.Editor.Macmeta {
if mod&core.Qt__AltModifier > 0 && mod&core.Qt__ShiftModifier > 0 {
text = string(rune(key))
} else if mod&core.Qt__AltModifier > 0 && !(mod&core.Qt__ShiftModifier > 0) {
text = strings.ToLower(string(rune(key)))
2020-05-30 20:39:21 +09:00
}
}
2018-01-05 08:07:29 +00:00
if mod&core.Qt__KeypadModifier > 0 {
switch core.Qt__Key(key) {
case core.Qt__Key_Home:
2022-04-02 14:31:56 +09:00
return fmt.Sprintf("<%skHome>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_End:
2022-04-02 14:31:56 +09:00
return fmt.Sprintf("<%skEnd>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_PageUp:
2022-04-02 14:31:56 +09:00
return fmt.Sprintf("<%skPageUp>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_PageDown:
2022-04-02 14:31:56 +09:00
return fmt.Sprintf("<%skPageDown>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_Plus:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skPlus>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_Minus:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skMinus>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_multiply:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skMultiply>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_division:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skDivide>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_Enter:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skEnter>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
case core.Qt__Key_Period:
2020-11-10 23:21:20 +09:00
return fmt.Sprintf("<%skPoint>", e.modPrefix(mod))
case core.Qt__Key_0:
return fmt.Sprintf("<%sk0>", e.modPrefix(mod))
case core.Qt__Key_1:
return fmt.Sprintf("<%sk1>", e.modPrefix(mod))
case core.Qt__Key_2:
return fmt.Sprintf("<%sk2>", e.modPrefix(mod))
case core.Qt__Key_3:
return fmt.Sprintf("<%sk3>", e.modPrefix(mod))
case core.Qt__Key_4:
return fmt.Sprintf("<%sk4>", e.modPrefix(mod))
case core.Qt__Key_5:
return fmt.Sprintf("<%sk5>", e.modPrefix(mod))
case core.Qt__Key_6:
return fmt.Sprintf("<%sk6>", e.modPrefix(mod))
case core.Qt__Key_7:
return fmt.Sprintf("<%sk7>", e.modPrefix(mod))
case core.Qt__Key_8:
return fmt.Sprintf("<%sk8>", e.modPrefix(mod))
case core.Qt__Key_9:
return fmt.Sprintf("<%sk9>", e.modPrefix(mod))
2018-01-05 08:07:29 +00:00
}
}
2017-06-16 08:43:05 +01:00
2021-07-25 22:35:17 +09:00
specialKey, ok := e.specialKeys[core.Qt__Key(key)]
if ok {
if key == int(core.Qt__Key_Space) || key == int(core.Qt__Key_Backspace) {
mod &= ^core.Qt__ShiftModifier
}
return fmt.Sprintf("<%s%s>", e.modPrefix(mod), specialKey)
}
2018-01-05 08:07:29 +00:00
if text == "<" {
2020-03-24 23:40:45 +09:00
modNoShift := mod & ^core.Qt__ShiftModifier
return fmt.Sprintf("<%s%s>", e.modPrefix(modNoShift), "lt")
2017-06-06 02:42:11 +01:00
}
2021-07-25 22:35:17 +09:00
isCaretKey := key == int(core.Qt__Key_6) || key == int(core.Qt__Key_AsciiCircum)
// Normalize modifiers, CTRL+^ always sends as <C-^>
2021-07-30 12:01:15 +09:00
if isCaretKey && (mod&controlModifier() > 0) {
2021-07-25 22:35:17 +09:00
modNoShiftMeta := mod & ^core.Qt__ShiftModifier & ^cmdModifier()
return fmt.Sprintf("<%s%s>", e.modPrefix(modNoShiftMeta), "^")
2018-01-05 08:07:29 +00:00
}
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
2021-07-25 22:35:17 +09:00
rtext := []rune(text)
isGraphic := false
if len(rtext) > 0 {
isGraphic = unicode.IsGraphic(rtext[0])
}
if text == "" || !isGraphic {
2020-11-28 09:21:42 +09:00
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
}
2021-07-25 22:35:17 +09:00
// Ignore special keys
if key == int(core.Qt__Key_VolumeDown) ||
2021-07-30 12:01:15 +09:00
key == int(core.Qt__Key_VolumeMute) ||
key == int(core.Qt__Key_VolumeUp) {
2021-07-25 22:35:17 +09:00
return ""
}
2021-07-30 12:01:15 +09:00
2021-07-25 22:35:17 +09:00
text = keyToText(key, mod)
}
2021-07-30 12:01:15 +09:00
c := text
if c == "" {
return ""
2018-01-05 08:07:29 +00:00
}
2020-03-22 22:51:13 +09:00
char := []rune(c)[0]
// char := core.NewQChar11(c)
2020-03-22 22:51:13 +09:00
// Remove SHIFT
if (int(char) >= 0x80 || unicode.IsPrint(char)) && !(mod&controlModifier() > 0) && !(mod&cmdModifier() > 0) {
mod &= ^core.Qt__ShiftModifier
2019-10-31 23:06:47 +09:00
}
// if (char.Unicode() >= 0x80 || char.IsPrint()) && !(mod&controlModifier() > 0) && !(mod&cmdModifier() > 0) {
// mod &= ^core.Qt__ShiftModifier
// }
2019-10-31 23:06:47 +09:00
2020-03-22 22:51:13 +09:00
// Remove CTRL
if int(char) < 0x20 {
2021-07-25 22:35:17 +09:00
text = keyToText(key, mod)
2018-01-05 08:07:29 +00:00
}
// if char.Unicode() < 0x20 {
// text = keyToText(key, mod)
// }
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 int(char) >= 0x80 && unicode.IsPrint(char) {
mod &= ^core.Qt__AltModifier
2020-03-22 22:51:13 +09:00
}
// if char.Unicode() >= 0x80 && char.IsPrint() {
// mod &= ^core.Qt__AltModifier
// }
2021-07-30 12:01:15 +09:00
// Some locales require Alt for basic low-ascii characters,
// remove AltModifer. Ex) German layouts use Alt for "{".
if isAsciiCharRequiringAlt(key, mod, []rune(c)[0]) {
mod &= ^core.Qt__AltModifier
}
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" {
2021-07-25 22:35:17 +09:00
if mod&controlModifier() > 0 && !(mod&core.Qt__AltModifier > 0) {
prefix += "C-"
}
if mod&core.Qt__ShiftModifier > 0 {
prefix += "S-"
}
2021-07-25 22:35:17 +09:00
if mod&core.Qt__AltModifier > 0 && !(mod&controlModifier() > 0) {
prefix += e.prefixToMapMetaKey
}
} else {
2021-07-25 22:35:17 +09:00
if mod&cmdModifier() > 0 {
2018-01-05 08:07:29 +00:00
prefix += "D-"
2017-07-03 07:14:29 +01:00
}
2021-07-25 22:35:17 +09:00
if mod&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-11-28 09:21:42 +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-11-28 09:21:42 +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.keyControl = core.Qt__Key_Meta
e.keyCmd = core.Qt__Key_Control
} else if runtime.GOOS == "windows" {
e.keyControl = core.Qt__Key_Control
e.keyCmd = (core.Qt__Key)(0)
2018-01-05 08:07:29 +00:00
} else {
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
2022-03-01 14:30:47 +09:00
func (e *Editor) close(exitcode int) {
2018-01-08 10:23:16 +00:00
e.stopOnce.Do(func() {
2022-03-01 14:30:47 +09:00
e.stop <- exitcode
2018-01-08 10:23:16 +00:00
})
}
func (e *Editor) saveAppWindowState() {
settings := core.NewQSettings("neovim", "goneovim", nil)
settings.SetValue("geometry", core.NewQVariant13(e.window.SaveGeometry()))
settings.SetValue("windowState", core.NewQVariant13(e.window.SaveState(0)))
}
2018-01-08 10:23:16 +00:00
func (e *Editor) cleanup() {
sessions := filepath.Join(e.configDir, "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")
}
}