使用 Doom Emacs 构建 iOS 应用
我通过 Doom Emacs 发布了我的第一个 iOS 应用 SPEEM,而不是通过 Xcode。我不是说我只是在 Emacs 中编辑了几个文件,然后在构建时切换回来。我是说整个循环:编写 Swift,构建,启动模拟器,安装应用,启动它,流式日志,重启 LSP,搭建新项目。所有这些都在 Emacs 内部完成,所有操作都是通过我自己编写的 SPC i 快捷键驱动的。本文将讲述如何以及为什么这甚至可能实现。简而言之,苹果提供了一小队命令行工具,比如 xcodebuild、xcrun simctl、xcrun swift-format、sourcekit-lsp,而大多数 iOS 开发者从未直接接触过它们。Xcode 只是将它们包装起来的华丽外壳(当然还有许多其他内置的实用工具)。如果你愿意自己将这些工具结合在一起,你可以在任何允许你运行 shell 命令并读取进程输出的编辑器中建立一个真实的 iOS 工作流程。Doom Emacs 恰好在这方面表现非常出色(或者说任何 Emacs 发行版实际上都是如此)。对我来说,结果是一个约 1000 行的 modules/ios.el 文件,它提供了 SPC i b 用于构建,SPC i s 用于在选定的模拟器上安装和启动,SPC i l 用于流式过滤日志,SPC i n 用于搭建新的 SwiftUI 项目,以及我将在下面逐步介绍的其他一些功能。为什么我这样做 我生活在 Emacs 中。我已经每天使用 Doom Emacs 进行四年了:Rust、Elixir、Kotlin/Android、Web、org-mode、Magit,所有这些。当我为 SPEEM 回到 iOS 开发时,我尝试了两周的 Xcode,感觉就像穿上了别人的鞋子。不是坏鞋子,就是不合适。我还有一个多语言配置。我有 modules/rust.el、modules/elixir.el、modules/kotlin-android.el、modules/web.el,等等。每种语言都有相同的结构:一个主要模式、LSP、构建/运行/测试的快捷键。iOS 作为唯一的例外让我感觉不对。所以我坐下来写了 modules/ios.el。这是里面的内容。苹果在命令行上实际提供了什么 在使用任何 Emacs Lisp 之前,了解现在有什么是有帮助的。当你运行 xcode-select -p 时,你会得到活动开发者目录,其中包含 Xcode 内部使用的所有工具:$ xcode-select -p /Applications/Xcode.app/Contents/Developer 在其中,与通过终端构建和运行 iOS 应用相关的重要工具有:xcodebuild,编译你的 .xcodeproj 或 .xcworkspace。它接受方案、SDK、目标和一系列操作(如构建、清理、测试)。这是当你按下运行时 Xcode 自身调用的内容。xcrun simctl,控制 iOS 模拟器。引导、安装、卸载、启动、终止、截屏、覆盖状态栏。你在模拟器应用中点击的任何操作,都可以用 simctl 完成。xcrun swift-format,苹果官方的 Swift 格式化工具。对 stdin/stdout 有效。sourcekit-lsp,苹果的 Swift 语言服务器。与 Xcode 一起发布,位于 Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp。这就是给我补全、跳转定义、错误和重构的内容。xcode-build-server,并不是苹果提供的,但至关重要。它生成一个 buildServer.json,告诉 sourcekit-lsp 项目的实际配置(构建标志、模块等)。没有它,LSP 是有效的,但对你项目的一半是盲目的。brew install xcode-build-server。xcodegen,也不是苹果提供的。从一个小的 YAML 文件生成 .xcodeproj。我用它来搭建新项目,这样我就不必打开 Xcode 的项目编辑器。一旦你了解这些的存在,其余的就是 orchestrating。我的 Doom 配置的结构 我的 Doom 配置分为多个模块。顶层的 config.el 很小: ;;; config.el -*- lexical-binding: t; -*- (setq doom-font (font-spec :family "Fira Code" :size 13 :weight 'semi-light) doom-variable-pitch-font (font-spec :family "Fira Sans" :size 14) doom-theme 'doom-monokai-pro display-line-numbers-type t org-directory "~/org/") (load! "modules/core") (load! "modules/lsp") (load! "modules/rust") (load! "modules/elixir") (load! "modules/ios") (load! "modules/kotlin-android") (load! "modules/web") (load! "modules/slint") (load! "modules/projectile") (load! "modules/org") (load! "modules/tools") (load! "modules/keybindings") ; 所有 map! 调用都集中在此处,最后加载 iOS 特定的部分位于 modules/ios.el 中,相关的快捷键在 modules/keybindings.el 中。我将快捷键与功能代码分开,以便所有的 map! 都在一个地方,更易于 grep,也更易于理解。在 Doom-modules 侧,init.el 启用标准的 (swift +lsp) 语言模块: :lang (swift +lsp) ; 谁需要 emoji 变量?这为我提供了 swift-mode 和 LSP 支持。以下所有内容都建立在此之上。指向正确 sourcekit-lsp 的 LSP 这里有一个微妙之处。在 Mac 上通常有两个 sourcekit-lsp 二进制文件:一个在 /Library/Developer/CommandLineTools/... 和一个在活动的 Xcode 内部。它们不一定是相同版本,从而使用错误的版本会以令人困惑的方式破坏诊断。我想要与我活动的 Xcode 匹配的那个。 (let* ((dev (string-trim (shell-command-to-string "xcode-select -p"))))
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