最近又开始折腾编辑器了, 当然还是一个历史遗留问题, 我最爱的Sublime还是不能通过终端执行C/C++程序, 或者就是执行完之后直接退出了, 绕了一圈, 从每一个程序中加上system(read);
算是一个折中的方案, 但是终归有点麻烦, 采用AppleScript(命令行中使用osascript -e
)的方法当然可以, 但是我找了半天也没一个能跑明白… 只能说自己功力不够
下面倒是一个可以通过applescript跑起来的例子, 就是对iTerm
不行, 只能对系统默认的终端(Terminal.app
)来操作… 还是有点鸡肋的. 这个命令我参考了1, 并做了一些改动.
# double `-e`
osascript -e 'tell application "Terminal" to activate' -e 'tell application "Terminal" to do script "/Users/xxx/Desktop/main && read -n && exit"'
# single `-e`
osascript -e 'tell application "Terminal" to activate do script "clear && /Users/xxx/Desktop/main && read -n && exit"'
稍加配置就可以直接在sublime中运行了, 这里的配置就不详细说了. 其实万变不离其宗, 都是通过修改后缀为.sublime-build
的JSON文件实现的编译系统的配置. 下面主要以主流的iTerm为例进行配置.
这里借鉴一位印度开发者的gist2, 这里我修改成直接能运行的配置, 如下:
{
"shell_cmd": "g++ $file_name -o ${file_base_name}.out && \"/Users/xxx/Library/Application Support/Sublime Text 3/Packages/User/run-in-iTerm.sh\" ${file_path}/${file_base_name}.out",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c, source.c++, source.cxx, source.cpp",
}
其中的run-in-iTerm.sh
如下(其实还是Apple脚本):
#!/bin/bash
################################################
# https://stackoverflow.com/questions/32675804/how-do-i-execute-a-command-in-an-iterm-window-from-the-command-line
# https://www.iterm2.com/documentation-scripting.html
# Better Examples @ https://gitlab.com/gnachman/iterm2/wikis/Applescript
################################################
osascript - "$@" <<EOF
on run argv
tell application "iTerm"
activate
set new_term to (create window with default profile)
tell new_term
tell the current session
repeat with arg in argv
write text arg
end repeat
end tell
end tell
end tell
end run
EOF
但是我后来发现, 这个appleScript脚本还是有一些不方便的地方, 就比如每次执行之后都会创建一个新的iTerm窗口, 需要自己关闭, 我需要的是按下enter之后就销毁窗口(这点在vs或者dev-c++上就做得很好).
于是我又找到另外一种脚本3, 如下:
#!/bin/bash
osascript - "$@" <<EOF
on run argv
tell application "iTerm"
tell current session of current window
repeat with arg in argv
write text arg
end repeat
end tell
end tell
end run
EOF
上面脚本的意思是通过现有的窗口完成程序的运行, 但是这个也有一个问题, 就是必须要有一个已经打开的iTerm窗口, 否则就会报错说找不到打开的iTerm窗口, 这个还是有点烦, 接着找…
后来接连看了几篇回答和对应的外链(其实就是gist代码段和iTerm官方给出的代码), 分别是4,5, 发现Applescript已经被iTerm弃用了, 取而代之的是Python-API, 但是配置起来还是比较麻烦(其实就是因为自己没学过async
)
后来几经摸索, 我想出来了一个方案, 就是在前面给出的json的基础上, 设置一些参数, 使得Press ENTER to exit
得以实现, 下面是最后的配置, 当然, 这里也参考了sublime的build system的主要配置参数6, 比较简单, 这里我直接贴出来代码了:
{
"shell_cmd": "g++ -std=c++20 $file_name -o ${file_base_name}.out && \"/Users/xxx/Library/Application Support/Sublime Text 3/Packages/User/run-in-iTerm.sh\" \"clear && ${file_path}/${file_base_name}.out && read 'word?Press ENTER to exit!' && exit\"",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c, source.c++, source.cxx, source.cpp",
}
通过捕获read
命令的方式进行配置7, 这里也有一个坑, 就是之前的read -p "xxx"
的方式在zsh
上面失效了, 就必须采用read "name?what's your name?"
的方式进行读取, 一个测试的例子如下:
❯ read "name?what's your name?"
what's your name?paul
❯ echo $name
paul
# another format
❯ read name\?"what's your name?"
what's your name?paul
❯ echo $name
paul
这里当然就是随便选取一个别名即可, 我取的就是Press ENTER to exit!
这里有一个小插曲, 就是看第一段applescript中的代码, 里面的
repeat with arg in argv write text arg end repeat
- 1
- 2
- 3
部分是不是很像Python的
for i in range()
呢? 其实就是逐参数读取的命令, 这里我设置了一连串的命令, 就是方便其在iTerm中执行:\"clear && ${file_path}/${file_base_name}.out && read 'word?Press ENTER to exit!' && exit\"
- 1
总体效果还是很不错的, 如下:
macos - How to use osascript to open the Terminal App in a new window and make sure it’s on the top of all other windows? - Ask Different (stackexchange.com); ↩︎
How do I execute a command in an iTerm window from the command line? - Stack Overflow; ↩︎
Scripting - Documentation - iTerm2 - macOS Terminal Replacement; ↩︎
Build Systems — Sublime Text Unofficial Documentation (sublime-text-unofficial-documentation.readthedocs.io); ↩︎
bash - zsh: read:-p: no coprocess error while using read command with -p flag - Ask Ubuntu; ↩︎