在 EverEdit 下配置 Go 语言编译环境

关键字

EverEdit, Golang, Compiler, IDE, EverEdit Mode, EverEdit Templete, EverEdit Theme, EverEdit Syntax, EverEdit Output Windows, EverEdit Menu, EverEdit Script

概述

EverEdit 是 Windows 下最优秀的文本编辑器之一,它自带 mode 的概念,可扩展性远胜于同类编辑器,我们可以将它配置成为任何编程语言的编码环境,它的可扩展体现在以下几个方面:

  • 菜单的自定义
  • 模板的自定义
  • 命令的自定义及配置多样性
  • 语法高亮的定义
  • 脚本连接系统功能的能力

Go 语言是 Google 公司为解决高并发所创造的编译型语言,说到它,除了它的发明者都是牛人,其中之一是 Ken Thomspson,Unix 的发明者之一。

这篇文章将简要的叙述,如何把 EverEdit 配置为 Go 语言的编译环境。

步骤

让我们从 Emacs 说起,很多活在 Emacs 中的人,大多已经不再需要每次启动时按下 M-x 输入 org-mode 了,因为他们已经把 Emacs org-mode 作为了默认模式。

这里的 mode 可以理解为一种环境,这个优秀的概念源自 Emacs,EverEdit 中也完全实现了,并且相应的,我为它定制了 todo mode,也叫 taskpaper mode,可以很方便的以树状管理项目和任务,留待后文叙述。一种 mode 通常包括:

  • 进入一种布局
  • 对一种格式的文本的高亮显示
  • 在菜单中插入编辑这种格式文本所需要的工具

上述三个方面,EverEdit 都可以完成的很好,且比同类的编辑器要快。甚至,当需要为一种新语言定制 mode 时,EverEdit 无疑比 Emacs 和 VSCode 都要快。

拿 Go 语言为例子,为方便表示,后文我们假设 EverEdit 的安装根目录是 $EVEREDIT_ROOT

模板

首先,我们需要一个 Go 语言模板。这里我们用 Google 出版的《Go 程序设计语言》一书第一页的 Hello World 程序为例:

package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界!")
}

我们将这个文件保存为 $EVEREDIT_ROOT/template/template.go,然后点击菜单【文件】【新建】【配置模板】,选中 Go,配型选择 Go,模板中输入 template.go。经过这个配置后,就可以在新建时按我们配置好的模板新建了。

是不是很简单?你会发现为 EverEdit 配置模板,整体时间不超过 1 分钟,而以后新建时,能节省无数个 1 分钟。

语法着色

当我们从模板新建文件,并以扩展名 .go 保存,输入以上代码的过程中会注意的,EverEdit 已经内置为 Go 语言实现了高亮,这也是配置操作过程中,存在类型为 Go 语法着色的原因,这个贡献来自 Morler,它的奥妙在于 EverEdit 安装目录下的 /syntax/go.mac,这是一种类 vbscript 语法的定义文件。

'*******************************************************************************
' EverEdit Syntax File
' Language:    Google Go
' Maintainer:  www.everedit.net  Morler
' History:
'   2013/04/04 First Version
'   2013/05/14 Updated
'   2015/10/15 Added outline support (Thanks ldbug)
'*******************************************************************************
Include( ".\const.mac" )

Set go=CreateParser()

Set rComment1=go.CreateRegion(COLOR_COMMENT1, "+//+", "$", False )
Set rComment2=go.CreateRegion(COLOR_COMMENT2, "+/*+", "+*/+", False )

