侧边栏壁纸
博主头像
GabrielxD

列車は必ず次の駅へ。では舞台は?私たちは?

  • 累计撰写 675 篇文章
  • 累计创建 128 个标签
  • 累计收到 28 条评论

目 录CONTENT

文章目录

【小技巧】在macOS下配置Sublime4使用外部终端编译并运行代码

GabrielxD
2022-10-03 / 1 评论 / 1 点赞 / 825 阅读 / 1,843 字
温馨提示:
本文最后更新于 2023-04-24,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

写在前面

引入

众所周知,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 自行查看,这里不过多介绍),实现的效果如下:

image-20221003031550444

如果这就解决了我的需求那么这篇文章就不会出现了(笑)。

现有解决方案的痛点

这样的解决方案有几个缺陷:

  1. C++ 程序可以直接跑,但是 Java 程序是需要使用 java 命令运行的,所以无法用于 Java。
  2. 可自定义程度太低。
  3. 运行完成后无法自动清理编译的文件。

新的解决方案

首先声明,我的这种解决方案非常简单粗暴,应该已经有许多前人发现并用于实践中了,这里的“新的”只是对于我自己而言。

想法是:如果可以让 Sublime 帮忙执行一个 shell 脚本 并传入当前代码的文件名及其路径,然后由这个脚本来进行编译运行的操作就可以很好的解决以上的三个问题了!

先看看这种方案的展示吧:

展示

image-20221003033038549

编译错误

image-20221003033131157

环境

演示环境

  • 系统: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

配置

  1. 首先在 Sublime 中选择:工具 > 编译系统 > 新建编译系统

image-20221003034315776

  1. 先不做任何修改保存该文件 ⌘ + S(可以随意修改该文件名字)

image-20221003034556101

  1. 然后右键编辑器空白的地方选择「打开所在文件夹…」(一般来说,该目录是 ~/Library/Application Support/Sublime Text/Packages/User

image-20221003034709452

在该目录下创建一个目录用于存放我们自己编写的用于编译运行程序的 shell 脚本,我这里新建了 UserScripts 目录(如果您完全不知道这是在干什么,可以先跟着目前部分的教程走,随后阅读下面的原理部分以做出自定义)

image-20221003035456063

  1. 在刚才创建的目录中创建其中创建并编写用来编译运行代码的 shell 脚本。
    我这里创建了 cpp_build.shjava_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
  1. 现在回到 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。

参考

1

评论区