写在前面
引入
众所周知,Sublime 在使用默认的 JavaC 或 C++ Single File 配置编译运行代码时会调用其内置的终端进行输出,而这个终端是不支持输入的。但我使用 Sublime 做算法题时有经常会有需要程序输入的需求,于是就需要 Sublime 调用外部终端来编译和运行代码(至少运行要在外部终端中完成),带着这样的需求网上查了一圈之后发现大多数教程的解决方案是自定义编译系统,其中编译用到的命令大多是:
{
"shell_cmd": "g++-12 \"${file}\" -std=c++11 -o \"${file_path}/${file_base_name}\" && open -a Terminal.app \"${file_path}/${file_base_name}\"",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:?(.*)$",
"working_dir": "${file_path}",
"selector": "source.c++",
}
其中关键的是:
"shell_cmd": "编译命令 && open -a Terminal.app \"${file_path}/${file_base_name}\"",
也就是使用 open
指令指定使用 Terminal.app
应用打开编译完成的 ${file_path}/${file_base_name}
文件(关于 open
命令的介绍及用法可以在终端中输入 man open
自行查看,这里不过多介绍),实现的效果如下:
如果这就解决了我的需求那么这篇文章就不会出现了(笑)。
现有解决方案的痛点
这样的解决方案有几个缺陷:
- C++ 程序可以直接跑,但是 Java 程序是需要使用
java
命令运行的,所以无法用于 Java。 - 可自定义程度太低。
- 运行完成后无法自动清理编译的文件。
新的解决方案
首先声明,我的这种解决方案非常简单粗暴,应该已经有许多前人发现并用于实践中了,这里的“新的”只是对于我自己而言。
想法是:如果可以让 Sublime 帮忙执行一个 shell 脚本 并传入当前代码的文件名及其路径,然后由这个脚本来进行编译运行的操作就可以很好的解决以上的三个问题了!
先看看这种方案的展示吧:
展示
编译错误
环境
演示环境
- 系统:macOS Monterey 12.6 (芯片:Apple M1 Pro)
- Sublime Text:Sublime Text Dev Channel, Build 4134
- Terminal:Terminal 2.12.7(445)
- iTerm2:iTerm2 Build 3.4.16
- SHELL:zsh
配置
- 首先在 Sublime 中选择:工具 > 编译系统 > 新建编译系统
- 先不做任何修改保存该文件 ⌘ + S(可以随意修改该文件名字)
- 然后右键编辑器空白的地方选择「打开所在文件夹…」(一般来说,该目录是
~/Library/Application Support/Sublime Text/Packages/User
)
在该目录下创建一个目录用于存放我们自己编写的用于编译运行程序的 shell 脚本,我这里新建了 UserScripts
目录(如果您完全不知道这是在干什么,可以先跟着目前部分的教程走,随后阅读下面的原理部分以做出自定义)
- 在刚才创建的目录中创建其中创建并编写用来编译运行代码的 shell 脚本。
我这里创建了cpp_build.sh
与java_build.sh
,下面给出文件内容:
cpp_build.sh
#!/bin/bash
echo -ne "\033]0;"$2"\007"
clear
cd "$1"
echo -e "\033[1;32m[Compiling]\033[0m"
g++-12 "$2" -std=c++11 -o "$3"
echo -e "\033[1;32m[Running]\033[0m"
./"$3"
echo -e "\033[1;32m[Finished]\033[0m"
rm "$3"
echo "Press ENTER to exit..."
read
java_build.sh
#!/bin/bash
echo -ne "\033]0;"$2"\007"
clear
cd "$1"
echo -e "\033[1;32m[Compiling]\033[0m"
javac -encoding "UTF-8" -d . "$2"
echo -e "\033[1;32m[Running]\033[0m"
java "$3"
echo -e "\033[1;32m[Finished]\033[0m"
rm "$3"*.class
echo "Press ENTER to exit..."
read
- 现在回到 Sublime Text 编辑器,编辑之前创建的
xxx.sublime-build
为:(注意要修改目录名与脚本名为刚才创建的目录名和脚本名,以及修改iTerm.app
为您的终端)
C++ 的配置文件:cpp.sublime-build
{
"shell_cmd": "cd \"$packages/User/UserScripts\" && echo \"cd '${packages}/User/UserScripts' && ./cpp_build.sh '${file_path}' '${file_name}' '${file_base_name}'\" > tmp.sh && chmod +x tmp.sh && open -a iTerm.app tmp.sh",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:?(.*)$",
"working_dir": "${file_path}",
"selector": "source.c++",
}
Java 的配置文件:java.sublime-build
{
"shell_cmd": "cd \"$packages/User/UserScripts\" && echo \"cd '$packages/User/UserScripts' && ./java_build.sh '$file_path' '$file_name' '$file_base_name'\" > tmp.sh && chmod +x tmp.sh && open -a iTerm.app tmp.sh",
"file_regex": "^(...*?):([0-9]*):?([0-9]*)$",
"working_dir": "${file_path}",
"selector": "source.java",
}
到这里配置就已经完成了,可以回到你的代码中按 ⌘ + ⇧ + B 来选择 build 配置并执行啦。
原理
首先我们从 xxx.sublime-build
开始,以 java.sublime-build
为例:
"shell_cmd": "cd \"$packages/User/UserScripts\" && echo \"cd '$packages/User/UserScripts' && ./java_build.sh '$file_path' '$file_name' '$file_base_name'\" > tmp.sh && chmod +x tmp.sh && open -a iTerm.app tmp.sh"
这条命令首先进入 $packages/User/UserScripts
目录下,把以下内容覆盖写入 tmp.sh
这个文件中:
cd '$packages/User/UserScripts' && ./java_build.sh '$file_path' '$file_name' '$file_base_name'
(这里带有 $
符号的都是 Sublime 所定义的环境变量,写入后会被替换为其对应的值,具体见:Build Systems - variables)
然后执行 open -a iTerm.app tmp.sh
也就是用 iTerm.app
这个应用打开 tmp.sh
脚本。
tmp.sh
中的内容表示:还是进入 $packages/User/UserScripts
目录下,向 java_build.sh
脚本中传入 $file_path
、 $file_name
、$file_base_name
这三个参数并执行。
然后看 xxx.sh
脚本,这里以 java_build.sh
为例:
#!/bin/bash
echo -ne "\033]0;"$2"\007" # 把当前终端的标题改为传入的第二个参数
clear # 清屏
cd "$1" # 进入第一个参数传入的路径
echo -e "\033[1;32m[Compiling]\033[0m" # 输出绿色加粗的[Compiling]
javac -encoding "UTF-8" -d . "$2" # 编译java代码
echo -e "\033[1;32m[Running]\033[0m" # 输出绿色加粗的[Running]
java "$3" # java命令运行第三个参数传入的文件名
echo -e "\033[1;32m[Finished]\033[0m" # 输出绿色加粗的[Finished]
rm "$3"*.class # 删除编译出的字节码文件
echo "Press ENTER to exit..." # 输出普通文本
read
由于每次都会覆盖写入 tmp.sh
文件,所以该文件不用处理。
一些问题
Q:使用 iTerm 时,终端的标题没有被修改?
A:进入 iTerm2 > Preferences… > Profiles > 你的配置 > General > Basics > Title,勾选 Application in terminal may change the title。
评论区