Set rString1=go.CreateStringRegion( COLOR_STRING1, "'", "\", False )
Set rString2=go.CreateStringRegion( COLOR_STRING2, """", "\", False )

Set rString3=go.CreateStringRegion( COLOR_STRING1, "", "`", False )

'Reserved words
Set iWord1=go.CreateWord(COLOR_WORD1, "break case chan const continue default defer delete else fallthrough for func go goto if import interface map package range return select struct switch type var", True)

'Functions
Set iWord2=go.CreateWord(COLOR_WORD2, "append cap close closed complex copy imag len make new panic print println real recover main", True)

'Types
Set iWord3=go.CreateWord(COLOR_WORD3, "bool byte complex complex64 complex128 float float32 float64 int int8 int16 int32 int64 string uint uint8 uint16 uint32 uint64 uintptr _", True)

'Constants & Zero value
Set iWord4=go.CreateWord(COLOR_OPERATOR, "true false iota nil", True)

'operators
Set iOperator=go.CreateItem(COLOR_OPERATOR, "[\{\}\(\)\+\-\*\\=%&\^!~\|<>?\.,:;@\$\[\]]",False )


go.AddRegion( rComment1 )
go.AddRegion( rComment2 )
go.AddRegion( rString1 )
go.AddRegion( rString2 )
go.AddRegion( rString3 )
go.AddWord( iWord1 )
go.AddWord( iWord2 )
go.AddWord( iWord3 )
go.AddWord( iWord4 )
go.AddItem( iOperator )

'number
go.AddItem( go.CreateItem(COLOR_NUMBER, "(?<!\w)[+-]?([1-9][0-9]*\.?[0-9]*[e]?[-]?[0-9]*\.?[0-9]*|0([0-7]+|x[0-9A-Fa-f]+)|(?<!-)0(?!\.)|0\.[0-9]*[e]?[-]?[1-9][0-9]*)(?!\w)", False) )

go.IndentText "\{\s*$", False,  "}\s*$", False
go.FoldText "\{", False, "\}", False
go.SetPairs( "[]''""""{}()" )
go.CommentLine( "//" )
go.CommentBlock "/*", "*/"

借助上述文件清晰定义规则的解析,EverEdit 会识别扩展名为 .go 的文件以你选择的主题(Theme)渲染。Syntax 和 Theme 相关话题,我们将在 EverEdit 的介绍文章中叙述。

编译集成

自定义外部工具

集成编译,我们可以简单的以自定义外部工具的方式来完成。这里我们假设你已经在 Windows 下配置好 Go 语言环境。这样,我们就可以在菜单【工具】【设置】【外部工具】中来定义 Go build 命令,配置方法如下:

标题:08. Go Build
命令:go build
参数:$(FilePath)
初始目录:$(FileDir)
动作模式:捕获输出(隐藏窗口)

但更高级的,我们可以用 mode 脚本来实现。下面我们先自定义 mode 的菜单。

mode 自定义菜单

通常我喜欢将 EverEdit 的安装目录放入快捷目录中,这样我们可以很方便的在 EverEdit 中定义 EverEdit 的配置,首先,我们先创建一个 $EVEREDIT_ROOT/mode/Go.esm 文件,内容如下:

[Menu]
Title=GO Mode
[Menu0]
Key=C+B
Command0=3,Go build,${AppPath}\mode\go\build.ejs
[Menu1]
Key=CS+R
Command0=3,Go run,${AppPath}\mode\go\run.ejs
[Menu2]
Key=CS+C
Command0=3,Go clean,${AppPath}\mode\go\clean.ejs
[Menu3]
Command0=3,Go env,${AppPath}\mode\go\env.ejs
[Menu4]
Command0=3,Go fmt,${AppPath}\mode\go\fmt.ejs
[Menu5]
Command0=3,Go version,${AppPath}\mode\go\version.ejs
[Menu6]

上述即定义了一个在打开 .go 文件时,帮助菜单之前出现的菜单。(EverEdit 3.x 版本,这个菜单是帮助菜单后面),其中包含 build、run、clean、env、fmt、version 等 go 语言常用命令。

再创建一个文件夹

$EVEREDIT_ROOT/mode/go/

并加入上述命令的的入口文件。

build.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('build');

run.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('run');

clean.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('clean');

env.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('env');

fmt.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('fmt');

version.ejs

Include(App.AppPath + "\\mode\\go\\cmd.ejs");
cmd('version');

现在我们已经定义好菜单的入口和执行文件,最后是主文件

cmd.ejs

Include(App.AppPath + "\\mode\\kaffa\\common.js");

function cmd(cmd) {
    var doc = App.ActiveDoc;
    var docPath = doc.PathName;
    if (doc.PathName.length == 0) {
        ShowMsgBox('You should save current file with extension .go!', 'Message from EverEdit', 0);
        doc = null;
        return;
    }
    SendCommandEx("cm_file_save");

    var arr = docPath.split('\\');
    var filename = arr.pop();
    var dir = arr.join('\\');
    var encoding = getEncodingName(doc.Encoding);    
    var cmdStr = '';
    if (cmd == 'build') {
        cmdStr = 'go build ' + docPath;
    }
    else if (cmd == 'run') {
        cmdStr = 'go run ' + docPath;
    }
    else if (cmd == 'version') {
        cmdStr = 'go version';
    }
    else if (cmd == 'env') {
        cmdStr = 'go env';
    }
    else if (cmd == 'fmt') {
        cmdStr = 'go fmt ' + docPath;
    }
    else if (cmd == 'clean') {
        cmdStr = 'go clean';
    }
    var outMsg = App.GetResultFromExe(cmdStr, dir, doc.Encoding)

    var out = App.OutputWindow;
    out.Clear();
    out.Show();
    out.OutputText(outMsg);
    out.SetJumpPattern("^(.*?):(\d+):", 1, 2, 0);
    doc = null;
}

大功告成!关闭 EverEdit 再打开。

此时,当我们打开任意一个 .go 文件时,在帮助菜单之前即会出现 Go Mode 菜单,下拉后含有上述六个命令,前三个带有快捷键。

验证

现在,我们从模板新建一个 .go 文件,存为 HelloWorld.go,既可执行 Go Build 将之编译为 .exe 文件了。

我们继续测试,go fmt 命令用来格式化 go 语言文件,我们会发现 go fmt 没有重新加载格式化后的文件,这可以通过简单修改 EverEdit 的脚本 cmd.ejs 来实现文件重新加载。

// 前略...
    else if (cmd == 'fmt') {
        SendCommandEx("cm_file_close");
        cmdStr = 'go fmt ' + docPath;
    }
    else if (cmd == 'clean') {
        cmdStr = 'go clean';
    }
    var outMsg = App.GetResultFromExe(cmdStr, dir, doc.Encoding)

    if (cmd == 'fmt') {
        App.OpenDoc(docPath);
    }
// 后略...

这里我们在命令执行前运行了 SendCommandEx(“cm_file_close”); 来关闭文件,在命令执行后,运行了 App.OpenDoc(docPath); 再次打开。经测试,整个过程一闪而过,这也是受益于 EverEdit 的迅捷和小巧。

菜单增强

接下来,除了运行命令,还可以在菜单中加入外部链接跳转,我们编辑 Go.esm 文件,在其中加入 go 语言常用的学习网址,整体如下:

[Menu]
Title=GO Mode
[Menu0]
Key=C+B
Command0=3,Go build,${AppPath}\mode\go\build.ejs
[Menu1]
Key=CS+R
Command0=3,Go run,${AppPath}\mode\go\run.ejs
[Menu2]
Key=CS+C
Command0=3,Go clean,${AppPath}\mode\go\clean.ejs
[Menu3]
Command0=3,Go env,${AppPath}\mode\go\env.ejs
[Menu4]
Command0=3,Go fmt,${AppPath}\mode\go\fmt.ejs
[Menu5]
Command0=3,Go version,${AppPath}\mode\go\version.ejs
[Menu6]
SEP=Y
[Menu7]
Command0=2,Go Official Website,https://golang.org/
[Menu8]
Command0=2,Go Documentation,https://golang.org/doc/
[Menu9]
Command0=2,Go Packages,https://golang.org/pkg/
[Menu10]
Command0=2,The Go Project,https://golang.org/project/
[Menu11]
Command0=2,A Tour of Go,https://tour.golang.org
[Menu12]
Command0=2,The Go Playground,https://play.golang.org/
[Menu13]
Command0=2,Go source code,https://github.com/golang/go/

至此,我们就完成了 Go mode 的常规配置,整体时间不超过 30 分钟。本文所涉及的代码,笔者已经上传至 Github,需要的读者可移步下载,其中还加入了 Go.esm.2052 中文菜单文件。

总结

EverEdit 就是这样一款可定义性超高的文本编辑器,本文主要讲述了 templete、mode,涉及 Theme、Syntax、Output Windows、Menu、Script,其实还可以增加 Snippet 以加速语法的支持。当然,还有什么更好的点子留待读者 fork 我的 EverEdit Go Mode,或留言反馈噢。

发表评论

电子邮件地址不会被公开。 必填项已用*标注