想法验证:超轻量级全功能纯文本界面 REPL 类语言 IDE: Vim+Tmux+Slimv

想法验证:超轻量级全功能纯文本界面 REPL 类语言 IDE: Vim+Tmux+Slimv

前言

以前写过一篇文章超轻量级纯文本界面 REPL 类语言 IDE, 介绍了在纯粹文本界面下如何用 Vim + Tmux + vim-slime 搭建一个超轻量级的 REPL 类语言开发环境, 配置步骤很简单, 初学者使用起来也很容易上手, 不过用过几回后发现缺憾: 这个开发环境是否是太简陋了点? 也就是比语言自带的 REPL 稍微多了个编辑区的功能, 尤为是使用过 Emacs + Slime 环境的朋友, 多么但愿能在 vi 下用到相似的功能啊!vim

好消息是, 如今 slimv 出现了--(其实它早就出现了,只不过刚刚进入本文做者视野), 它整合了 slime 的大多数功能, 能够用于 vim 环境. 不过初步阅读文档后发现, 帮助文档里介绍的 Linux 环境下的例子都要用到 XWindows 下的 XTerm 或者 KDE 下的 konsole, 这有点背离咱们但愿使用纯文本界面的初衷, 毕竟咱们的目标是打造一款在流畅运行在树莓派上的超轻量级开发环境, 并不但愿启动笨重庞大的视窗系统来浪费资源.sass

怎么办? 先进行理论分析, 看看 slimv 的原理, 它其实跟 Emaca 下的 slime 同样, 使用 XTerm 的目的是为了启动一个 swank 服务端, 可是 swank 服务端是不须要视窗系统的, 能够直接在纯文本界面下用脚原本启动, 只要保持 slimvswank 版本一致, 端口号使用 slimv 默认值, 那么咱们在纯文本界面下启动的 swank 服务端照样能够为 slimv 提供链接服务. 并且, Emacs + slime + Common Lisp 是能够运行于纯文本界面的, 说明从理论上讲, slimv 也应该具有这个能力.网络

试验1: 纯手工启动 swank.lisp 并链接

先试验一下, 由于 slimv 中服务端的程序是这个 ~/.vim/bundle/slimv/slime/start-swank.lisp 因此咱们能够用任意一个 Common Lisp 实现来执行这个脚本, 这里咱们先试试 CLISP, 命令为:app

clisp -i ~/.vim/bundle/slimv/slime/start-swank.lisp

刷过一堆信息, 最后显示:ide

;; Swank started at port: 4005.

很好,说明咱们经过命令行成功地启动了 swank 服务端函数

这个服务端口能够经过 slimv 或者 telnet 登陆上去, 先说说 telnet 怎么连, 另外开一个终端窗口, 输入学习

telnet 127.0.0.1 4005

就会显示链接成功:测试

Air:slime admin$ telnet 127.0.0.1 4005
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

而后第一个启动 CLISP 的终端窗口就会出现一个 REPL 提示符 CL-USER, 变为以下界面:ui

;; Swank started at port: 4005.
CL-USER>

这里其实就是通过 swank 包装的 REPL 接口, 是能够直接输入表达式求值的lua

CL-USER> (+ 12 34)
(+ 12 34)
46
CL-USER>

好玩吧, :)

好了, 言归正传, 继续咱们的试验.

试验2: 试验在 tmux 不一样的窗口启动 swank

slimv 的文档中, 默认使用了 XTerm 来启动 swank, 可是通过上面的理论分析和动手试验, 咱们清楚地了解到 swank 服务端并不须要一个图形界面下的程序来启动, 那么咱们但愿把 swank 服务端启动在一个 tmux 的窗口中, 这样咱们使用 vim + tmux 的组合时能够很方便地经过快捷键来切换, 固然, 也能够启动在同一个 tmux 窗口的不一样面板内, 可是鉴于咱们屏幕面积有限, 并且通常状况下不须要太多关注这个 swank 服务端的状态, 因此仍是另外启动一个新窗口好了.

这里由于以前对 tmux 主要是使用一些快捷键, 具体经过脚本如何调用的知识基本没查过, 因此稍微花了点时间去研究, 最终经过网络学习到了如何在 tmux 的窗口里启动程序, 其实就是一句脚本的正确格式,

tmux new-window -d -n REPL9 "clisp -i ~/.vim/bundle/slimv/slime/start-swank.lisp"

