macOS 批量修改默认打开方式

(以迁移 VSCode 到 Cursor为例)

macOS 批量修改默认打开方式
Photo by Kelli McClintock / Unsplash

背景

最近使用了不同版本的 VSCode,有原版的,还有 Windsurf,Cursor。用到最后还是更偏好 Cursor 的代码补全 Cursor Tab,丝滑不是别的能比的,Windsurf 的代码补全虽然免费还是差点意思。

但是当前各种代码文件的默认打开方式都绑定到了 Windsurf 上,特别是 Raycast 打开某些文件或者文件夹默认是 Windsurf,而且找不到修改的地方,猜测应该是跟系统的默认编辑方式有关。因此考虑把 Windsurf 绑定的后缀全都转移到 Cursor 上。

网上找了很久因为没有发现简单的方法,不过发现了一个可以用命令行修改打开方式的软件 duti,这样也算是可以自己实现自动化修改了。

基本思路

  1. 获取 Cursor 支持的文件类型,位置在/Applications/Cursor.app/Contents/Info.plist,使用 Python 自带的的 plistlib 库读取

    这个文件可以通过在 Application 文件夹内右击应用图标,然后显示包内容,里面找到。

  2. 查看这些文件类型绑定的打开方式,如果是 Windsurf 就改成 Cursor,这里需要安装 duti

    brew install duti
    

参考实现:把 Windsurf 绑定的文件类型修改为 Cursor 默认打开

import plistlib  # 读取 plist 文件
import subprocess  # 执行命令


def get_default_opener(ext):
    # 获取当前的打开方式
    result = subprocess.run(['duti', '-x', ext], capture_output=True, text=True)
    if result.returncode != 0:
        print(result.stderr)
        return None
    return result.stdout.split("\n")[0]


def set_default_opener(ext, opener, role):
    # 设置默认的打开方式
    result = subprocess.run(['duti', '-s', opener, ext, role], capture_output=True, text=True)
    if result.returncode != 0:
        print(result.stderr)
        return False
    return True

if __name__ == '__main__':
    # 目标软件的 Info.plist 路径
    app_name = 'Cursor'
    path = f'/Applications/{app_name}.app/Contents/Info.plist'
    with open(path, 'rb') as f:
        plist = plistlib.load(f)
    # 简单处理一下
    ext_list = [{
        'name': item['CFBundleTypeName'],
        'ext': item['CFBundleTypeExtensions']
    } for item in plist['CFBundleDocumentTypes']]
    # 获取 bundle_id
    bundle_id = plist['CFBundleIdentifier']
    # 结果是类似这样的
    # ext_list : [{'ext': ['h'], 'name': 'C header file'},
    #  {'ext': ['c'], 'name': 'C source code'},
    #  {'ext': ['gitattributes', 'gitconfig', 'gitignore'],
    #   'name': 'Git configuration file'}, ...]
    # bundle_id : 'com.todesktop.Cursor' 或者破解之后的 Cursor,可能是别的值。

    # 遍历所有扩展名,把 Windsurf 相关的改成 Cursor
    # 之所以不全改,是因为有些扩展名我已经自定义过了,比如 markdown 文件,我习惯用 Typora 打开。
    # Html 文件,我习惯用浏览器打开,或者还有的要用 jetBrains 的一些 IDE 打开。
    # 这里的逻辑可以自行修改
    for item in ext_list[:]:
        print(item['name'])
        for i, ext in enumerate(item['ext']):
            default_opener = get_default_opener(ext)
            print(f'    {ext} -> {default_opener}', end='')
            if default_opener == 'Windsurf':
                print(f' -> {app_name}')
                set_default_opener(ext, bundle_id, 'editor')
            else:
                print()

PS: 如果只想修改某一个扩展名的打开方式,有简单的方式,直接访达右键查看简介,在打开方式那里可以选择改变全部。

GitHub - moretension/duti: A command-line tool to select default applications for document types and URL schemes on Mac OS X
A command-line tool to select default applications for document types and URL schemes on Mac OS X - moretension/duti
duti
Homebrew’s package index