这行命令告诉 tmux 新建一个窗口(参数 new-window), 后台运行(参数 -d), 名字叫REPL9(参数 -n REPL9), 而后在这个窗口内执行双引号里的命令(参数 "clisp -i ~/.vim/bundle/slimv/slime/start-swank.lisp")

很好, 在显示一大堆信息后 swank 服务端成功启动了, 执行结果

;; Swank started at port: 4005.

那咱们试着从 vim 中用 slimv 链接一下, 用 vim 打开一个测试用的 test.lisp 文件, 进入命令状态, 按下快捷键 逗号 小写英文字母c

,c

因而在 vim 的编辑窗口上方新开了一个 REPL 窗口, 显示以下:

24 CLISP 2.49 (2010-07-07) (built on air.local [192.168.0.2])  Port: 4005  Pid: 68955
 25 ; SWANK 2014-10-10
 26 CL-USER>

再去看看 swank 服务端, 显示以下:

;; Swank started at port: 4005.
CL-USER>
;;  Loading file /Users/admin/.vim/bundle/slimv/slime/contrib/swank-asdf.lisp ...
;;   Loading file /Users/admin/.slime/fasl/2014-10-10/clisp-2.49-unix-unknown/contrib/swank-repl.fas ...
WARNING: The generic function #<STANDARD-GENERIC-FUNCTION THREAD-FOR-EVALUATION> is being modified, but has already been called.
WARNING: Replacing method #<STANDARD-METHOD (#<STRUCTURE-CLASS MULTITHREADED-CONNECTION> (EQL :FIND-EXISTING))> in
         #<STANDARD-GENERIC-FUNCTION THREAD-FOR-EVALUATION>
;;   Loaded file /Users/admin/.slime/fasl/2014-10-10/clisp-2.49-unix-unknown/contrib/swank-repl.fas

很显然, 链接成功了! 试着在 REPL 区对表达式求值:

注意, 由于 vim 区分命令模式和编辑模式, 而咱们的 REPL 区其实就是一个 vim 编辑缓冲区(相似于 Emacs 下的 buffer 的概念), 所以, 若是咱们想要在 REPL 区输入什么表达式, 须要先切换到插入模式(按 i ), 而后再输入要求值的表达式,显示以下:

26 CL-USER> (+ 123 345)
 27 468
 28 CL-USER>

很好, 成功了,很是漂亮, 先切换回命令状态(快捷键 Esc), 再切换回代码编辑区(C-w w), 试试看能不能把代码编辑区的代码片断经过快捷键发送到 REPL 区求值, 把光标挪到一个表达式上, 而后按下快捷键: 逗号 小写英文字母e (,e), 很好, 发送过去了,求值成功了!

28 CL-USER> (print "hh")
 29 "hh"
 30 CL-USER>
REPL   -----------------------                                                                                                                                        
  1 (+ 1 2)
  2
  3 (format t "hello")
  4
  5 (print "hh")
  6
  7 (make-hash-table)
  8
  9 (defun hello ()
 10   (print "hello,world")
 11   )

上半部分是 REPL 区,下半部分是代码编辑区

再试试对函数定义的求值, 快捷键 逗号 小写英文字母d(,d), 继续成功,以下:

30 CL-USER> (defun hello ()
 31   (print "hello,world")
 32   )
 33 HELLO
 34 CL-USER>
REPL   -------------------------                                                                                                                                        
  1 (+ 1 2)
  2
  3 (format t "hello")
  4
  5 (print "hh")
  6
  7 (make-hash-table)
  8 (defun hello ()
  9   (print "hello,world")
 10   )

slimv 支持的 slime 函数以及默认快捷键

slimv 号称是世界上对 slime 函数支持最全面的 vim 实现, 没有之一, 那么咱们看看它究竟支持哪些 slime 的函数:

注意: slimv 默认设置 vim<leader> 键为逗号(,), 因此你的 .vimrc 中就不要对 <leader> 另外定义了.

----                                                    *slimv-keyboard*
The default keybindings (|g:slimv_keybindings|=1) and another easy to remember
built-in keybinding set (|g:slimv_keybindings|=2) for Slimv are the following.
Please note that the leading ',' key below refers to <Leader>, which is set
by Slimv to ',' by default (see |g:slimv_leader|).

In the graphical menu the currently active keyboard shortcuts are displayed
beside the menu item names, so one can refer to the GUI menu as a quick
reference for the keymappings.

Vim defines timeout values for mapped key sequences. If you find that Vim does
not allow you enough time between pressing ',' and the last key(s) of the
sequence, then you may want to fine tune these Vim options:
|timeout|, |ttimeout|, |timeoutlen|, |ttimeoutlen|.

    Set#1   Set#2    Command
    ---------------------------------------------------
    ,,      ,,       Slimv Menu
    Edit commands (Insert mode):
    <C-X>0           Close Form
    <Tab>            Complete Symbol
    <Space>          Function Arglist
    Edit commands (Normal mode):
    ,)      ,tc      Close Form
    ,(      ,(t      Paredit Toggle
    Evaluation commands:
["x],d  ["x],ed      Eval Defun (current top level form) [put in register x]
["x],e  ["x],ee      Eval Current Expression (current subform) [put in reg. x]
["x],r  ["x],er      Eval Region (visual selection) [or text from register x]
    ,b      ,eb      Eval Buffer
    ,v      ,ei      Interactive Eval (evaluates in frame when in SLDB)
    ,u      ,eu      Undefine Function
    Debug commands:
    ,1      ,m1      Macroexpand-1
    ,m      ,ma      Macroexpand All
    ,t      ,dt      Toggle Trace
    ,T      ,du      Untrace All
    ,B      ,db      Set Breakpoint
    ,l      ,dd      Disassemble
    ,i      ,di      Inspect (inspects in frame when in SLDB)
    ,a      ,da      Abort
    ,q      ,dq      Quit to Toplevel
    ,n      ,dc      Continue
    ,H      ,dl      List Threads
    ,K      ,dk      Kill Thread
    ,G      ,dg      Debug Thread
    Compile commands:
    ,D      ,cd      Compile Defun
    ,L      ,cl      Compile and Load File
    ,F      ,cf      Compile File
["x],R  ["x],cr      Compile Region [or text from register x]
    Cross Reference commands
    ,xc     ,xc      Who Calls
    ,xr     ,xr      Who References
    ,xs     ,xs      Who Sets
    ,xb     ,xb      Who Binds
    ,xm     ,xm      Who Macroexpands
    ,xp     ,xp      Who Specializes
    ,xl     ,xl      List Callers
    ,xe     ,xe      List Callees
    Profile commands:
    ,p      ,pp      Toggle Profile
    ,B      ,pb      Profile by Substring
    ,U      ,pa      Unprofile All
    ,?      ,ps      Show Profiled
    ,o      ,pr      Profile Report
    ,x      ,px      Profile Reset
    Documentation commands:
    ,s      ,ds      Describe Symbol
    ,A      ,da      Apropos
    ,h      ,dh      Hyperspec
    ,]      ,dt      Generate Tags
    Repl commands:
    ,c      ,rc      Connect to Server
    ,y      ,ri      Interrupt Lisp Process
    Set#1   Set#2    Command
    ---------------------------------------------------
    ,\      ,\       REPL Menu (separate menu, valid only for the REPL buffer)
    REPL menu commands:
    ,.      ,rs      Send Input
    ,/      ,ro      Close and Send Input
    ,g      ,rp      Set Package
    <C-C>   <C-C>    Interrupt Lisp Process
    ,<Up>   ,rp      Previous Input
    ,<Down> ,rn      Next Input
    ,-      ,-       Clear REPL

Note:

Some mappings accept an optional "x prefix (where x is a register name)
similarly to Vim's p (put) and y (yank) commands. These commands may
additionally use the given Vim register to store or retrieve text.

Commands "Eval Defun" and "Eval Current Expression" also store the form being

evaluated in the given register. When using uppercase register name, the
current form is appended to the contents of the register.

Commands "Eval Region" and "Compile Region" use the contents of the given
register (instead of the selected region) for evaluation or compilation.

This feature may be used for remembering and recalling a test form used for
testing parts of the code.

洋洋洒洒真是很多, 稍微试验几个, 发现确实支持, 简直太好了, 看来咱们想在纯文本界面的 vim 下使用全功能的 slime 大有但愿!

目前为止, 咱们已经完美验证了原先的想法: 在纯文本界面下用 tmux 启动 swank 服务端, 并经过 slimv 链接到 swank, 而后对新建的 REPL 区进行求值试验, 一切都很完美, 剩下的就工做是把咱们的验证成果转化为配置文件, 让它们应用起来!

明天继续...

相关文章
相关标签/搜索