LookMinds
去登录

《个人电脑使用(以苹果产品为例)》

《个人电脑使用(以苹果产品为例)》,共 28 章。事实上,前两个就已经足够了(都是有声词典)……另外,还需要下载 Dictionary Development Kitpyglossary 使用方法如下:以 Merriam-Webster\'s_Collegiate_Di…

Source: https://github.com/xiaolai/apple-computer-literacy

《个人电脑使用(以苹果产品为例)》

> 作者:李笑来 · 本人在 GitHub 公开的书稿 · [GitHub 仓库](https://github.com/xiaolai/apple-computer-literacy) · 本馆按 2025-02-19 的版本收录,共 28 章。图片以链接形式给出。

Mdict 词典转换

0. Mdict 格式词典下载

[freemdict.com](https://downloads.freemdict.com/) 和 [mdict.org](https://mdx.mdict.org/)上有很多 Mdict 格式的词典文件。Mdict 的词典文件,通常由一个 `.mdx` 文件和一个 `.mdd` 文件构成,声音和图片都打包在 `.mdd` 文件之中。需要同时下载两个文件,放到同一个目录中进行处理。

**推荐**

* [Cambridge Advanced Learner's Dictionary 4ed](https://downloads.freemdict.com/Recommend/Collections/_Cambridge/CALD%204th/)
* [Merriam-Webster's Collegiate Dictionary 11ed (Pic&Sound)](https://downloads.freemdict.com/Recommend/Collections/Merriam-Webster/Merriam-Webster/Merriam-Webster/)
* [Longman Dictionary of Contemporary English 6ed](https://downloads.freemdict.com/Recommend/Collections/_Longman/STFU%20LongmanBundle-%E7%BB%AE%E5%8F%A5%E6%85%A8%E9%90%97-By%20Amazon%2020160928/Longman%20Dictionary%20Of%20Contemporary%20English%206th%20EnEn)
* [Longman Language Activator](https://downloads.freemdict.com/Recommend/longman-activator.zip)
* [Collins CoBuild Advanced Learner's Dictionary](https://downloads.freemdict.com/Recommend/CollinsCOBUILDAdvancedLearner%E2%80%99sDictionaryOnline2017.zip)
* [American Heritage Dictionary 5ed](https://downloads.freemdict.com/Recommend/AHD5.zip)
* [Oxford Collocation Dictionary](https://mdx.mdict.org/%E5%85%AD%E5%A4%A7%E7%9F%A5%E5%90%8D%E8%AF%8D%E5%85%B8/%E7%89%9B%E6%B4%A5_Oxford/Oxford%20Collocations%20Dictionary_%2015-10-15/)

事实上,前两个就已经足够了(都是有声词典)……

1. 所需工具与环境

```bash
# Python (python 3.11.5 specified)
conda create -n mdict python=3.11.5
conda activate mdict
pip install pyglossary lxml beautifulsoup4 html5lib

# install Homebrew; if brew already installed, skip this section.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

# speex for converting spx to wav
brew install speex

# ffmpeg for converting wav to mp3
brew install ffmpeg
```

另外,还需要下载 `Dictionary Development Kit`

* 下载地址:[Additional Tools for Xcode](http://developer.apple.com/downloads)

* 下载与操作系统中安装的 xcode 匹配的 “Additional Tools for Xcode”
```bash
# check out xcode version
xcodebuild -version
```

* 将其中 `Utilities` 下的 `Dictionary Development Kit` 目录整体拷贝粘贴到本机 `/Applications/Utilities` 下

* 用以下代码替换 `/Applications/Utilities/Dictionary Development Kit/bin/build_dict.sh` 的第 `221` 行:

```bash
rsync -a "$OTHER_RSRC_DIR"/ "$OBJECTS_DIR"/dict.dictionary/"$CONTENTS_DATA_PATH" || error "Error."
```

3. 转换 mdx

`pyglossary` 使用方法如下:

```bash
pyglossary --write-format=AppleDict <mdx_file> <output_dir>
```

以 `Merriam-Webster\'s_Collegiate_Dictionary_11th\(Pic\&Sound\).mdx` 为例:

```bash
pyglossary --write-format=AppleDict Merriam-Webster\'s_Collegiate_Dictionary_11th\(Pic\&Sound\).mdx "Merriam-Webster's Collegiate Dictionary"
```

4. spx 文件的转换

如果 `OtherResources` 目录里的声音文件原本就是 `.mp3` 就可以跳过这一步。但,如果是 `.spx` 的话,就需要将 `.spx` 文件转换为 `.mp3` 文件:

```bash
# long time needed, possibly up to an hour or more...
for file in *.spx; do
# Decode the SPX to WAV
speexdec "$file" "${file%.spx}.wav"
# Encode the WAV to MP3
ffmpeg -i "${file%.spx}.wav" -f mp3 "${file%.spx}.mp3"
# Optionally remove the intermediate SPX file
rm "$file"
# Optionally remove the intermediate WAV file
rm "${file%.spx}.wav"
done
```

而后,`xml` 文件里的声音文件名也需要转换(可以提前用 vscode 或者 sublime text 打开 xml 查看一下,根据需要批量替换的字符串修改以下命令)

```bash
sed -i '' 's/\.spx/\.mp3/g' file.xml
```

如果需要将 `.wav` 文件批量转换为 `.mp3`:

```bash
for file in *.wav; do
ffmpeg -i "$file" -f mp3 "${file%.wav}.mp3"
# Optionally remove the intermediate WAV file
rm "$file"
done
```

5. 其它定制信息

`pyglossary` 生成的文件中,`.css` 文件,可根据自己需要修改。

macOS 原生词典里面是不支持 `base64` 格式的字体文件的,所以我们需要手动将原先css里面base64格式的字体转换成它原来的样子并放到 `Contents` 文件夹下。

[Base64 Online - base64 decode and encode (motobit.com)](https://www.motobit.com/util/base64-decoder-encoder.asp)

`.plist` 文件中,`CFBundleName` 是词典缩写(显示在词典的标签栏上),`CFBundleDisplayName` 是词典名称的完整名称(显示在 Preference 对话框中),可根据自己需要修改。

6. 安装词典

```bash
cd "Merriam-Webster's Collegiate Dictionary"
make
```

生成的词典在 `objects` 目录中。

安装词典到 `~/Library/Dictionaries`:

```bash
make install
```

而后就可以在 Dictionary 里,`cmd+,` 在对话框里选择新安装的词典了。

7. 删除词典

在 `~/Library/Dictionaries` 目录中将词典的整个目录删掉即可。

8. 捷径

若是懒得折腾,可以在百度网盘下载一个压缩包,解压缩后,把其中六个词典目录挪到 `~/Library/Dictionaries` 目录之下即可,重新启动 Dictionary.app,`cmd+,` 在对话框里选择新安装的词典。

链接: https://pan.baidu.com/s/1TpYyYYdvFGsMLI65i7NBog?pwd=buqn 提取码: buqn

> * Cambridge Advanced Learner's Dictionary.dictionary
> * Collins COBUILD Advanced Learner's Dictionary.dictionary
> * Merriam-Webster's Collegiate Dictionary.dictionary
> * Longman Dictionary of Contemporary English 6ed.dictionary
> * Longman Language Activator.dictionary
> * Oxford Collocation Dictionary.dictionary

Mechvibes

[Mechvibes](https://mechvibes.com/) 是个看起来挺无聊的小软件,为键盘配置个性化的声音,比如,模拟机械键盘的敲击声…… 有 macOS/Windows/Linux 各种版本。

学日语的时候,我用它为每个键盘对应的日文字母配置了发声文件,用来让自己快速适应日文键盘,超级好用。

日文字母的发声文件,是用 edge_TTS 生成的,Python 代码片段也很简单:

```python
import asyncio
import edge_tts
import pygame
import time

voice = "ja-JP-NanamiNeural"

string = "49,ぬ;50,ふ;51,あ;52,う;53,え;54,お;55,や;56,ゆ;57,よ;48,わ;189,ほ;187,へ;81,た;87,て;69,い;82,す;84,か;89,ん;85,な;73,に;79,ら;80,せ;65,ち;83,と;68,し;70,は;71,き;72,く;74,ま;75,の;76,り;186,れ;186,け;221,む;90,つ;88,さ;67,そ;86,ひ;66,こ;78,み;77,も;188,ね;190,る;191,め;189,ろ;222,ろ"
pairs = string.split(";")

for p in pairs:
key, value = p.split(",")
output_file_name = f"{value}.mp3"
communicate = edge_tts.Communicate(value, voice)
await communicate.save(output_file_name)
time.sleep(3)
# print(f'"{key}": "{value}.mp3",')

```

下载 [japanese-keyboard-sound.zip](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/files/japanese-keyboard-sound.zip),解压缩,拷贝到 `~/mechvibes_custom` 文件夹内,重新启动 Mechvibes,即可选择自定义键盘声音包。

NotebookLM by Google

[NotebookLM](https://notebooklm.google.com) 是 Google 推出的 “人工智能辅助笔记” 应用。用户上传文档(PDF/TXT/Markdown)至 NotebookLM 后,就可以向文档提问,由 AI 回答。

除此之外,无论是论文还是书籍,NotebookLM 都可以为此生成一个 "Deep Dive Podcast",大约 30 分钟左右的两人对话语音讲解。

目前(2024 年 12 月)的局限之一是只能用英语才能获得最佳效果。

我的做法是:

> 1. 先在 Kindle 上读完一本书(我觉得这一步绝对不能跳过);
> 2. 从自己的 [Content Library](https://www.amazon.com/hz/mycd/digital-console/contentlist/booksAll/dateDsc/) 里下载相应的 azw3 文件;
> 3. 使用 ePubor 软件将其转换成 epub 文件(参见[这篇文章](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/kindle.md));
> 4. 【待续……】

我写了一个 Automator Quick Action —— 如此这般之后,在 Finder 里右键点击 epub 文件的时候,会多出一个 `Context Menu: Convert EPUB to markdown`……(

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/quickaction-context-menu.png)

它会把 `epub` 文件转换成一个文件夹,其中有整本书的 `txt` 文件,以及拆分的各个章节的 `markdown` 文件,另外,`epub` 中原本包含的内容,在 `html` 子目录中。

有一个前提:你的系统中安装了 `pandoc` 命令行工具 —— 如果没有的话,可以通过 `brew install` 命令安装。

```bash
brew install pandoc
```

另外,你也需要检查一下系统内置的 `unzip` 是否存在:

```bash
which unzip
```

如果不存在的话,就用 `brew` 安装:

```bash
brew install unzip
```

如果你想要自己用 Automator 写 Quick Action 的话,可以在 Quick Action 里添加以下 Shellscript 内容:

``` bash
#!/bin/zsh

# Path to pandoc
PANDOC_CMD="/opt/homebrew/bin/pandoc"

# Get the selected EPUB file
EPUB_FILE="$1"

# Verify the file exists
if [ ! -f "$EPUB_FILE" ]; then
exit 1
fi

# Define paths
ZIP_FILE="${EPUB_FILE%.epub}.zip"
TMP_DIR=$(mktemp -d)
OUTPUT_DIR="${EPUB_FILE%.epub}"

# Create output directory
mkdir -p "$OUTPUT_DIR/html"

# Copy and rename the EPUB to a ZIP file
cp "$EPUB_FILE" "$ZIP_FILE"

# Unzip the file
unzip -q "$ZIP_FILE" -d "$TMP_DIR"
if [ $? -ne 0 ]; then
rm -rf "$TMP_DIR" "$ZIP_FILE"
exit 1
fi

# Locate the OEBPS folder
OEBPS_DIR=$(find "$TMP_DIR" -type d -name "OEBPS")
if [ -z "$OEBPS_DIR" ]; then
rm -rf "$TMP_DIR" "$ZIP_FILE"
exit 1
fi

# Copy all content from OEBPS to the output directory's html folder
cp -R "$OEBPS_DIR"/* "$OUTPUT_DIR/html/"

# Determine if the folder contains .html or .xhtml files
if ls "$OEBPS_DIR"/*.html 1> /dev/null 2>&1; then
FILE_EXT="html"
elif ls "$OEBPS_DIR"/*.xhtml 1> /dev/null 2>&1; then
FILE_EXT="xhtml"
else
FILE_EXT=""
fi

# Convert files to Markdown if a valid file type is found
if [ -n "$FILE_EXT" ]; then
for HTML_FILE in "$OEBPS_DIR"/*."$FILE_EXT"; do
if [ -f "$HTML_FILE" ]; then
BASENAME=$(basename "$HTML_FILE" ."$FILE_EXT")
"$PANDOC_CMD" "$HTML_FILE" -t plain --strip-comments -o "$OUTPUT_DIR/$BASENAME.md"
fi
done
fi

# Convert the entire EPUB to a single TXT file
FULL_TXT_FILE="$OUTPUT_DIR/$(basename "${EPUB_FILE%.epub}.txt")"
"$PANDOC_CMD" "$EPUB_FILE" -t plain --strip-comments -o "$FULL_TXT_FILE"

# Cleanup
rm -rf "$TMP_DIR"
rm "$ZIP_FILE"

# Notify completion
osascript -e "display notification \"Output saved to: $OUTPUT_DIR\" with title \"EPUB Processor\""
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/quickaction-script.png)

你也可以直接下载这个文件:[Convert EPUB to Markdown.workflow](https://raw.githubusercontent.com/xiaolai/apple-computer-literacy/main/files/Convert%20EPUB%20to%20Markdown.zip),将其保存到 `~/Library/Services` 文件夹中即可。

继续回到 NotebookLM 工作流中:

> 4. 新建一个 Notebook,将整本书的 txt 文件上传,让 NotebookLM 生成 Podcast;
> 5. 在将拆分成各个章节的多个 Markdown 文件添加至这个 Notebook;如此这般之后,就可以 “针对整本书(只选择整本书的文件)” 或者 “只针对某个章节(只选择某个章节的文件)” 提问。

我最常用的几个 Prompt 分别是(主要是针对每个章节提问):

> * Make an extensive summary of this file.
> * List all scientific findings the author mentioned in this file.
> * List all metaphors and analogies in this file.
> * List all phrasal verbs and idioms in this file, and provide concise Chinese translation of them according to the context.
> * List all less common vocabulary in this file and provide phonetics, part of words, and concise Chinese translation according to the context.
> * Provide a short list of "Further Reading", recommend 5 best related books and scientific papers.

Alfred

Alfred 的图标,是个英式管家常戴的那种窄边圆礼帽 —— 当初一看到这个名字,就想起来蝙蝠侠的管家,Alfred Pennyworth),也不知道这个软件当初起名字是不是跟这个有关系。

反正,Alfred 真的像是你的系统管家,能帮你干很多很多事情 —— 通过一个跟 Spotlight 相似的一个搜索框,你可以非常快捷地完成很多工作。

```bash
brew install alfred
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/alfred-4-hero.png)

我买的 License 是它的 [Mega Supporter, Free Lifetime Upgrades, £49](https://www.alfredapp.com/shop/) —— 在工具上省钱是没出息的。

它的所有功能里,我最常用的,是剪贴板增强功能,它可以保存你的所有剪贴板历史,当你需要的时候,可以用快捷键 `⇧⌘p` 查看,选择究竟应该粘贴哪个 —— 在此基础上还支持快捷键和搜索……

除此之外,它还有很多功能值得研究。

比如,你想快速完成从 Terminal 到 Finder,或者反之 —— 虽然前面介绍过很多做法 —— 那么,最方便的,就是直接下载一个 Alfred Workflow,[alfred-terminalfinder](https://github.com/LeEnno/alfred-terminalfinder/raw/master/TerminalFinder.alfredworkflow)(右键 `Save as...`);下载到本地之后,在安装好 Alfred 的情况下,鼠标双击下载好的文件,将其导入 Alfred —— 而后就可以一个快捷键呼出 Alfred Search Box(我为其设置的快捷键是 `⌥ ␣`(Option 和 Space),然后,输入 `tf⮐` 或者反之 `ft⮐` —— 太方便。

再比如说,需要输入一些 Unicode 的时候,官方自带的 Charater View 要多别扭就有多别扭…… 可是,在 Alfred 里安装 [Unicode Text Search Workflow](https://github.com/bevesce/unicode-symbols-search/raw/master/Unicode%20Symbols%20Search.alfredworkflow) 之后,就实在是太方便了,在输入框里输入:`uss four fi↩` (不用等到输入完整的时候,`⅘` 已经排在第一位了)按下回车键的时候,`⅘` 这个字符已经在剪贴板里,并且放到你刚刚正在输入的区域里了……

应该花点时间研究一下 Github 上的 [Awesome Alfred](https://github.com/alfred-workflows/awesome-alfred-workflows) 的仓库,里面有很多方便且必须的 Alfred Workflow……

另外,Alfred 的一些脚本(比如上面提到的 USS)需要 Python@2,但,MacOX 的最近版本中已经废弃了 Python 2.7…… 一个解决方案就是[去官网下载并安装 Python 2.7](https://www.python.org/downloads/release/python-2718/),之后,在 Alfred 中需要使用 Python 2.7 的时候选择 `/usr/local/bin/python` 作为脚解释器……

Alfred 的 `Run Script` 中,没有办法指定 Python 的安装目录(比如,通过 Homebrew 安装的 Python3)。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/alfred-script-path.png)

XCode 在系统中安装了一个 `/usr/bin/python3` 和 `usr/bin/pip3`,是 Alfred 可以调用的。所以,当需要为这个环境安装模块的时候,要在命令行中执行:

```bash
/usr/bin/pip3 install ....
```

以下是一个例子(用来将英文转换成 IPA 音标 —— 可处理句子)

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/alfred-script-python3-example.png)

在此之前,就需要在命令行中用 `/usr/bin/pip3` 安装 `eng-to-ipa` 模块:

```bash
/usr/bin/pip3 install eng-to-ipa
```

另外,我写了一个 [Window Managment Workflow](https://github.com/xiaolai/Window-Management-alfredworkflow),可以指定各种快捷键设定当前窗口的尺寸和布局,值得试试……(有了这个之后,我基本放弃了 BetterTouchTool —— 我原本用它做窗口管理。)

Anki(暗记)Deck 制作(Python)

[Anki](https://apps.ankiweb.net/) 是一个开源免费的 “速记卡(Flashcard)工具”。Anki 这个名称是日文 “暗記”(あんき)的英文拼写 —— 意思相当于中文的 “熟记”。

1. Python Library for Generting Anki Decks: genanki

> https://github.com/kerrickstaley/genanki

本地安装: `pip install genanki`

2. 从文本中截取例句

最好的记忆方式,并不是直接记忆一个单词列表 —— 无论那个列表制作多么精良…… 不要错过或者跳过制作单词列表之前的一步:

> **认真阅读**或者**反复阅读**文本。

任何时候都一样:

> 真正有意义的完整文本(而不是只言片语)是词汇生根发芽的土壤。

```python
from nltk.tokenize import sent_tokenize

def find_sentences_with_word(text, target_word, case_sensitive=False):
"""
Find sentences containing a specific word/phrase.

Args:
text: Input text (string)
target_word: Word/phrase to search for
case_sensitive: Whether to match case (default: False)

Returns:
List of matching sentences
"""
sentences = []

for line in text.split('\n\n'):
for sent in sent_tokenize(line):
sentences.extend(sent.split('.” '))
matches = []

for sentence in sentences:
if not case_sensitive:
# Case-insensitive search
if target_word.lower() in sentence.lower():
matches.append(sentence)
else:
# Case-sensitive search
if target_word in sentence:
matches.append(sentence)

# Ensure the exact sentence is returned
exact_matches = [match for match in matches if target_word in match]

return exact_matches

example usage

# full_text_file = "The Knowledge Illusio.txt"
# with open(full_text_file, 'r', encoding='utf-8') as file:
# full_text = file.read()

search_word = 'detonation'

first_instance = find_sentences_with_word(full_text, search_word)[0]

```

英文单词有 “一辈子背不完” 的感觉 —— 没办法,英文的词汇库实在是过于丰富。但,这并不是压力,其实是很有趣的大脑体操,反正,经常动脑会防止老年痴呆……

Kindle 上读书的时候,用特定的颜色(比如黄色)标记生词,随后,可以将其导出。(参见:[与 Kindle/Audible 有关的话题](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/kindle.md))。

可以用以下命令,将 epub 电子书转换成 txt 文件:

```bash
pandoc example.epub -t plain --strip-comments --no-highlight -o example.txt
```

3. 获取词汇原形

从文本里拷贝粘贴后整理词汇列表,往往需要一定的处理:

> * 去掉所属格(`’s` 或者 `'s`')
> * 名词或动词的复数转换为单数
> * 动词的现在分词、过去式、过去分词转换为动词原形

这些可以用 `nltk.stem` 里的 `WordNetLemmatizer` 做

```python
# Ensure the necessary NLTK data packages are downloaded
# nltk.download('wordnet')
from nltk.stem import WordNetLemmatizer

def get_base_form(word, pos):
lemmatizer = WordNetLemmatizer()
if word.endswith("’s") or word.endswith("'s"):
word = word[:-2]
if pos == 'v.':
return lemmatizer.lemmatize(word, 'v')
elif pos == 'n.':
return lemmatizer.lemmatize(word, 'n')
else:
return lemmatizer.lemmatize(word)
```

4. 用免费或付费的 AI 获取词汇词性以及词汇在例句中的释义

```python

lmstudio could be downloaded from https://lmstudio.ai/

# Configuration
API_URL = "http://localhost:1234/v1/chat/completions"
HEADERS = {
"Content-Type": "application/json",
"Authorization": "Bearer lm-studio" # Authorization may not be required
}

def generate_response_lmstudio(prompt, max_tokens=5000, temperature=0.2):
# Once used: Llama-3.3-70B-Instruct-Q4_K_M.gguf
payload = {
"model": "local-model", # Model name shown in LM Studio (arbitrary)
"messages": [
{"role": "user", "content": prompt + '\n Provide answer directly and with no further explaination.'}
],
"temperature": temperature,
"max_tokens": max_tokens,
"stream": False # Set to True for streaming responses
}

try:
response = requests.post(API_URL, json=payload, headers=HEADERS)
response.raise_for_status()
return response.json()['choices'][0]['message']['content']
except Exception as e:
return f"Error: {str(e)}"

def generate_response_openai(prompt, max_tokens=5000, temperature=0.15):
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI(
)
try:
response = client.chat.completions.create(
model="gpt-4o-mini", # You can choose the engine you want to use
messages=[
{
"role": "system",
"content": "You're a helpful assistant. You answer user's prompt directly, with no futher explanations."
},
{
"role": "user",
"content": prompt
}
],
max_tokens=max_tokens,
temperature=temperature
)
return response.choices[0].message.content
except Exception as e:
return f"Error: {str(e)}"

```

BetterTouchTool

BetterTouchTool 是个功能非常强大的软件,通过设置键盘和触摸板的快捷方式,可以实现很多细琐但又重要的功能。把它设置成系统登录时自动登录,而后,它就安静地躲在工具条上,随时帮你做些事情。

```bash
brew install bettertouchtool
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/btt-setting.png)

—— `Luanch BetterTouchTool on startup` 之前打勾。

在它众多的功能之中,我使用最为频繁的是用它设置快捷键去控制程序窗口,比如,用键盘控制当前正在使用的程序窗口,让它靠近左半边放大,或者靠右占屏 ⅓,将窗口挪到另外一个显示器,或者另外一个桌面等等……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/btt-keyboard-shortcut.png)

在这张设置截图里,就能看到我是为每个动作设置了哪个快捷键的,比如,`⌥⌘→` 就是我用来把窗靠右边占屏 ⅓ 的快捷键。我依次为屏幕二分、三分、四分设置了不同的快捷键。每个快捷键都多试几遍,就基本上能记住了。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/btt-touchpad.png)

在这张截图里,是我为触摸板设置的几个动作快捷方式。需要说明一下的是 TipTap Left(2 Fingers Fix),是这样一个动作:

> * 三指轻放在触摸板上(我用食指、中指、无名指)
> * 在中指和无名指不动的情况下,抬起食指,轻点一下触摸板

TipTap Middle(2 Fingers Fix),是这样一个动作:

> * 三指轻放在触摸板上(我用食指、中指、无名指)
> * 在食指和无名指不动的情况下,抬起中指,轻点一下触摸板

我用这两个动作替代了系统的三指左划和三指右划 —— 这在浏览器中相当于是「上一页」和「下一页」,挺省心省力的。

它的设置可能看起来比较麻烦,不过,你需要做的只不过是:

1. [购买一个付费许可](https://folivora.ai/buy),我买的是 LIFE TIME LICENSE,$20.5;
2. 下载并导入[我的 presets](https://raw.githubusercontent.com/xiaolai/apple-computer-literacy/main/files/xiaolai.bttpreset)(使用鼠标右键,选择 `Save as...`),voila! 你一下子多了很多快捷键可用……

另外,说到「窗口管理」,一个必须设置的就是拖动窗口的快捷方式。在 Mac 上,我更习惯使用触摸板而不是鼠标。所以,「三指拖动窗口」对我来说,是必需的功能设置。`System Preferences → Accessibility → Pointer Control → Trackpad Options... → Enable dragging → three finger drag`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/three-finger-drag.png)

另外,在多个 Desktop Space 之间切换有系统内建的快捷键:

> * `⌃ ←` 或在触摸板上四指左滑,切换到前一个 Desktop Space
> * `⌃ →` 或在触摸板上四指右滑,切换到后一个 Desktop Space
> * `⌃ ↑` 或在触摸板上四指上滑,切换到 Misson Control 模式,查看所有窗口和 Desktop Space
> * `⌃ ↓` 或在触摸板上四指下滑,返回当前 Desktop Space

[点击这里](https://support.apple.com/en-hk/guide/mac-help/mh14112/mac)查看 Desktop Space 的官方说明。

控制计算机

1. 两种方式

一个计算机用户 “控制” 计算机的方法,粗略可以划分为两种:

> * 图形界面交互
> * 文本界面交互

我们平日里用的各种应用程序,无论是在台式机上还是在移动设备上,绝大多数都是图形界面交互(GUI),通过指针设备(鼠标、触摸板、甚至手指)指指点点就可以完成大部分操作。这些应用程序都是包装好,面向普通用户设计的,一方面为的是提高效率,另外一方面是为了降低用户的 “学习门槛” —— 毕竟,使用文本界面进行交互,被认为是 “专家” 才去做的事情。

2. 文本编辑器

Dock

Dock 上一排图标大多数情况下并没有实际的用处 —— 除了碍眼之外。LaunchPad 都是没用的,因为打开程序什么的,基本上都是用 Spotlight 完成(或者用 Alfred 替代)。最近打开的程序,被固定在 Dock 上更是讨厌。

在 `System Preference > Dock & Menu Bar` 里,把 `Show recent applications in Dock` 前面的勾去掉:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/dock.png)

然后在 Terminal 里执行以下命令:

```bash
defaults write com.apple.dock persistent-apps -array; killall Dock
```

…… 一下子清爽了!

关于 MacOS 的各种 “默认设置”,参见:

> https://macos-defaults.com/

电子表格简明进阶教程

电子表格几乎可以称作是计算机时代里「最伟大的发明之一」—— 因为它使得绝大多数普通人瞬间拥有了与数学家一样的「算力」。

举个例子,$2^2 = 4$ 或者 $3^3 = 27$ 上过小学的人都能算出来(其实是背出来的),可是,$2.5^{3.2} = ?$ 我们的大脑直接宕机了 —— 别说我们普通人了,数学家的脑子也一样会宕机…… 用电子表格就简单了,无非是 `=power(2.5, 3.2)`,等于 `18.76756928`。在没有电子表格之前,我们就是束手无策啊!

事实上,在斐波那契于 1202 年发表《计算之书》之前,欧洲人还在使用罗马数字,你可以想象一下,没有小数点的时代里,人们计算利息或者汇率有多麻烦甚至不可能?在阿拉伯数字成为人类计算的通用工具之后,要再过将近五百年,才有幂运算的出现;直到 19 世纪上半叶,法国数学家拉克洛瓦(S. F. Lacroix)在他出版的《代数学》讨论了同底数幂的乘法法则之后,指数律才开始出现于任何一本代数教科书中…… 今天,人们在初中的时候就已经学习幂运算了 —— 不过,实际上,大多数人在生活中很少真的去用,虽然其实它总是最必须的计算工具之一。

说明

Github 的 markdown 不支持 LaTeX 数学公式,所以,在 GitHub 上大家会看到诸如 `$2^2 = 4$` 这样的 inline LaTeX。如果你使用类似 [Typora](https://typora.io/) 这样的 Markdown 编辑器打开的话就可以看到正确的数学表达式。当然,在 Typora 中也需要设置,勾选`Inline Math (e.g: $\LaTeX$)`:

[〔图:Typora Settings〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/typora-settings.png)

另外,也可以直接查看 [README.pdf](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/README.pdf) 查看正确显示的内容。

> 注:当前这个教程中使用的是 [Google Spreadsheets](https://docs.google.com/spreadsheets/),MAC 上的 Numbers 引入外部数据很受局限,而 Windows 上 Microsoft Office 套件中的 Excel 虽然也有[一整套的外部数据导入方式](https://support.microsoft.com/en-us/office/import-data-from-external-data-sources-power-query-be4330b3-5356-486c-a168-b68e9e616f5a),但相对更加麻烦(还得学它那个比较令人讨厌的 VBA)……

1. 简单幂运算

做投资的人最需要幂运算 —— 当然,也是因为加减乘除反正谁都会。

如果一个投资标的可以做到年化复合回报率 15%,那么,一百年后,它为投资人创造了多少倍的回报呢?—— 还别说,真有这样的投资标的,2019 年的时候,可口可乐公司上市一百周年。人们算了一下,在这一百年间,可口可乐公司竟然为股东创造了 15% 的年化复合回报率!

> $(1 + 15\%)^{100} = ?$

在电子表格里的某个单元输入以下公式:`=power((1+15%), 100)`,而后就会得到结果:`1174313.451` —— $117.4313$ 万倍!在一百年的时间里,可口可乐公司为股东创造了 117 万多倍的投资回报!

反过来,若是你想知道能给你在10 年里创造 20 倍的投资标的应该做到多少的年化复合回报率呢?

如果我们想做到 $n$ 年 $m$ 倍的投资回报,那么年化复合回报率 $x$ 应该是多少呢?

> $\because (1 + x)^n = m$
>
> $\therefore x = \sqrt[n]{m} - 1 $

写到电子表格里就是 `x = POWER(m, 1/n) - 1`

10 年里创造 20 倍的投资标的应该做到多少的年化复合回报率呢?我们只需要在电子表格的某个单元输入以下公式:`=power(20, 1/10) - 1` ,会得到 `0.3492828477`,也就是说,得做得到年化复合回报率 $35\%$ 左右的投资标的才能让你赚到 10 年 20 倍…… 10 年 10 倍呢?大约需要做到 $26\%$(即,`0.2589254118`)。

总结一下:

> * `POWER(x,y)` 就相当于是 $x^y$;
> * `POWER(x, 1/y)` 就相当于是$\sqrt[y]{x}$

2. 定投收益率计算

某一个特定的起始金额用 `POWER(x,y)` 就足够了,可若是计算定投,就不够了…… 因为金额可能随时增加。这样的时候,就得用其它公式了,比如

> `FV(rate, nper, pmt, pv, type)`

FV 是 Future Value 的缩写。它适合用于基于固定利率和等额分期付款方式,返回某项投资的未来值。

`FV` 函数有 5 个参数,分别如下:

> * rate,贴现率、利率、或收益率
> * nper,期数,年、月、日都可以(如果以月为期,那么,rate 应该是月息);
> * pmt,投入金额,也就是每期流入的现金
> * pv,现值,也就是初期投入的现金
> * type,数字 0 或 1,用以指定各期的付款时间是在期初还是期末。如果省略 type,则假设其值为零。

[〔图:fv〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/FV.png)

**注意**:

> 在电子表格的财务公式中,支出用**负数**,收入用**正数**。

当我们想知道如果我要 $n$ 期后得到资金 $m$,那么每个月要投入多少钱 $x$?那么,要用 PMT 函数(PMT 是 PayMenT 的缩写):

> `PMT(rate, nper, pv, fv, type)`

[〔图:PMT〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/PMT.png)

3. 定期不定额的收益率计算

电子表格里还有个很厉害的财务函数,用来计算不定期、不定金额、可以包含收支的收益率计算公式,`IRR(Internal Rate of Return)`和` XIRR`。

假设在 20 年时间里,你一直每年购买某支股票,每年购买两三千元之间,有些年份里会收到一些股息 —— 这相当于是「定期不定额」—— 到了第 20 年,你手中的股票价值为 962,583,那么,这些年来你的投资复合年化回报率是多少呢?`IRR` 公式很简单,就是把这些年的现金流罗列出来后,用 `=IRR(xx:yy)` 算出来:

[〔图:IRR〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/IRR.png)

电子表格计算的结果是,25.78%。

4. 不定期不定额的收益率计算

一般来说,人们在投资的时候,很难非常准时地以一年或者一月买入或者卖出,相当于「不定期不定额」—— 那么就可以用 XIRR 公式去计算总收益率。`XIRR`公式很简单,就是 `=XIRR(现金流,日期流)`

[〔图:XIRR〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/XIRR.png)

如此一通操作之后,总收益率是 $77.98\%$。

> 另,经 [@luownpeng](https://github.com/luowenpeng) 提醒,使用 `XIRR` 函数有一个注意事项:
>
> > The series of values must contain at least one positive and one negative value.
> >
> > (现金流数据)要包含至少一个正值以及一个负值……

5. 引入外部数据

有时我们希望电子表格中的某个数据可以实时引用网络上的外部数据。比如,你可能想要在[BigONE](https://big.one) 这个交易所上正在交易的 XIN 的实时价格……

5.1 ImportXML

Google Spreadsheets 里内建了一个 `ImportXML()` 函数,它可以让你获取任意网页里的任意数据。

比如,如果我们想要获取 Coinmarketcap 上的比特币实时价格数据,那么,我们用浏览器打开 https://coinmarketcap.com/currencies/bitcoin/markets/ 就可以看到。如果我们用鼠标右键点击价格数据之后,选择 `Inspect` 的话,看到的是这样的:

[〔图:coinmarketcap-inspect〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/coinmarketcap-inspect.png)

`ImportXML()` 使用 XPath 语法获取数据,现在我们要获取的是这个网页里,`class` 为 `priceValue___11gHJ` 的 `div` 区块里的数据…… 那 `ImportXML()` 要写的内容也没多复杂:

> `=IMPORTXML("https://coinmarketcap.com/currencies/bitcoin/markets/", "//div[contains(@class, 'priceValue___11gHJ')]")`

如此这般,我们获得的是一个字符串,如上图网页中所显示的那样,是 `$29,228.84` 。可我们想要的是可用来计算的价格数值,而非一个字符串 —— 那怎么办?再套上一个 `value()` 函数就可以了:

> `=value(IMPORTXML("https://coinmarketcap.com/currencies/bitcoin/markets/", "//div[contains(@class, 'priceValue___11gHJ')]"))`

另外,想要深入学习 XPath 的话,可以参照 [w3schools 上的 XPath 教程](https://www.w3schools.com/xml/xpath_intro.asp)。

5.2 ImportJSON

网络上,很多动态数据网站都提供 API,它们一般使用 *json* 数据格式。比如,[BigONE](https://big.one) 就是是有 API 的:

> https://open.big.one/docs/api.html

[通过翻阅文档](https://open.big.one/docs/spot_asset_pair_trade.html),大致可知 XIN-USDT 的 json 数据链接如下:

> https://big.one/api/v3/asset_pairs/XIN-USDT/ticker

这个链接返回的是一个 *json* 数据包:

```json
{"code":0,"data":{"asset_pair_name":"XIN-USDT","bid":{"price":"128.34","order_count":1,"quantity":"0.301"},"ask":{"price":"130","order_count":1,"quantity":"1.51772"},"open":"128.34","high":"130.1","low":"124.83","close":"130","volume":"22.32818","daily_change":"1.66"}}
```

有太多大括号嵌套,乃至于这样根本看不清楚嵌套关系…… 幸亏网上有很多工具,比如,[Code Beautify](https://codebeautify.org/jsonviewer)…… 用它处理一下好了。

[〔图:code-beautify〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/code-beautify.png)

—— 哦!原来可以调取 `/data/close` 里的数据就可以了……

> 另,经 [@HarryYC](https://github.com/HarryYC) 提醒,还有个很方便的 Google Chrome 插件可以用来查看 json 数据,[jsonView](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc/related?hl=en)。

对于 json 数据,有个外部公式,叫做 `ImportJSON`,在电子表格的单元格里,它是这么写的:

> `=ImportJSON("https://big.one/api/v3/asset_pairs/XIN-USDT/ticker", "/data/close","noHeaders")`

不过,现在还不能显示正确,因为 ImportJSON 是个外部工具([你可以在 Github 上查看它的仓库](https://github.com/bradjasper/ImportJSON)),所以你需要做些额外的设置:

> 1. 点击 `Tools` 菜单,选择 `Script Editor`;
> 2. 点击 `Create script for Spreadsheet`;
> 3. 删除掉编辑器里的代码,替换成[这个脚本的代码](https://raw.githubusercontent.com/bradjasper/ImportJSON/master/ImportJSON.gs);
> 4. 将脚本名称更换为 `ImportJSON.gs`,并点击保存按钮;
> 5. 再返回电子表格之后,即可在任意单元格里使用 `ImportJSON()` 函数了……

当然,为了计算时不出意外,导入的数据,还是要用 `value()` 转换一下:

> `=value(ImportJSON("https://big.one/api/v3/asset_pairs/XIN-USDT/ticker", "/data/close","noHeaders"))`

6. 示例表格

以上教程中的所有公式和数据,都可以在保存于 Google Spreadsheets 上的《[电子表格简明进阶教程示例表格](https://docs.google.com/spreadsheets/d/1WLWukDdHPMt3Zx19bROMAJkM8PVS46TKiYFwyk7vC1Y/edit?usp=sharing)》内看到。

把屏幕变成 “墨水屏”

长时间面对屏幕写作的时候,眼睛的确容易累。在非编程的场景下,黑白屏幕可能更舒服 —— 因为蓝光就是最重要的伤眼因素。编程的场景下,不太适合用 “墨水屏”,因为代码高亮(用各种颜色区分文本)还是很管用的。

macOS 系统有个快捷键,`Option + Command + F5`,可以呼出 Accessibility Shortcuts 对话框:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/accessibility-shortcuts.png)

`Vision` 区里的 `Color Filters` 之前的勾选,就是用来在 “彩色/黑白” 模式中切换的。

如果还嫌麻烦,可以用以下命令安装 [Grayscale](https://github.com/brettferdosi/grayscale),一个可以驻留在工具栏的小工具,可为 “彩色/黑白” 模式切换设置快捷键,比如 `Shift + Option + Command + Space`:

```bash
brew install --cask --no-quarantine brettferdosi/tap/grayscale
```

安装完毕之后,还可以去 `System Preference > Login Items` 里把 Grayscale 这个应用添加到 `Open at Login` 列表中去。

另外,iOS 里也有 `Color Filters` 开关,在 `System Preference` 里搜索 `Color Filters` 即可找到。

另外,无论是 macOS 还是 iOS,现在都可以用 Shortcuts 创建快捷方式:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/toggle-color-filters.png)

而后将快捷方式 pin 到 Menubar 上(maOS),或者放置到屏幕上(iOS),也很方便。

另外,根据研究,Dark Mode 的确对护眼更有帮助 —— 毕竟黑色(深色)背景几乎不回反光。有一个 Alfred Workflow,可以用来设置快捷键,键盘切换 Light Mode 和 Dark Mode:

> https://github.com/mermaid/alfred-dark-mode-toggle

也就是说,Grayscale 和 Dark Mode 组合,可能更好一些。

Jupyterlab

我写《自学是门手艺》的时候,就是用 Jupyterlab 写的 —— 因为在写作的过程中要确保所有的代码都是真正能够正确执行的。在没有 Jupyterlab 之前,写一本编程书籍出版之后,读者们几乎必然会遇到「压根就无法正确执行」的代码 —— 读者苦恼,作者其实更苦恼,谁想写出来卖出去的是垃圾呢?

用 Jupyterlab 还可以极方便地编写一些短程序,测试并使用 —— 不仅仅是 Python…… 不过,我在 Jupyterlab 上还真的基本上只用 Python。

-----
**⚠️ 注意**:[Jupyter-Desktop](https://github.com/jupyterlab/jupyterlab-desktop) 已经发行一段时间了,有人觉得它不稳定,我用了一段时间觉得没什么问题。

```bash
brew install --cask jupyterlab
```
手动安装的话,到官网 [Jupyter-Desktop](https://github.com/jupyterlab/jupyterlab-desktop) 下载相应操作系统的版本。以下以 MacOS 版本为例。

将下载文件解压缩,而后将 `JupyterLab.app` 拖入 `Applicatoins` 目录。

双击 `JupyterLab.app` 的图标打开程序,第一次打开的时候,程序界面底部有一行字:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jd-first-open.png)

在随后的对话框里,有一个 `Install` 按钮:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jd-install-bundled-environment.png)

Python 环境安装完毕之后,点击 `Apply & Restart` 重启 `JupyterLab`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jd-be-installed.png)

再次打开的 `JupyterLab` 的首屏底部那行字就没有了…… 有必要的话,以后可以再 `Settings`(设置)里做更改:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jd-reopen.png)

比如,我可能回去设置 `Working directory`(默认的工作目录),以方便地管理我的 notebook 文件:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jd-settings-server.png)

至此,JupyterLab Desktop 就安装完了,开发环境安装彻底傻瓜化了,一键完成。

另外,关于 MacOS 上 `jlab` 命令行工具 `实际上并未安装` 这个 [bug](https://github.com/jupyterlab/jupyterlab-desktop/issues/655) 的解决(其实也谈不上是什么 bug,问题出在[MacOS 系统的读写权限默认设置……](https://github.com/jupyterlab/jupyterlab-desktop/blob/master/troubleshoot.md#macos-write-permission-issues)):

```bash
sudo chmod 755 /Applications/JupyterLab.app/Contents/Resources/app/jlab
sudo ln -s /Applications/JupyterLab.app/Contents/Resources/app/jlab /usr/local/bin/jlab
```

—— 当然,前提是 `.zshrc` 文件里定义过 `/usr/local/bin` 这个系统默认搜寻路径($PATH)。

旧文(纯新手已经没必要这么折腾)

-----

Jupyterlab 是个「服务器端」软件,只提供一个 WebUI,用浏览器访问。这也有点讨厌,因为你经常一不小心就彻底退出浏览器,相当于是不小心就把某个正在工作中的 Jupyterlab 给关掉了。在 MacOS 上运行 Jupyterlab 还有另外一个强迫症患者受不了的地方 —— 你得保持一个 Terminal 窗口开着…… 同样,你经常会一不小心就退出了整个 Terminal,导致 Jupyterlab「被迫退出」。

于是,要折腾一番,才能让这个神器 Jupyterlab 妥帖地听话……

1. 安装 Miniconda

```bash
brew install miniconda
```

如果遇到错误提示说 `... Bad CPU type in executable`(如果你用的是苹果最新 M1 芯片的电脑,可能会这样),那么就用以下命令:

```
softwareupdate --install-rosetta
arch -x86_64 brew install miniconda
```

安装完毕之后,执行以下两条命令:

```bash
conda init "$(basename "${SHELL}")"
exec zsh
```

> miniconda 的安装脚本,是在最开头提醒你的:
>
> ```shell
> ==> Caveats
> Please run the following to setup your shell:
> conda init "$(basename "${SHELL}")"
> ```
>
> 可后来的消息很快滚了两屏之后,你「好像是没有看到一样」—— 所以,以后得养成好习惯:
>
> > 耐下性子浏览一遍那些「天书」一样的消息……

而后,你可以用 `which conda` 命令看看安装是否成功。如果成功,你会看到这样一串消息:

```bash
conda () {
\local cmd="${1-__missing__}"
case "$cmd" in
(activate | deactivate) __conda_activate "$@" ;;
(install | update | upgrade | remove | uninstall) __conda_exe "$@" || \return
__conda_reactivate ;;
(*) __conda_exe "$@" ;;
esac
}
```

以后,你可以用 `brew upgrade miniconda` 保持 Miniconda 处于最新状态。

2. 为 Jupyterlab 创建一个虚拟环境

作为新手,先别管啥叫「虚拟环境」,只管先照着做就是了。

```bash
conda create -n jupyter python ipython jupyterlab nodejs
conda activate jupyter
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/conda-venv-jupyter.png)

如果你的 Terminal 安装过 Powerlevel10K Theme,那么,命令行的提示符,会提醒你当前处于 jupyter 这个虚拟环境之中……

现在可以测试一下 Jupyterlab 了:

```bash
jupyter lab
```

稍等片刻,浏览器会自动打开,向你展示 Jupyterlab 的 WebUI……

在 Terminal 中用快捷键 `⌃ c`(Control 和 c)终止当前正在运行的程序。

3. 创建一个配置文件

```bash
jupyter notebook --generate-config
```

生成的配置文件保存在 `./jupyter/` 文件夹中,用 Sublime Text 打开 `jupyter_server_config.json` (当然,你用系统自带的免费的但愚蠢的 Text Edit 也行),把 `password` 改成空字符串:

```json
{
"ServerApp": {
"password": ""
}
}
```

以上步骤也可以用 `echo` 命令替代:

```bash
cat <<EOF > $HOME/.jupyter/jupyter_server_config.json
{
"ServerApp": {
"password": ""
}
}
EOF
```

4. 创建两个服务文件

第一个文件

```bash
subl /opt/homebrew/bin/jupyterservice
```

拷贝粘贴以下内容到这个文件,并保存:

```shell
#!/bin/zsh
PATH="/opt/homebrew/Caskroom/miniconda/base/bin:$PATH"
eval "$(conda 'shell.zsh' hook)"
conda activate jupyter
cd ~
/opt/homebrew/Caskroom/miniconda/base/envs/jupyter/bin/python -m jupyter lab --no-browser
```

以上两个步骤也可以用 `echo` 命令替代:

```bash
cat <<EOF > /opt/homebrew/bin/jupyterservice
#!/bin/zsh
PATH="/opt/homebrew/Caskroom/miniconda/base/bin:$PATH"
eval "$(conda 'shell.zsh' hook)"
conda activate jupyter
cd ~
/opt/homebrew/Caskroom/miniconda/base/envs/jupyter/bin/python -m jupyter lab --no-browser
EOF
```

然后再执行一条命令

```bash
chmod +x /opt/homebrew/bin/jupyterservice
```

第二个文件

```
subl ~/Library/LaunchAgents/com.jupyter.lab.plist
```

拷贝粘贴以下内容到这个文件,并保存:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.job</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/jupyterservice</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/local.job.err</string>
<key>StandardOutPath</key>
<string>/tmp/local.job.out</string>
</dict>
</plist>
```

以上两个步骤也可以用 `echo` 命令替代:

```bash
cat <<EOF >~/Library/LaunchAgents/com.jupyter.lab.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.job</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/jupyterservice</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/local.job.err</string>
<key>StandardOutPath</key>
<string>/tmp/local.job.out</string>
</dict>
</plist>
EOF
```

5. 启动服务

```bash
launchctl load ~/Library/LaunchAgents/com.jupyter.lab.plist
```

如此这般,Jupyterlab 就作为服务在后台运行了,以后每次重新启动的时候它都会跟着静悄悄地自动启动。

现在,你随时可以在任何浏览器中打开网址:`http://localhost:8888` —— 你可以把某个浏览器当作 Jupyter 专用,反正浏览器软件那么多。

如果你想重新启动 Jupyter 服务,那么:

```bash
launchctl unload ~/Library/LaunchAgents/com.jupyter.lab.plist
launchctl load ~/Library/LaunchAgents/com.jupyter.lab.plist
```

如果你想方便一点,不想每次都到这个文档里拷贝粘贴命令,那么,在 `~/.zshrc` 文件末尾添加如下几行:

```shell
# for jupyter
alias jpu="launchctl unload ~/Library/LaunchAgents/com.jupyter.lab.plist"
alias jpl="launchctl load ~/Library/LaunchAgents/com.jupyter.lab.plist"
alias jpr="jpu && jpl"
```

而后通过 `exec zsh` 重新启动 zsh…… 现在,你在 Terminal 里可以使用三个新命令了:

```bash
jpu # 停止 jupyter 服务
jpl # 启动 jupyter 服务
jpr # 重启 jupyter 服务
```

这下你学会了,`alias` 就是「自定义缩写」。`exec zsh` 实在太常用了,想不想少敲些字符呢?我想。于是,我的 `~/.zshrc` 文件里就多了两行:

```bash
alias zsr="exec zsh" # 重新启动 zsh
alias zs="subl ~/.zshrc" # 用 sublimetext 打开 ~/.zshrc 文件
```

6. 干脆打包个 App

有个基于 Nodejs 的程序,可以把 Web 服务打包成本地 APP,叫做 [Nativefier](https://github.com/jiahaog/nativefier)。

```bash
conda activate jupyter
npm install nativefier -g
cd ~/Applications
curl https://github.com/xiaolai/apple-computer-literacy/raw/main/images/jupyterlab-app-icon.png --output jupyterlab-app-icon.png
nativefier "http://localhost:8888" -i jupyterlab-app-icon.png
rm jupyterlab-app-icon.png
```

终于,以后我可以这样用 Jupyterlab 了……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jupyter-my.png)

与 Kindle/Audible 有关的话题

1. epub

Kindle 书籍 (`awz3` 文件)是有 DRM 加密的(digital rights management)。但,自己购买的书,还是有办法解密并转换成 epub 格式,只不过,麻烦一点,贵一点。

首先是得购买一个 Kindle 物理设备 —— 这样你才会有一个 `Serial Number` —— 在设备的设置中,或者 Amazon 的 [Device Managment](https://www.amazon.com/hz/mycd/digital-console/alldevices) 页面中能够找到。

我用的是收费软件 [ePubor](https://www.epubor.com/)。在它的设置中,填写你的 `Kindle Device Serial Number`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/epubor-kindle-sn.png)

而后就可以用 Epubor 将自己购买的书籍从 `awz3` 文件转换为 `epub` 格式了;至于已购书籍文件,可以在 Amanzon 网站中的 [Content Management](https://www.amazon.com/hz/mycd/digital-console/contentlist/allcontent/dateDsc) 中下载。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/awz3-download.png)

如果需要批量下载自己购买过的书籍,可使用这个仓库里的软件:

> https://github.com/yihong0618/Kindle_download_helper
>
> 该软件使用方法可以[参见这里](https://cloud.tencent.com/developer/article/2188172)。

2. mp3

收费软件 [OpenAudible](https://openaudible.org/) 可以经过 Amazon 登录授权之后,将所有已购有声书下载到本地,并将其转换成 `mp3/m4a/m4b` 格式。

3. Calibre

我自己是用命令行的 pandoc 处理 `epub` 格式转换(比如转换成可编辑的 html),但,更多人可能需要图形界面,那就只能是 [Calibre](https://calibre-ebook.com/) 了。

```bash
brew install --cask calibre
```

有了 [DeepL](https://www.deepl.com) 之后,我购书不再只限于英文了,因为任何语言的书都可以转换格式之后提交 DeepL 自动翻译,还可以写脚本处理文本渲染格式。

4. Whisper

Whisper 是 [OpenAI](https://openai.com) 推出的语音转换文字的人工智能工具包,支持很多种语言。在 github 上,有一个项目,[Whisper Auto Transcribe](https://github.com/tomchang25/whisper-auto-transcribe),在本地机器上配置好 Python 环境之后,就可以用这个软件为 `mp3` 有声书配上 “字幕”(`srt`、`vtt` 格式)。在我的 Macbook Air M2 上,文字转换时间大约比有声书的总时长稍微短一点,如果有条件用 GPU 加速的话,一本 14 小时的书,差不多 40 分钟就能弄完。

5. iina

[iina](https://iina.io/) 是一款基于 [mpv](https://mpv.io/) 的媒体播放器,界面很好看。

```bash
brew install --cask iina
```

在 iina 的设置里,`iina → Settings → Advanced`:

* 开启 `Enable advanced settings`
* 勾选 `Use config directory`

创建 mpv 的设置文件,在 `~/.config/mpv/mpv.conf` 文件中添加以下内容:

```
[extension.mp3]
profile-desc="profile for audiobooks"
audio-display=external-first
cover-art-auto=all
sub-auto=all
sub-align-x=left
sub-margin-x=100
sub-pos=85
sub-font-size=50
save-position-on-quit=yes
stop-screensaver=always
```

播放 `mp3` 有声书的时候,`mp3` 文件、`srt` 文件,以及一个封面图片文件放在同一个目录:

```code
.
├── Basic Economics, Fifth Edition.mp3
├── Basic Economics, Fifth Edition.srt
└── audiobook.png
```

然后用 iina 打开 `mp3` 文件:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/iina-playing-audiobook.png)

有用的快捷键:

* 转到上一条字幕位置: `Shift + Left`

* 转到下一条字幕位置: `Shift + Right`
* 音乐播放模式转换: `Option + Command + m`
* 放大窗口: `Command + =`
* 缩小窗口: `Command + -`

6. Kindle Annotations

在 Kindle 上,阅读过程中做的各种标记(Annotation),官方一直没有给出很好的导出方法(移动版上有通过邮件方式导出的方式 —— 真不知道开发者怎么想的)。

但,可以通过访问 https://read.amazon.com/notebook ,然后再手动拷贝出某本书的标记,而后保存为 `.html` 文件,再想办法用 python 处理…… 虽然有点麻烦,但也没啥办法,我一直这么做 —— 具体步骤如下图所示:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/kindle-annotations.png)

我用以下函数提取特定颜色的标记文本(默认选择 `yellow`):

```python
from bs4 import BeautifulSoup

def extract_kindle_annotations(file_path, color="yellow"):
# Read the HTML file
with open(file_path, 'r', encoding='utf-8') as file:
html_content = file.read()
# Parse HTML with BeautifulSoup
soup = BeautifulSoup(html_content, 'html.parser')
# Initialize lists to store annotations and their colors
annotations = []
# Find highlights for current color
highlights = soup.find_all('div', class_=f'kp-notebook-highlight-{color}')
# Extract text from each highlight
for highlight in highlights:
annotations.append(highlight.get_text().strip())
return annotations
```

----

Miscellaneous

1. 鼠标点击任何位置移动窗口

从 MacOS High Sierra 开始,可以将窗口移动动作设置为 “用鼠标点击窗口任意位置进行拖动”(而非 “必须通过点击并拖动窗口标题栏”)—— 就好像是在 Linux 操作系统那样……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/moving-windows.gif)

在 Terminal 中输入:

```bash
defaults write -g NSWindowShouldDragOnGesture -bool true
```

而后重新登录系统。

取消以上操作的方式是,在 Terminal 中输入:

```bash
defaults delete -g NSWindowShouldDragOnGesture
```

2. 特殊文件夹图标

在用户根目录下 `~` 创建一个文件夹,名为 `Developer`,而后在 Finder 中将其拖至侧边栏,将得到一个画有系统内建图标的文件夹图标 —— 更多,请参见[这篇文章](https://weblog.antranigv.am/posts/2023/02/hardcoded-folder-icons-in-macos/)。

Microsof Edge Browser

微软的浏览器,Edge,是基于 Google 的 Chrome 制作的。最近的新版本中,Edge 推出了基于 AI 的「自动朗读文本」…… 这其实并不是一个新鲜功能 —— IBM Voice 推出(1997)到现在都已经 24 年了…… 当时在 Windows 95 上试用这个功能的时候,纯粹是「鸡肋」的感觉。

[〔图:1〕](https://user-images.githubusercontent.com/152970/133545201-a3b90e34-2fcc-4920-a263-ba38f1e95cce.png)

然而,这一次的确不一样,从用户的角度,它不仅实用,而且真的很好 —— 起码,朗读已经基本上听不出「机器口音」了。

试用了一下之后,马上因为这个功能从各种浏览器中直接迁徙到了 Edge 上。想想微软也是很奇葩,弃用 Windows 的我在十年之后,发现手中用的东西,微软的还挺多,比如,github,vscode, 还有现在的这个 edge…

这个文本朗读功能(Read Aloud)在几天之内就彻底改变了我的新闻阅读习惯 —— 从过去「主要看新闻」直接变成了「只听新闻」…… 尤其是我现在整天站在工作台前的走步机上,更使得我喜欢这个文本朗读功能。

> 注意,经过一段时间的推荐和使用才发现,系统的地区设置如果是「中国」的话,朗读功能里的声音列表就没有「Natural」(自然语音)—— 所以,得在系统设置里把 Location 改成其他地方,比如 United States。
>
> 如果这还不起作用,那么清空一下本地的 DNS Cache,在 Terminal 里执行以下命令:
>
> ```bash
> sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder.
> ```

后来,我干脆用 BetterTouchTool 设置了个快捷键,`Ctrl + R`,用来完成以下几个步骤:

> 1. 进入 Immersive Reading Mode
> 2. 打开 Read Aloud
> 3. 把浏览器窗口大小调整一下,变成一个长条… 文本朗读功能是有「自动翻页」,但,若是窗口小一点,偶尔看一眼文本的时候更方便… 你自己试试就知道了。

BetterTouchTool 现在是收费软件了(有 45 天试用期),但,它和 Alfred(也是收费软件)、Divvy 是我用 Mac 的必需 —— 没它们的电脑我都不敢想象该怎么使用……

1. 先添加一个快捷键,将其设置成 `^R` —— 也就是 `Ctrl + R`;

[〔图:2〕](https://user-images.githubusercontent.com/152970/133545519-55a7f92a-c442-43c1-9ae7-f8b02738e3f5.png)

2. 让 BetterTouchTool 将 `F9` 这个快捷键发送至 Microsoft Edge

[〔图:3〕](https://user-images.githubusercontent.com/152970/133545522-f77894f3-4768-4f45-aef0-fe113b408a40.png)

3. 让 BetterTouchTool 停顿 `2` 秒钟……

[〔图:4〕](https://user-images.githubusercontent.com/152970/133545523-0e933d78-ac0e-434b-b1cd-bd39ff587eb7.png)

4. 让 BetterTouchTool 点击 Microsoft Edge 的菜单,`Tools > Read Aloud > Turn On`,设置的时候,输入的是 `Tools;Read Aloud;Turn On`(注意,这里是区分大小写的!)

[〔图:5〕](https://user-images.githubusercontent.com/152970/133545524-784c8ccb-7840-43ee-b8ba-0f9e1bba7796.png)

5. 让 BetterTouchTool 执行一段 AppleScript,是用来重置窗口位置的:

[〔图:6〕](https://user-images.githubusercontent.com/152970/133545526-c49a6065-e750-4937-b32d-ba1956ab86b6.png)

代码如下:
```applescript
tell application "Microsoft Edge"
set bounds of front window to {0, 0, 800, 300}
end tell
```
就这样。

一些插件插件

Microsoft Edge 是基于 Google Chrome 的,所以,它们的插件是通用的。

有些我常用的插件,罗列在下面:

* [Download All Images](https://microsoftedge.microsoft.com/addons/detail/download-all-images/hpceppbbhmfebdnpaeiififakbogkgfa)
* [EpubReader](https://microsoftedge.microsoft.com/addons/detail/epubreader/gbfdomjljjkagpgdlidoicebkgpienmf?hl=en-US) 用这个插件可以打开 epub 文件,于是,任何电子书,瞬间变成了「有声书」……
* [Alex Traffic Rank](https://chrome.google.com/webstore/detail/alexa-traffic-rank/cknebhggccemgcnbidipinkifmmegdel) 毕竟,很多时候,一个网站的流量和排名,能多少体现出其内容质量。
* [IMDB Ratings for Netflix](https://chrome.google.com/webstore/detail/imdb-ratings-for-netflix/dnbpnlalaijjbogmjbpdkdcohoibjcmp)
* [Markdown Here](https://chrome.google.com/webstore/detail/markdown-here/elifhakcjgalahccnjkneoccemfahfoa)
* [Stylus](https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne) 网页样式自定义,有很多网站没有它的话就真的很难看,比如 [HackersNews](https://news.ycombinator.com/)
* [Wikipedia URL Shortener](https://chrome.google.com/webstore/detail/wikipedia-url-shortener/ioekneldioljahdoiddhikknahbbkhan)

还有个 [bypass-paywalls](https://github.com/iamadamdev/bypass-paywalls-chrome) 可以试试。虽然几乎所有的付费网站我都全年订阅了,我还是会使用这个插件,因为有它就省的我每次都要打开 1Password 去登录了…… 安装得稍微麻烦。方法一,是用官网的

1. 选择一个保存目录,而后用 `git` 先下载源码到该目录中:

```bash
git clone [email protected]:iamadamdev/bypass-paywalls-chrome.git
```

2. 在浏览器的地址栏里输入 `edge://extensions` 到达插件管理页面
3. 点开左下角 `Develop mode` 开关
4. 在右侧顶部点 `Load Unpacked` 按钮,弹出的对话框里,先浏览至插件的目录,而后点击 `Select` 按钮,即可完成安装。

注意:插件文件夹得一直留在那里,删除它等于卸载插件。

还有,Bypass-paywalls 最好和 [uBlock Origin](https://microsoftedge.microsoft.com/addons/detail/ublock-origin/odfafepnkmbhccpbejgmiehpchacaeak) 一起配合使用。

另外,[MD Reader](https://github.com/Heroor/md-reader) 是我最近才开始用的插件。以前没有在浏览器里阅读 Markdown 的必要,但,自从开始用 Edge 的朗读功能之后,一个能在 Edge 里跑的 Markdown 阅读器就成了必需。

1. 选择一个保存目录,而后用 `git` 先下载源码到该目录中:

```bash
git clone https://github.com/Heroor/md-reader.git
cd md-reader
npm install
npm run build
```

2. 与上面安装 by-passwalls 一样,`Load Unpacked`(浏览并选择至 `md-reader/extension`目录)
3. 我会修改一下 Markdown 显示的样式,css 文件在 `extension/css/content-script.css`;修改完之后,重新启动 Edge,就可生效。

```css
/* body.md-reader 的 font-family 里,把 "Kaiti SC" 放在最开头*/
font-family: "Kaiti SC", -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;

/* body.md-reader .md-reader__body .md-reader__markdown-content 里同样; */
font-family: "Kaiti SC", -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
/* 加额外加一行:中文排版的一个小秘诀,字符之间有一点点空间,看起来就很舒服 */
letter-spacing: 1px;
/* 楷体字符较小,所以,字号可以放大一点,原本是 15px,改成 18px */
font-size: 20px;

/* 相应地,h1, h2, h3, h4, h5... 字号可能都要调整一下 */
/* 用百分比更好一些(以上面指定过的字号 20px 为基础: */
/* h1: 220%; h2: 200%; h3: 180%... */
/* body.md-reader .md-reader__body .md-reader__markdown-content h1 {...} */
```

常用新闻网站

> * https://www.ft.com/ Financial Times
> * https://hbr.org/ Harvard Business Review
> * https://sloanreview.mit.edu/ MIT Sloan Management Review
> * https://www.reuters.com/ Reuters
> * https://www.scientificamerican.com/ Scientific American
> * https://time.com/ TIME
> * https://www.economist.com/ The Economist
> * https://www.newyorker.com/ The New Yorker
> * https://www.nytimes.com/ The New York Times
> * https://www.wsj.com/ The Wall Street Journal
> * https://www.washingtonpost.com/ The Washington Post
> * https://www.wired.com/ WIRED
> * https://www.worldpoliticsreview.com/ World Politics Review

如何把 Microsof Word 当作白板教学工具?

如何把 Microsof Word 当作白板教学工具?

在教学电子化时代,“板书” 成了令很多老师头疼的事情。

比如,板书的字不好看,写不工整…… 这其实也怪不的这一代的老师,因为这一代老师很可能干脆就用着键盘长大的,用着带有模糊音纠正的拼音输入法长大的,执笔写字不漂亮,其实非常正常。反正这一代人和上一代人不一样,没有被 “写一首漂亮字就可以给首长当秘书” 的段子忽悠过……

差不多十五年前,我在新东方教英语写作的时候,用 Microsoft Word 当作 “板书工具”,学生们见识到之后慨叹,“从来没有见过有人这么用过 Word!” —— 没想到的是,这么长的时间过去之后,“如何把 Microsof Word 当作白板教学工具?” 依然是值得分享的内容。

当年我用的 Windows 操作系统,可现在已经转到 MacOS 多年,所以以下就只演示如何在 Microsoft Word for Mac(version 16.35)中进行设置了 —— 但,无论如何,原理是一模一样的。

打开 Word,关闭所有文档,而后在 Help 菜单下的搜索框中输入 “Editor”,你会看到 “Visual Basic Editor” 菜单跳出并突出显示,直接按回车键(Enter),即能打开 Visual Basic Editor。(呼出 Help 菜单的快捷键是 `Shift + Command + /`)

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/help-editor.png)

在左侧上部 “Project - Normal” 面板中选择 “NewMacros”,而后在右侧 “Normal - NewMacros (Code)” 面板中输入以下代码(或者拷贝粘贴):([vba 文件](https://raw.githubusercontent.com/xiaolai/apple-computer-literacy/main/files/newMacro_for_NomalTemplate.vba))

```vba

Sub Macro_Selection_Font_Color_RED()
Selection.Font.ColorIndex = wdDarkRed
End Sub

Sub Macro_Selection_Font_Color_BLUE()
Selection.Font.ColorIndex = wdDarkBlue
End Sub

Sub Macro_Selection_Font_Color_BLACK_WHITE_SWITCH()
If Selection.Font.ColorIndex = wdWhite Then
Selection.Font.ColorIndex = wdBlack
Else
Selection.Font.ColorIndex = wdWhite
End If
End Sub

Sub Macro_Selection_Highlight_switch()
If Selection.Range.HighlightColorIndex = wdNoHighlight Then
Selection.Range.HighlightColorIndex = wdYellow
Else
Selection.Range.HighlightColorIndex = wdNoHighlight
End If
End Sub

Sub Macro_Selection_Double_Strikethrogh()
Selection.Font.DoubleStrikeThrough = Not Selection.Font.DoubleStrikeThrough
End Sub

Sub Macro_Selection_Set_FontSizeLarge()
Selection.Font.Size = 32
End Sub

Sub Macro_Selection_Reset()
Selection.Font.Reset
End Sub

Sub Macro_Selection_Font_Grow()
Selection.Font.Grow
End Sub

Sub Macro_Selection_Font_Shrink()
Selection.Font.Shrink
End Sub

Sub Macro_Selection_to_Question_Mark()
Dim length As Integer
Dim strTemp As String
strTemp = ""
length = Len(Selection.Text)
For i = 1 To length - 1
strTemp = strTemp + "?"
Next i
Selection.Delete
Selection.InsertAfter (strTemp + " ")
Selection.MoveRight Unit:=wdCharacter, Count:=1
End Sub
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/editor-code.png)

按快捷键 `Command + s` 保存,而后关掉 “Visual Basic Editor”。刚刚完成的是,在 “Normal” 这个模版中添加了 10 个宏。以后,你用 Normal 这个模版创建的所有文档,都自动带有这 10 个宏。在直播中,你有可能会创建新的模版(比如,希望用这个模版新建的文件大小都是定制过的),那么就需要你在新的模版里重新添加 “NewMacros” 才行。

现在,回到主菜单,再次从 “Help” 菜单的搜索框里输入 “keyboard”:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/help-keyboard.png)

按回车键,进入 “Customize Keyboard” 对话框:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/assign-shortcut.png)

在 “Categories” 里找到 “Macros” 并点击,而后右侧的 “Commands” 列表里就能看到你刚刚在 Visual Basic Editor 里面设置的宏。然后,就可以给它们逐一设置快捷键。我的设置是这样的(`⌘` 是 Mac 上的 `Command` 键):

| 宏名称 | 快捷键 | 备注 |
| --------------------------------------------- | ------------- | ------------------------------------ |
| Macro_Selection_Font_Grow | `⌘ 1` | 不断增大选中文本的字体尺寸 |
| Macro_Selection_Font_Shrink | `⌘ 2` | 不断减小选中文本的字体尺寸 |
| Macro_Selection_Highlight_switch | `⌘ 3` | 选中文本在高亮与非高亮之间切换 |
| Macro_Selection_Set_FontSizeLarge | `⌘ 4` | 将选中文本的字体大小设置为 32 |
| Macro_Selection_Font_Color_BLACK_WHITE_SWITCH | `⌘ 5` | 将选中文本颜色进行黑白切换 |
| Macro_Selection_Font_Color_BLUE | `⌘ 6` | 将选中文本颜色设置为深蓝色 |
| Macro_Selection_Font_Color_RED | `⌘ 7` | 将选中文本颜色设置为深红色 |
| Macro_Selection_to_Question_Mark | `⌘ 8` | 将选中文本替换为问号字符串 |
| Macro_Selection_Double_Strikethrogh | `⌘ 9` | 将选中文本加上双删除线 |
| Macro_Selection_Reset | `⌘ 0` | 将选中文本的字体恢复为默认颜色与大小 |

如此这般之后,我就可以在课堂上单手操作很多事情了(即便有时需要两只手也依然相当方便):

> * 将一个段落中的某个重点句子(或者词汇)字体放大、加上颜色、或者高亮;
> * 在 “造句” 或者 “替换” 场景中,先把某些文本设置成 “白色”,观众看到的就是空白,而后选中那些文本,按一个快捷键,就可以将其变成黑色、蓝色、红色,或者再次变回“空白”…… 再进一步还可以加上高亮……
> * 默认情况下,Word 里对加重、倾斜、下划线,分别有快捷键 `Command + b`、`Command + i`、`Command + u`;但,并没有加上双删除线的快捷键;现在,用 `Command + 9` 即可……

以上的 10 个快捷键(宏),使得我在课堂上可以将 Word 当作非常灵活的白板使用……

另外一个细节是,要将 Word 的 View 设置成 “Web Layout” 才好:

[〔图:weblayout〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/weblayout.png)

再进一步,你可以研究一下 “Customize Keyboard” 对话框,值得添加快捷键的功能事实上非常多,不妨根据你自己的需要设置一下。

另外,在 MacOS 上,还有一种方式可以为 Word 设置快捷键 ——尤其为是那种 Word 默认并没有给你设置快捷键的功能,比如,“Word Count...”

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/word-count.png)

打开 “System Preference.app”(点击桌面顶部工具条最左面的苹果图标,就可以找到它),依次选择 “Keyboard” > “Shortcuts”,而后在左边的列表中选中 “App Shortcuts”:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/system-preference-keyboard-shortcuts.png)

点击右边列表下面的那个 “+” 按钮,添加一个快捷键:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/add-app-shortcut.png)

如此这般之后,你就可以随时用 `Command + = ` 查看 “Word Count” 了。

有了这样的设置(或者称为 “定制”)之后,作为老师的你,就会觉得 Powerpoint 相对于 Word 来看,简直弱爆了…… 不是吗?

当然,你还可以酷炫一点,比如,文档背景改成粗糙的黑色,文字颜色根据背景再改一改,再找个好看一点的手写字体,模拟黑板的样子…… 反正,工具谁都有,可善用工具的人可不多。

现在,直播平台基本上都支持 [OBS](https://obsproject.com/) 推流。在 OBS 场景布置中,放一个 “窗口捕捉”,显示 Word 窗口,即可以拥有一个相当方便的 “白板”(或 “黑板”、甚至 “绿板”)。

------
补充:

设置好的 Kyeboard Customization 和 Macro 都共同保存在 `Normal.dotm` 这个模板文件中,在 MacOS 下寻找 `Normal.dotm` 的位置:

```bash
cd $HOME
find . -name 'Normal.dotm' 2>/dev/null
```
将这个文件做个备份,将来万一重新安装了 Word 的时候,用备份替换一下,就不用再设置一遍了。

如何使用 OBS 直播?

[OBS](https://obsproject.com/) 可以将多个可以预处理的输入源有序地拼接在一起而后推流到直播平台上,是教育工作者讲授直播课堂的必备工具。

下载地址:

> https://obsproject.com/

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/obs-usage.png)

1. 预览

打开 OBS 程序,看到的主窗口画面是这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/OBS-first-open.png)

配置好之后的窗口大概是这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/obs-mainwindow.png)

同时按下 `command` 键和 `,` 键,呼出 “Preference” 窗口,在“推流”中设置好服务器和串流密钥(这些参数,要在直播平台生成直播后获得):

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/obs-preference.png)

如此这般之后,就可以开始直播了……

2. 场景设置

所谓场景,就是一组输入源的组合,输入源包括以下类型:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/输入源.png)

你可以根据需求创建多个场景,并且在直播过程中根据需求随时切换场景。

比如,可以设置一个场景,命名为 “开场白” —— 因为自己准备开播需要一定的时间,人家进入直播间也需要一定的时间,所以,就可以用以下输入源拼接成一个场景:

> * 图像
> * 媒体源

这样的话,人们进入直播间,虽然目前尚未开始直播,但可以看到一张海报的同时能够听到背景音乐……

而讲课的时候,若是需要一个书写功能,那么就可以设置一个“板书显示”场景:

> * 窗口捕获
> * 音频捕捉设备

这样的话,当老师切换到这个场景的时候,观众看到的是那个程序窗口(文字输入的时候,我所使用的是 Typora 这个 Markdown 编辑器),以及老师正在讲话的声音。

如果你想要让观众同时看到摄像头面前的你,那么,在以上场景中再添加一个输入源,“视频捕捉设备”,并且可以在预览屏幕上直接调整显示大小:

> * 窗口捕获
> * 音频捕捉设备
> * 视频捕捉设备

需要注意的是,“来源”面板里的输入源,是有先后顺序的。处于最顶端的来源,放在最前面,依次层叠。

3. 需要注意的地方

主要有两个需要注意的地方。

第一个是新手不经提醒就一定会掉进去的坑:

> 在直播的时候,电脑的声音输出要静音 —— 否则,直播中会出现无限循环的回音……

另外一个需要注意的是,从电脑上直播的时候,观众从手机上,只能看到上半屏在直播,可以通过横放手机达到全凭效果;自定义分辨率不一定会成功,因为每个直播平台的处理方式不一样。

4. 一直播直播操作步骤

* 登录网页版 yizhibo.com (注意,最好使用微博登录;这么做的另外一个麻烦就是,你发起直播的时候,微博上就会自动发一条消息)
* 点击“直播管理”,发起直播。
* 配置 OBS 的串流密钥
* 而后在互动生成页面,选择“先审后发”,点 “生成互动模块” 按钮。
* 在 OBS 上 “开始推流”。

技巧:

1. 可以使用按住 ALT 键,crop(剪裁视频源)

https://obsproject.com/forum/threads/camera-size.4585/

2. 窗口捕捉,如果看不到已有窗口列表,那么,System Preference > Security & Privacy > Screen Recording 里面,OBS.app 之前需要打勾。如果 Screen Recording 右侧的列表为空,那么,需要现在 OBS 中,添加一个 Display Capture,会有一个对话框跳出来,让你在 System Preferernce 里面勾选。

待补充

快捷键设置:语音输入一键静音很必要

讲课用来消回音的输入设备,最好的,其实是苹果的 airpod 耳机(不是 pro)

用 iPad 做展示板是最好的选择;Reflector3;DemoPro

在 iPad 上,什么都可以做,Prezi/Keynotes/Powerpoint/Paper....

“prezi,讲 iPhone 作为遥控器” —— Prezi 是“窗口播放”,而不是全屏播放,这点,比 powerpoint、keynotes 更好;Prezi 中文字体问题,解决方案是,用 sketch,直接将文字导出为透明背景的 png,导入 Prezi。

摄像头的位置;

绿幕的使用方法;

Powerlevel10K 的配置

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-1.png)

如果没有安装某一个 Nerd Fonts 的话,那么,这一张和接下来的三张截图里,Diamond、Lock、Debian logo 都不会正确显示,第四张的一系列图标不仅不会正确显示,还会有错接情况…… 直接按 `q` 退出设置脚本,安装好 Nerd Fonts 之后,重新来过……

`y` Yes.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-2.png)

`y` Yes.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-3.png)

`y` Yes.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-4.png)

`y` Yes.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-5.png)

`3` Rainbow. 觉得这个最好看。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-6.png)

`1` Unicode.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-7.png)

`2` 24-hour format. 我喜欢 24 小时的格式。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-8.png)

我选了 `3` Slanted. 样式上来看,`1` 也不错。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-9.png)

`1` Sharp

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-10.png)

`1` Flat. 就是觉得左右对称挺好……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-11.png)

`2` Two lines. 我喜欢 Prompt 出现在第二行,尤其是工作目录比较长的时候,这样才感觉舒适……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-12.png)

`3` Solid. 用一根实线把已执行过的命令隔开。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-13.png)

`4` Full. 还是为了左右对称

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-14.png)

`1` Lightest.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-15.png)

`2` Sparse. 松快一点舒服。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-16.png)

`2` Many icons. 图标多点挺好看的。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-17.png)

`2` Fluent. 多点提示没啥不好。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-18.png)

`y` yes. 既然是特色功能,当然需要。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-19.png)

`1` Verbose (recommended). 既然推荐,那就是它了。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-20.png)

`y` Yes. 这是因为重新设置才有,当然是 Overwrite.

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/p10k-configure/p10k-configure-21.png)

用程序批量填充单元格公式

我现在很少打开 Microsoft Excel 和 Apple Numbers 了,因为它们已经被 Google Spreadsheets 替代。

这些电子表格都一样,提供「自动填充单元格」的功能。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-speadsheets-auto-generate.png)

比如,在上图中,我点击 `J2` 单元格,然后,`J2` 的蓝色边框的右下角有一个方点 —— 我用鼠标点中那个方点,往下拖,那么,在我用鼠标拖出来的范围内,都用 `J2` 单元格的内容填充……

—— 可问题在于,若是我需要填充的单元格多达几百个,甚至更多,鼠标拖拽就很费劲了……

有程序帮忙就方便了。用 Python 写两行代码,就可以很方便地生成无论多少行,比如,我需要 816 行:

```python
for i in range(0, 816):
print(100)
```

将输出结果拷贝粘贴到电子表格里就行了…… 我用 [Jupyterlab](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/jupyterlab.md) 是这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/jupyterlab-spreadsheet-helper.png)

批量生成公式也很简单……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-speadsheets-auto-generate-2.png)

```python
for i in range(2, 816+1):
print(f'=J{i}/I{i}')
```

虽然你可能看不懂程序,但,你可以盯着看一下,把这段代码当作「模版」,然后,根据自己的需求改一改…… 比如,你需要的是 `1056` 行,那你就把上面代码中的 `816` 改成 `1056` 就可以了……

然后拷贝粘贴,几百个单元格就填充完了:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-speadsheets-auto-generate-3.png)

现在,想要算每天的收益率,那就是把 `J` 列的数字合计,就是「累计投资额」,把 `K` 列合计就是当前「累计购买数量」,再乘以 `I` 列的对应价格,就是「当前资产净值」……

> 收益率 = 累计购买数量 x 当前价格 / 累计投资额 - 1

于是,前几行单元格里填充的公式应该是这样:

```json
=SUM(K2:K2)*I2/SUM(J2:J2)-1
=SUM(K2:K3)*I3/SUM(J2:J3)-1
=SUM(K2:K4)*I4/SUM(J2:J4)-1
=SUM(K2:K5)*I5/SUM(J2:J5)-1
=SUM(K2:K6)*I6/SUM(J2:J6)-1
=SUM(K2:K7)*I7/SUM(J2:J7)-1
=SUM(K2:K8)*I8/SUM(J2:J8)-1
=SUM(K2:K9)*I9/SUM(J2:J9)-1
```

这样的时候,你就会沮丧地发现,要填充几百个单元格竟然是「**不可能的**」!—— 因为当你正确写完第一个单元格之后,Spreadsheet 自作聪明地把它替换成了 `=SUM(K2)*I2/SUM(J2)-1`……

然后,就算你把前三行都填充进去,然后,选中这三行,用鼠标拖拽那个方点,你会发现 Spreadsheet 的「自动」完全是乱七八糟的……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-speadsheets-auto-generate-4.png)

Google Spreadsheet 的自动填充(其他的电子表格都一样),只能完成最基本的操作;一旦需要多一点的变量,它就没办法帮你「自动」了……

—— 也就是说,**你不写程序帮你自己的话,这么简单且常用的事儿,你自己竟然无能为力!**

可,用 Python,还是两行就够:

```python
for i in range(2, 817+1):
print(f'=SUM(K2:K{i})*I{i}/SUM(J2:J{i})-1')
```

> 观察一下,这次是从 `2` 开始的,所以,到 `817 + 1` 结束,而不是 `816 + 1`……

然后就瞬间生成了:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-speadsheets-auto-generate-5.png)

拷贝粘贴进去,就完事儿了 —— 这竟然是一个真的拦路虎!到底能拦住多大比例的人群我们无从而知,但,反正过去肯定能拦住你。

也就是说,无论多复杂的公式,你调整一下以上两行 Python 程序的「模版」,反正到最后都能弄出来……

以上的示例表格,可通过这个链接访问:

> [示例表格](https://docs.google.com/spreadsheets/d/1bWtV-J5J4U177DHsa6BtqGdTAGcm7Iy6iOFupW3A3n0/edit?usp=sharing)

epub Plugins for Spotlight

Github Repo:

> https://github.com/GenjiApp/EPUB-Plugins

从 Terminal 开始……

0. Language

系统语言要设置成英文。这样的好处在于,将来你遇到任何问题的时候,出错信息里里外外全都是英文的,于是,就可以直接拷贝粘贴到 Google 里搜索解决方案。不然的话,各种名称都可能因为是中文的而找不到太好的解决方案…… 另外,Region 也干脆设置成 `United States` 算了,因为将来可能还需要用海外账号使用 TV App,和 News App……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/system-preference-language.png)

1. Terminal (1)

打开一个新的 Mac(iMac、Macbook 等等),即便你是新手,要第一个使用的,就是 Terminal 程序。

在新的 Mac 上打开 Terminal 程序的方法有以下几个:

> * 先点击 Dock 上的 Launchpad 图标 [〔图〕](https://help.apple.com/assets/5FDD15EE12A93C067904695E/5FDD15F412A93C0679046966/en_US/a1f94c9ca0de21571b88a8bf9aef36b8.png) ,而后在搜索框里输入 `Terminal`,随后通过点击打开。
> * 在 Finder [〔图〕](https://help.apple.com/assets/5FDD15EE12A93C067904695E/5FDD15F412A93C0679046966/en_US/058e4af8e726290f491044219d2eee73.png) 程序里 ,打开 `/Applications/Utilities` 文件夹,双击里面的 Terminal 程序图标。
> * 使用快捷键 `⌘ Space` 呼出 Spotlight,输入 `Terminal` 而后按 `⏎` 键,即,Return 键。

在 Spotlight 里输入 `ter` 这三个字母的时候,Terminal 已经排在第一位了,这时按下 `⏎` 键,即,Return 键,就可以打开 Terminal 程序。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/spotlight-terminal.png)

我第一次打开 Terminal 的时候是这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/original-terminal.png)

2. Xcode Command Line Tools

在 Terminal 中执行以下命令(或者手动输入进去,或者拷贝粘贴,而后按 `⏎` 键,即,Return 键):

```bash
xcode-select --install
```

而后会跳出一个消息窗口,按提示一步一步做即可 —— 根据你的网速,需要等一段时间才能够完成。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/installing-xcode-commandline-tools.png)

这一步安装,从你的角度来看,好像没发生什么……

还需要再执行一个命令:

```bash
sudo xcodebuild -license
```

3. Oh-my-zsh

在 BigSur 里,Mac OS 使用的默认 Shell,不再是 `bash`,而是 `zsh`,所以,干脆再安装一个 `zsh` 的增强工具,`oh-my-zsh` —— 它将来会提供很多方便:

```bash
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-after-ohmyzsh.png)

等一会儿安装好 Homebrew 之后,我们还可以进一步美化一下 Terminal 以及命令行提示符……

4. Homebrew (1)

以后大量的程序安装、升级、卸载,都靠 [Homebrew](https://brew.sh/) 。

使用同一个工具管理所有软件的下载安装,当然远比一个个打开网站手动下载再安装方便太多了。

但,用 Homebrew 最直接的好处就是,用它可以直接下载并安装必要的连接全网软件,免费的比如 [Shadowsocks-NG-R](https://github.com/qinyuhang/ShadowsocksX-NG-R/releases)、[ClashX](https://github.com/yichengchen/clashX/releases),收费的比如 [Surge](https://nssurge.com/) 等等 —— 没有 Homebrew,你就被限制住了:没有连接全网的软件,所以,无法打开 Google,也无法连接到下载上面提到的三个软件的网站上,然后,死循环……

Homebrew 官方的代码仓库保存在 [GitHub](http://github.com/) 上,在国内很多地方,直接访问 Github 要么直接访问不了,要么非常非常慢…… 所以,安装 Homebrew 的时候,需要「绕行」一下,先用国内镜像安装,然后再切换回官方源。

将以下代码拷贝粘贴到 Terminal 里,而后,按 `⏎` 键,即,Return 键:

```bash
# 使用国内源安装
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"
```

> **注意**
>
> 拷贝粘贴代码的时候,第一行包括进去了也没问题。`#` 这个字符是用来标注注释的,shell 会自动忽略当前行中 `#` 后面的所有内容。
>
> **补充**
>
> 官方源的安装使用以下代码
>
> ```bash
> # 使用官方源安装
> /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
> ```
>
> 另外,如果用的是官方安装脚本,那么,在安装结束之后,要补充执行以下命令:
>
> ```bash
> echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> /Users/$USER/.zprofile
> eval $(/opt/homebrew/bin/brew shellenv)
> ```

第一步选择镜像。我在北京,所以,就输入了 `2`,即,选择了清华大学下载源;随后,输入 `y` 确认开始执行脚本;之后会要求输入 password…… 这个 password 就是你的「开屏密码」(就是打开电脑,或者待机之后重新开机,需要登录的时候,所需要输入的那个密码)—— 在输入密码的时候,你在 Terminal 里看不到之前在图形界面中你所熟悉的对应的星号 `*****`,正确输入之后,按 `⏎` 键即可。如果输入错误,那就多按几次 `delete` 键,确保彻底删除所有已输入字符,重新输入即可。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/brew-install-password.png)

这个安装脚本会在 `.zprofile` 文件里补上一行:`eval $(/opt/homebrew/bin/brew shellenv)`,你暂时忽略这个细节,重新启动 Terminal。

而后,可以用以下命令验证 Homebrew 的安装:

```bash
which brew
brew update
brew doctor
```

实际上,`brew` 的常用命令也没几个,先放在这里,回头再来逐个试几遍……

```bash
brew -v
brew list
brew doctor
brew update
brew upgrade
brew search
brew info
brew cleanup
brew config
```

> **注意**
>
> 我现在用的是基于 Apple Silicon 芯片的 Mac,Homebrew 的安装目录,在基于 Intel Chip 的 Mac 上可能有所不同。Homebrew 的根目录到底是什么,在安装好之后,可以用 `echo $(brew --prefix) ` 查看。

5. VPN Clients

MacOS 上可用的 VPN 客户端,免费的有 Shadowsocks 和 ClashX,收费的有 Surge,都可以通过 `brew` 命令安装。

```bash
brew install shadowsocksx-ng-r
brew install clashx
brew install surge
```

使用 `brew` 命令安装的第三方程序,在系统默认的情况下,会触发警告,比如这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/system-security-warning.png)

于是,需要你在 System Preferences 里设置一下,在 `Allow apps downloaded from:` 之下,选择 `App Store and identified developers` ,然后,按那个 `Allow Anywa` 按钮:

[〔图〕](https://user-images.githubusercontent.com/152970/135500504-6303509f-9f4a-4b1e-8ba8-2a761d7bade1.png)

6. Homebrew (2)

如果你已经购买过 VPN 服务,并且能用以上三个 VPN 程序中的某一个设置好,那么,你应该能够顺畅地连接「外网」了,那么你现在可以把 homebrew 的「源」切换回官方源了 —— 将以下代码拷贝粘贴到 Terminal 里执行:

```bash
# 恢复官方源
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-cask"
git remote set-url origin git://github.com/Homebrew/homebrew-cask.git
# 更新至最新
brew update
# 检查 Homebrew 状态
brew doctor
```

若是看到警告信息,

```bash
Warning: A newer Command Line Tools release is available.
Update them from Software Update in System Preferences or run:
softwareupdate --all --install --force
```

那么,就执行一遍 `softwareupdate --all --install --force` 好了……

如果将来需要切换到国内的源,那么得按照以下方法操作(第一遍操作的时候,请直接跳到下一节开始阅读):

**替换为阿里源**

```bash
# 查看 brew.git 当前源
$ cd "$(brew --repo)" && git remote -v
origin https://github.com/Homebrew/brew.git (fetch)
origin https://github.com/Homebrew/brew.git (push)

# 查看 homebrew-core.git 当前源
$ cd "$(brew --repo homebrew/core)" && git remote -v
origin https://github.com/Homebrew/homebrew-core.git (fetch)
origin https://github.com/Homebrew/homebrew-core.git (push)

# 修改 brew.git 为阿里源
$ git -C "$(brew --repo)" remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git

# 修改 homebrew-core.git 为阿里源
$ git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git

# zsh 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
$ source ~/.zshrc

# bash 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
$ source ~/.bash_profile

# 刷新源
$ brew update
```

**替换为清华源**

```bash
# 替换各个源
$ git -C "$(brew --repo)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
$ git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git
$ git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-cask.git

# zsh 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles' >> ~/.zshrc
$ source ~/.zshrc

# bash 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles' >> ~/.bash_profile
$ source ~/.bash_profile

# 刷新源
$ brew update
```

**替换为中科大源**

```bash
# 替换各个源
$ git -C "$(brew --repo)" remote set-url origin https://mirrors.ustc.edu.cn/brew.git
$ git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git
$ git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git

# zsh 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.zshrc
$ source ~/.zshrc

# bash 替换 brew bintray 镜像
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile
$ source ~/.bash_profile

# 刷新源
$ brew update
```

**重置为官方源**

```bash
# 重置 brew.git 为官方源
$ git -C "$(brew --repo)" remote set-url origin https://github.com/Homebrew/brew.git

# 重置 homebrew-core.git 为官方源
$ git -C "$(brew --repo homebrew/core)" remote set-url origin https://github.com/Homebrew/homebrew-core.git

# 重置 homebrew-cask.git 为官方源
$ git -C "$(brew --repo homebrew/cask)" remote set-url origin https://github.com/Homebrew/homebrew-cask

# zsh 注释掉 HOMEBREW_BOTTLE_DOMAIN 配置
$ subl ~/.zshrc
# export HOMEBREW_BOTTLE_DOMAIN=xxxxxxxxx

# bash 注释掉 HOMEBREW_BOTTLE_DOMAIN 配置
$ subl ~/.bash_profile
# export HOMEBREW_BOTTLE_DOMAIN=xxxxxxxxx

# 刷新源
$ brew update
```

7. Terminal (2)

现在,可以「装修」一下 Terminal 了。

先安装一个字体

```bash
brew tap homebrew/cask-fonts
brew install --cask font-sauce-code-pro-nerd-font
```

设置 Terminal 的字体(目前使用的 Profile 是 Basic)—— 在 Terminal 处于当前焦点的情况下,按快捷键 `⌘ ,` 呼出 Terminal 的 Preferences 窗口,而后,在 Profiles 标签里,点击左边栏的 `Basic`,而后,在右侧 `Text` 标签页里设置 `Font`

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-preference-profile-Basic.png)

在右边的 `Font` 区域,点击 `Change` 按钮后,字体设置窗口里只有一个下拉菜单设置字体大小:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-font-dialog.png)

但是,如果你把窗口拉长,就可以直接输入字体大小了,比如,我经常用的是 `15` —— 在下拉菜单里就没有这个设置。下图中,我已经把字体换成了 `SauceCodePro Nerd Font Mono`,Typeface 选择了 `ExtraLight`……

[〔图〕](https://user-images.githubusercontent.com/152970/135479272-9d0d2405-a3e2-4c7e-9c8e-52f3e2670a19.png)

**注意**:一定要把字体设置 `Sauce Code Pro Nerd Font Mono`,这就是之前我们用 `brew` 命令新安装的字体。

在 Window 标签里,可以设置窗口大小(也就是一屏显示多少行,每行多少个字符),我一般是设置成 `120 x 32`,你自己看着办:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-window-size.png)

现在,再安装 Terminal 的 [Powerlevel10K Theme](https://github.com/romkatv/powerlevel10k) for zsh:

```bash
brew install romkatv/powerlevel10k/powerlevel10k
```

安装完毕之后,有一段提示

> To activate powerlevel10k, add the following line to .zshrc:
>
> source /opt/homebrew/opt/powerlevel10k/powerlevel10k.zsh-theme
>
> If your .zshrc sets ZSH_THEME, remove that line.

为了能很方便滴编辑 `.zshrc` 文件,我们再安装一个文本编辑器(免费,但也可以缴费注册)

```bash
brew install sublime-text
```

如此这般安装好 sublime-text 之后,在 Terminal 里,随时可以使用 `subl` 命令编辑任何文本文件。

现在使用 sublime-text 编辑 `~/.zshrc` 文件,在 Terminal 里输入

```bash
subl ~/.zshrc
```

在 `~/.zshrc` 这个文件里,已经有很多内容(都是之前安装 Oh-My-Zsh)的时候生成的。在里面找到有 `ZSH_THEME="robbyrussell"` 的那一行,在这一行开头加上以一个 `#`(在这个设置文件里,`#` 是注释符号,一行内 `#` 之后的部分会被忽略掉):

```bash
# ZSH_THEME="robbyrussell"
```

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/subl-zshrc.png)

而后,在按 `⌘ s` 保存之后,退出 SublimeText。

然后重新启动 Terminal,执行以下命令,Powerlevel10K 的配置脚本会自动开始。按照提示一步一步选择即可。可以多试几次,不满意,就重新设置一遍。如果实在不知道该怎么办,参照[我的选择](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/p10k-configure.md)。以后想要重新设置 Powerlevel10K 的话,就用以下命令:

```bash
p10k configure
```

另外,我比较喜欢 [SpaceGray](https://github.com/wtanna/Spacegray-OSX-Terminal-Theme) 这个 Terminal Theme。(事实上,你可以在网上找到很多 Terminal Theme for Mac OSX……)

```bash
cd ~
curl https://raw.githubusercontent.com/wtanna/Spacegray-OSX-Terminal-Theme/master/spacegray.terminal --output spacegray.terminal
open spacegray.terminal
```

然后,一个新的 Terminal 窗口会被打开。接着用快捷键 `⌘ ,`(即,同时按下**Command 键**和**逗号键**的组合),呼出 Preferences 窗口,而后,在 Profiles 标签里,点击左边栏的 `SpaceGray`,而后,在右侧 `Text` 标签页里设置 `Font`,`Windows` 标签里设置窗口大小…… 而后,再将 `SpaceGray` 设置为 `Default`。

设置完之后,可以把刚才下载的 `spacegray.terminal` 文件删掉:

```bash
cd ~
rm spacegray.terminal
```

而后, Terminal 就被「装修」成了这个样子:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-p10k-spacegray.png)

这个 Terminal 的标题栏上,标识是 `joker@192`,这里的 `192` 是目前系统的 `hostname`,而 `192` 是我当前使用电脑的内网 IP 地址中最没用的第一段(总计四段),没有任何意义…… 所以,我可以用以下命令设置当前计算机的`hostname`:

```bash
scutil --set HostName "Macbook-Air-M1"
```

而后重新启动 zsh:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/terminal-hostname-modified.png)

8. Softwares

第三方的程序,绝大多数都可以通过 `brew` 命令下载、安装、升级(我自己用的程序里,目前只有 Mixin Desktop 不能通过 `brew` 命令安装)—— 甚至,用 `brew` 命令还能安装一个 `mas` 用来管理 App Store 里的程序…… 而后,我可以用一行命令升级所有程序 `brew update && brew upgrade && mas upgrade` —— 当然,这条命令,你得等会儿才可以使用。

注意,在使用 `brew install` 之前,最好卸载已经安装的软件,否则,系统会提醒你使用 `brew reinstall` 命令。于是,最好先 `brew install appcleaner`,用 AppCleaner 软件,卸载(它能把应用程序之外留下的各种文件一并删掉)

8.1 基本 Shell 工具

```bash
brew install git # MacOS 自带的 Apple Git 也不是不能用,但,替换掉已经成了习惯
brew install wget # 比 curl 方便一点的下载工具
brew install carlocab/personal/unrar # 命令行解压缩工具
brew install tree # 用来查询目录的树状结构
brew install mas # 用来管理 App Store 里的软件
brew install yt-dlp # 主流视频网站文件命令行下载工具
brew install symboliclinker # 生成 Symbolic Link(类似 Windows 里的「快捷方式」)的服务
```

8.2 系统维护工具

```bash
brew install appcleaner # 图形化的软件卸载工具
brew install onyx # 系统维护工具,比如清理系统垃圾
brew install cleanmymac # 系统维护工具,功能比 onyx 多一点点,收费软件
```

8.3 系统增强工具

```bash
brew install bettertouchtool # 定制各种快捷操作,也能做窗口管理,收费软件
brew install alfred # 定制各种工具流,还包括一个剪贴板增强工具,收费软件
brew install blackhole-64ch # 系统音频软导流工具,用 OBS 做直播播放音乐时需要
```

8.4 文本编辑器

```bash
brew install sublime-text # 轻量级、速度快、功能丰富的纯文本编辑器
brew install visual-studio-code # 微软出品的代码编辑器(基于 Google Atom)
brew install typora # MacOS 上最好最方便的 Markdown 编辑器
```

8.5 各种浏览器

```bash
brew install google-chrome
brew install firefox
brew install microsoft-edge
brew install brave-browser
brew install opera tor-browser # 自带翻墙软件 tor,缺点是速度慢
```

8.6 代理服务器客户端

```bash
brew install shadowsocksx-ng-r # 支持订阅的 shadowsocks 客户端
brew install clashx # 另外一个代理服务器客户端(我没咋用过)
brew install surge # 收费的代理服务器客户端,还可以单独装在一台电脑上做局域网的网管
```

8.7 更多第三方软件

事实上,很多在 App Store 里能下载的软件,`brew` 里面也有,比如 Wechat 桌面版,比如微软的 Remote Desktop…… 只要是能用 `brew` 下载安装的,就全都用 `brew` —— 无非是在安装之前,先去用 `brew search <softwarename>` 搜索一下,看看能不能找到;找到之后,再用 `brew info <software name>` 确认一下……

```bash
brew install android-studio # 安卓模拟器,我用它在 MacOS 使用 Kindle 听读有声书
brew install audacity # 音频编辑器
brew install baidunetdisk # 百度网盘
brew install calibre # 电子书管理用具,我经常用它做一些电子书的格式转换
brew install dropbox # 云存储
brew install keka # 解压缩用具
brew install microsoft-remote-desktop # 远程桌面管理(比如,登录局域网内的某台 Windows 设备)
brew install miniconda # conda 极简版,我平时用 Jupyter lab 比较多
brew install obs # 直播推流软件,也可以用来录屏
brew install openaudible # 将 Audible 的文件转换成 mp3,收费软件
brew install sketch # 矢量图编辑工具,收费软件
brew install skitch # 印象笔记出品的一个截屏软件,比系统自带的功能更全一些
brew install spotify # 音乐软件,收费软件
brew install thunder # 迅雷下载工具
brew install transmission # 另一款 bittorrent 下载客户端
brew install vlc # 媒体播放器
brew install webcatalog # 将很多网站服务打包成 App 独立运行的软件,我用它下载 Google Sheets 之类
brew install wechat # 微信桌面版
```

也可以以下脚本安装以上所有软件(以下我用了 `brew reinstall` 命令,因为常常有不小心已经安装好的软件):

```shell
#!/bin/zsh
PACKAGES="git wget tree mas yt-dlp symboliclinker appcleaner onyx cleanmymac bettertouchtool alfred blackhole-64ch sublime-text visual-studio-code typora "

for p in $PACKAGES; do
if (echo $(brew list) | fgrep -q $p); then
echo "$p has already installed."
else
brew install $p
# echo "$p installed successfully."
fi
done;

# brew cleanup
# brew upgrade
```

用这个脚本的好处是,不会因为安装某个软件出错而中断。也可以[下载这个脚本](https://raw.githubusercontent.com/xiaolai/apple-computer-literacy/main/files/brewinstall.sh),根据需求编辑下载列表,而后在 Terminal 里运行 `sh brewinstall.sh`(当然要先用 `cd` 命令转到这个脚本所在的目录之中)。

用 mas 管理 App Store

尚未安装 `mas` 的话,用 `brew install mas` 安装。`mas` 命令的用法如下:

```bash
mas list # 列出 App Store 中已安装的软件
mas upgrade # 升级所有 App Store 中的软件
mas search # 搜索某软件的安装 ID
mas install <software id> # 安装某软件
```

在新电脑上,我用以下命令安装所有我需要在 App Store 中安装的软件:

```bash
mas install 1333542190 ## 1Password 7 密码管理软件
mas install 1569813296 ## 1Password for Safari
mas install 438292371 ## Amadeus Pro 音频编辑软件,收费
mas install 1487937127 ## Craft 笔记管理软件,MacOS、iOS 通用,收费
mas install 409222199 ## Cyberduck 可用 brew 安装,sftp 软件,但,我在 App Store 里付费了
mas install 553245401 ## Friendly Streaming 收费视频平台聚合,我用它在电脑上看 Netflix 什么的
mas install 682658836 ## GarageBand 苹果的音乐工作室
mas install 1461845568 ## Gifox 录屏软件,保存为 gif 动图
mas install 1551462255 ## GMRight Mouse Lite 与 Windows 系统相似的鼠标右键菜单增强;付费版本是 1555844307
mas install 1474276998 ## HP Smart 惠普打印机管理
mas install 408981434 ## iMovie
mas install 1136220934 ## Infuse 我用它来播放局域网内的视频
mas install 409183694 ## Keynote
mas install 1295203466 ## Microsoft Remote Desktop
mas install 462054704 ## Microsoft Word
mas install 409203825 ## Numbers
mas install 409201541 ## Pages
mas install 485812721 ## TweetDeck Twitter 的桌面客户端,可多栏显示
mas install 970502923 ## Typeeto 可用电脑键盘为 iOS 输入
mas install 497799835 ## Xcode
```

如此这般之后,我就可以用以下一行命令升级电脑里的所有软件了……

```bash
brew update && brew upgrade && brew tap buo/cask-upgrad && yes | brew cu --all --force && brew cleanup && mas upgrade
```

注意,`brew upgrade` 不会更新通过 `--cask` 安装的软件,所以,需要 `brew tap buo/cask-upgrad && brew cu --all --force` 才行……

9. Massed up

在整个操作过程中,有可能「不小心搞乱了」,那就重来一遍,无所谓的。

9.1 卸载通过 Homebrew 安装的软件

> **注意**
>
> 不能在此之前卸载 Homebrew 😅

卸载单个软件,用 `brew uninstall <package name>` 命令即可,比如,`brew uninstall shadowsocksx-ng-r`。若是想要卸载所有通过 Homebrew 安装的软件,那么,执行以下命令即可:

```bash
brew remove --force $(brew list) --ignore-dependencies
brew cleanup
```

9.2 卸载 Homebrew

卸载 Homebrew 的脚本如下 —— 至于两个脚本里用哪个,要看你正在使用的是哪个源:

```bash
# 使用官方源
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"

# 使用国内镜像
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/HomebrewUninstall.sh)"
```

然后再在 Terminal 里删除整个 Homebrew 的目录:

```
sudo rm -rf /opt/Homebrew
```

9.3 卸载 Oh My Zsh

使用 `uninstall oh-my-zsh` 命令即可。

10. Read & Search

一个有趣的现象是,新手在接触到命令行的时候,大脑好像时刻处于「恐慌状态」(Panic Mode),面对突然出现的一整屏信息「不知所措」—— 不仅是中国人害怕英文,事实上,就算那是母语(美国人看英文、中国人看中文),也是一样的反应……

事实上,作为新手所能遇到的问题,比如,执行某个步骤的时候所遇到的出错信息,都是可以通过 Google 找到答案的 —— 因为你肯定不是第一个也肯定不是唯一一个遇到同样问题的人。

在 Terminal 里遇到的出错信息,用鼠标选中(Mac 上也可能是触摸板),而后点右键呼出 Context Menu,里面有一项,就是 `Search with Google ` —— 所谓的「**研究**」,其实不过是 **Search, Search, and Research**,就是反复搜索么!

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/context-menu-search-google.png)

---

11. 另外一个终端软件:Ghostty

除了系统自带的 Terminal 之外,还有很多终端软件,比如 iTerm 之类。其中一个用起来很顺手也非常高性能的是 [Ghostty](https://ghostty.org),可以试试。

```bash
brew install --cask ghostty
```

在 Terminal 中已经设置过的 `p10k` 在 Ghostty 里直接生效。

Ghostty 的配置文件里,需要写的东西很少(更多配置可以参照[它的官方文档](https://ghostty.org/docs/config)):

```json
font-family = "SauceCodePro NFM ExtraLight"
font-size = 16
window-width = 120
window-height = 32
```

这个配置文件的保存位置是: `~/Library/Application Support/com.mitchellh.ghostty/config`

Sublime Text

一个称手的纯文本编辑器,是必需的。Sublime Text 看起来挺贵的,$99 —— 但用得多了就值了。不缴费也能继续使用,只不过会被经常提醒缴费而已。还有就是,未来你可能会觉得用免费的 Visual Studio Code 可能更舒适 —— 虽然后者启动时间略微长了那么一点点……

```
brew install sublime-text
```

用 Homebrew 安装 Sublime Text 之后,命令行里会多一个命令,`subl`。

任何人(哪怕不是程序员)都一样,经常需要

> * 搜索与替换,或者批量替换
> * 调整段落或者行的顺序,或者排序
> * —— **还有无数因为你不知道所以才不需要的细节……**

以下是一个用 Sublime Text 多行同时操作的演示:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/sublimetext-multiselection.gif)

更多的功能,不妨去查看以下别人的教程:

> * [GETTING STARTED WITH SUBLIME TEXT: 25 TIPS, TRICKS, AND SHORTCUTS - Sublime Text 3 Tips and Tricks | General Assembly](https://generalassemb.ly/blog/sublime-text-3-tips-tricks-shortcuts/))
> * [Sublime Text GIFS Cheat Sheet](https://www.shortcutfoo.com/blog/sublime-text-3-gifs-cheat-sheet/)

当然,任何人最终为了(极大)提高效率,都会(也都有可能)学一点编程的 —— 明明花同样的钱买了一个自动化工具(就是电脑),会不会写程序所带来的效率差异,而不是一倍两倍,有可能万倍千万倍都不止呢。

Terminal 和 Finder 之间的跳转

你总是需要很快地从 Terminal 跳转到 Finder,与此同时,你也总是需要很快地从 Finder 跳转到 Terminal……

1. 从 Terminal 到 Finder

在 Terminal 中,想要在当前文件夹下打开 Finder,可使用以下命令:

```bash
open .
```

`open`,会使用系统默认方式打开某个文件,比如:

```bash
open readme.md # 在我的系统里,会用 Typora 打开 readme 文件
open /Applications/AppCleaner.app/ # 打开 Application 文件夹里的 AppCleaner.app 程序
open . # . 代表所有,于是,系统会用 Finder 打开当前所在文件夹。
```

2. 从 Finder 到 Terminal

当前,你用 Finder 浏览到了某个文件夹,然后,你想用 Terminal 操作这个文件夹里的内容,这时,在 MacOS 的默认情况下,还挺麻烦,尤其是当那个文件夹名称很长(甚至不知道究竟是什么的时候)……

2.1 Finder 右键菜单

在 Finder 里选中一个文件夹,而后点击鼠标右键,最底部会有 `New Terminal Window at Folder` 以及 `New Terminal Tab at Folder`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/finder-context-menu.png)

> **注意**
>
> 有些时候,这个 `New Terminal at Folder` 可能在右键菜单最底部的 Services 的字菜单中……

2.2 Finder 菜单

另外一个方法是点击屏幕上方的菜单条上的 Finder 字样,然后再点击 Servies,在字菜单中,可以看到 `New Terminal at Folder` 以及 `New Terminal Tab at Folder`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/finder-Services-from-menu.png)

使用这个系统内建的 Service 的讨厌之处在于,你只能在 Finder 中点中某个文件夹的时候才能使用它…… 可是,更多的时候,你已经在某个文件夹内,于是,你只好多点几下,先回到当前文件夹的上一层,然后再在众多文件与文件夹之中找到你想要的那个文件夹,而后再启用这个 Service...

这个 Service 是可以为其设置快捷键的。`System Preference` → `Keyboard` → `Shortcuts` → `Services` → `New Terminal at Folder`:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/shortcut-new-terminal.png)

我以前为它设置过 `⇧⌘⌥t`(四个键的组合,Shift Command Option t),后来就算了,因为不再使用这个 Service 了。

2.3 GMRight Mouse

最简单的办法是安装一个叫做 GMRight Mouse Lite 的软件(它也有 Pro 版本,收费,但,Lite 版本已经基本够用)。

```bash
mas install 1551462255 # Light 版本
mas install 1555844307 # pro 版本
```

有了它之后,我在 Finder 里,在某个文件夹内的空白处点击鼠标右键,是这样的:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/gmright-pro.png)

GMRight Mouse,还提供了一个 New File 的快捷菜单,有很多模版,我选了 Text, Markdown, 和 Shell 这三个,因为我太常使用它们了。另外,那个 Copy Path,也是特别实用的,以后你就知道了。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/GMright-New-File.png)

2.4 AppleScript

GMRight Mouse 大多数情况下都很好,但,想要它打开 iCloud 目录,就不行了…… 在 iCloud 文件夹内,你点鼠标右键,可能就看不到 GMRight 的功能了 —— 这也许是它的 bug...

你在 Finder 里是很容易找到 iCloud Drive 的,可是,在 Terminal 里,没人告诉你的话,你事先是没办法知道你得这样:

```bash
cd ~/Library/Mobile\ Documents/com~apple~CloudDocs
```

—— 更不用提对新手来说,根本无法知道,在 Terminal 的命令行里,文件名或者文件夹名里的空格,得在前面加上一个「脱字符」`\`……

我的办法是用 Script Editor 保存个脚本:

```js
tell application "Finder"
if (count of windows) > 0 then
set thePath to target of front window
else
display dialog "There are no open Finder windows." with icon caution buttons {"OK"} with title "Open Terminal Here..."
return
end if
end tell

if not (exists thePath) then
tell application "Finder" to set theName to name of front window
display dialog "The location of the Finder window \"" & theName & "\" is not a real location (e.g. smart folder, search, network, trash, etc) and cannot opened in Terminal." with icon caution buttons {"OK"} with title "Open Terminal Here..."
return
end if
set thePath to quoted form of POSIX path of (thePath as alias)

tell application "Terminal"
if it is running then
-- This seems to be the only way to tell Terminal to open a new tab
tell application "System Events"
tell application process "Terminal"
set frontmost to true
try
keystroke "t" using command down
on error errMsg
set msg to "Error: " & errMsg & "
This probably means that you're using Mojave and you will need to add this app to the \"Accessibility\" section in the \"Privacy\" tab of the \"Security & Privacy\" System Preferences.
Please see the \"Mojave\" section of the README for more details"
display dialog msg buttons {"OK"} with icon caution with title "Open Terminal Here..."
return
end try
end tell
end tell
do script "cd " & thePath & " && clear" in last tab of front window
else
do script "cd " & thePath & " && clear"
end if
activate
end tell
```

> **注意**
>
> 这个脚本当然不是我写的,是我在网上找到的:[Open-iTerm-or-Terminal-Here...](https://github.com/rkanter/Open-iTerm-or-Terminal-Here.../blob/master/applescripts/Terminal.applescript)

把这个脚本命名为 `OpenTerminalHere`(默认会保存在 iCloud 的文件夹里);而后,需要的时候(比如,你刚刚用 Finder 浏览到某个文件夹),使用快捷键 `⌘ ␣`(Command 和 Space)呼出 Spotlight,输入到第五个字符,即, `opent` (不用等到你输入完全称)的时候,这个脚本应该已经排在第一位了,按 `⮐`(Return)就是执行该脚本,而后,Terminal 就应该打开,并且已经处于当前文件夹……

2.5 使用 Alfred

使用 AppleScript 当然也行,但,更方便的是在 Alfred 里添加一个 Keyword 工作流,用的就是上面的 Apple Script。你需要做的是,

> 1. 花钱购买 Alfred 这个软件的 Pro License
> 2. 下载并导入 "[Open Terminal Here..](https://github.com/xiaolai/apple-computer-literacy/blob/main/files/Open%20Terminal%20Here....alfredworkflow?raw=true) " 这个 Workflow(即,工作流)

当我需要的时候,我会用 `⌥ ␣`(Option 和 Space)呼出 Alfred 输入框,而后输入两个字符,`ot`,再按 `⮐`……

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/alfred-ot.png)

Alfred 软件非常灵活,也有很大的用处,花钱买它不亏。

还有另外一个 Alfred Workflow,[alfred-terminalfinder](https://github.com/LeEnno/alfred-terminalfinder),增加四个快捷命令:

> - ft: open current Finder directory in Terminal
> - tf: open current Terminal directory in Finder
> - fi: open current Finder directory in iTerm
> - if: open current iTerm directory in Finder

[〔图〕](https://camo.githubusercontent.com/14159afc328e47d5ccd8064eed087ebb59fff699337c0fd8fd98744d9b2fe8fc/68747470733a2f2f7261772e6769746875622e636f6d2f4c65456e6e6f2f616c667265642d7465726d696e616c66696e6465722f6d61737465722f73637265656e73686f745f66742e706e67)

Typora

Markdown 是一种极致简单的文本标记格式,今天已经成了互联网写作发布的最普遍方式。Markdown 的作者是 [Aaron Swartz](https://en.wikipedia.org/wiki/Aaron_Swartz)。一般文件名称以 `.md` 或者 `.markdown` 作为尾缀。

[Typora](https://typora.io/) 是 MacOS 上目前最好用的 Markdown 编辑器,缺点是没有 iOS 版本 —— 也就是说,在 iPad 上无法像 Craft、Bear 那样相互通用且共享文件,不过,的确绝大多数写作都是在 Mac 上完成的。

当前你正在阅读的文档,我写的时候,就是用 Typora。

自从开始使用 Markdown 之后,Microsoft Word 和 Apple Pages 都成了基本处于弃用的状态。Microsoft Word,现在我只是在直播的时候,把它当作白板使用(因为可以设置很多与格式有关的快捷键);Apple Pages 么,虽然顺手安装了,可真的很久很久没打开用了。

```bash
brew install typora
```

以下是官方示例视频:

<video autoplay="" muted="muted" preload="preload" loop="loop" style="border-radius: 8px;box-shadow: 0px 0px 8px 3px #ccc;" src="https://typora.io//img/beta.mp4"></video>

第一个要熟悉的快捷键是 `⌘/` —— 在 Souce Code Mode(源码)和 Rendered Text(渲染后文本)之间切换。

与文本格式相关的最基本快捷键,都在 Format 菜单里:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/typora-format.png)

比如,你想要插入图片,那就是 `⌃ ⌘ i` (在以上菜单中,Image 子菜单里可以看到),按下这个快捷键之后,会出现

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/typora-insert-image.png)

然后点文件夹图标,选择图片即可。

Paragraph 菜单里有更多与段落和整篇相关的快捷键:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/typora-paragraph.png)

Typora 提供很多 Theme,我一直用 Github:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/typora-them.png)

—— 这样的好处是,我平时编辑的样子,就是我发布在 Github 上的样子。

Typora 的设置面板也很简单直观 —— 基本上,默认的设置就很够用了。

Visual Studio Code

使用 "SauceCodePro Nerd" 字体

Settings UI 里没有对 Font-Weight 的选项,所以,只能在 `settings.json` 里编辑设置:

```json
// 在文件最末位 `}` 的上一行添加:
"editor.fontFamily": "'SauceCodePro Nerd Font Mono'",
"editor.fontSize": 17,
// 相当于 ExtraLight:
"editor.fontWeight": "200",
// 不要忘记设置 Terminal 窗口的字体
"terminal.integrated.fontSize": 16,
"terminal.integrated.fontWeight": "200",
```

使用独立的 User Profile 文件夹

命令行中使用以下命令:

```bash
code --extensions-dir $HOME/.vscode/js/extentions --user-data-dir $HOME/.vscode/js/user"
```

* 在 `~/.vscode/js/extentions/` 里保存扩展插件;
* 在 `~/.vscode/js/user/` 里保存用户设置……

极简版本 VSCode(方案一)

很多的时候,我们只想快速编辑一个文本文件,那么,VS Code 的默认洁面就显得 “臃肿” 和 “多余” 了…… 可以专门设定一个 “极简版本”。

1. 在 Termial 中执行以下命令:

```bash
code --user-data-dir $HOME/.vscode/minicode --extensions-dir $HOME/.vscode/minicode/extentions
```

这个意思是说,在 `~/.vscode/minicode` 下保存用户数据,在 `~/.vscode/minicode/extentions` 下保存为其安装的插件。

2. 在新打开的 VSCode 中,安装两个插件:

> * Customize UI
> * Github Theme

3. 按下快捷键 `SHIFT + COMMAND + p` 呼出命令板,找到 `Preferences: Open User Settings (JSON)`,将 `settings.json` 的文件夹内容替换为:

> 注意,在此之前,我[已经安装](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/start-from-terminal.md#7.%20Terminal%2(2))过 `SauceCodePro Nerd Font Mono` 字体。

```json
{
/**
* Minimal Code
*/
"customizeUI.stylesheet": {
".decorationsOverviewRuler": "display: none;",
".editor-group-container.title *": "display: none;",
".editor-group-container.title": "pointer-events: none;",
".editor-group-container.empty": "-webkit-app-region: drag;",
},
"customizeUI.titleBar": "inline",
"debug.console.fontFamily": "SauceCodePro Nerd Font Mono",
"debug.console.fontSize": 15,
"debug.console.lineHeight": 36,
"debug.toolBarLocation": "docked",
"diffEditor.ignoreTrimWhitespace": false,
"diffEditor.renderSideBySide": false,
"editor.bracketPairColorization.enabled": false,
"editor.colorDecorators": false,
"editor.cursorStyle": "line-thin",
"editor.fontFamily": "SauceCodePro Nerd Font Mono",
"editor.fontWeight": "200",
"editor.fontLigatures": true,
"editor.fontSize": 18,
"editor.formatOnSave": true,
"editor.glyphMargin": false,
"editor.gotoLocation.multipleDeclarations": "goto",
"editor.gotoLocation.multipleDefinitions": "goto",
"editor.gotoLocation.multipleImplementations": "goto",
"editor.gotoLocation.multipleReferences": "goto",
"editor.gotoLocation.multipleTypeDefinitions": "goto",
"editor.guides.indentation": false,
"editor.hideCursorInOverviewRuler": true,
"editor.lineHeight": 36,
"editor.lineNumbers": "off",
"editor.matchBrackets": "near",
"editor.minimap.enabled": false,
"editor.occurrencesHighlight": false,
"editor.renderLineHighlight": "none",
"editor.renderWhitespace": "none",
"editor.scrollbar.horizontalScrollbarSize": 8,
"editor.scrollbar.verticalScrollbarSize": 8,
"explorer.compactFolders": false,
"explorer.decorations.badges": false,
"explorer.openEditors.visible": 0,
"git.enableSmartCommit": true,
"git.confirmSync": false,
"markdown.preview.markEditorSelection": false,
"problems.decorations.enabled": false,
"scm.diffDecorations": "none",
"terminal.integrated.cursorStyle": "line",
"terminal.integrated.enableMultiLinePasteWarning": false,
"terminal.integrated.fontSize": 15,
"terminal.integrated.lineHeight": 1.85,
"window.autoDetectColorScheme": true,
"window.newWindowDimensions": "inherit",
"window.title": "${rootName}",
"window.titleBarStyle": "inline",
"workbench.activityBar.visible": false,
"workbench.colorTheme": "GitHub Dark Default",
"workbench.editor.enablePreview": false,
"workbench.editor.revealIfOpen": true,
"workbench.editor.showTabs": false,
"workbench.editor.untitled.hint": "hidden",
"workbench.iconTheme": null,
"workbench.list.horizontalScrolling": true,
"workbench.preferredDarkColorTheme": "GitHub Dark Default",
"workbench.preferredLightColorTheme": "GitHub Light Default",
"workbench.startupEditor": "none",
"workbench.statusBar.visible": false,
"workbench.tips.enabled": false,
"workbench.tree.indent": 16,
"workbench.tree.renderIndentGuides": "none",
"editor.inlineSuggest.enabled": true,
"security.workspace.trust.startupPrompt": "never",
"security.workspace.trust.enabled": false,
"security.workspace.trust.emptyWindow": false,
"editor.tabSize": 2
}
```

4. 为极简版 VSCode 设置一个 alias

在 `.zshrc` 里添加一行:

```bash
alias mcode="code --user-data-dir $HOME/.vscode/minicode --extensions-dir $HOME/.vscode/minicode/extentions"
```

而后重新启动 Terminal,以后就可以用 `mcode <filename>` 打开极简版 VSCode 并编辑一个文件了。

5. 效果展示

未打开任何文件的状态:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/minicode-no-file-open.png)

编辑文件时的状态:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/minicode-editing-settings-json.png)

极简版本 VSCode(方案二)

这个方案是使用 Visual Studio Code 的 [Portable Mode](https://code.visualstudio.com/docs/editor/portable)。以下以 MacOS 为例:

1. 创建一个文件夹,如,`/Applications/mcode`;而后下载 Visual Studio Code,解压缩,放到 `mcode` 文件夹中,将 `Visual Studio Code.app` 重命名为 `mcode.app`;
2. 在 `mcode` 文件夹中创建一个名为 `code-portable-data` 的文件夹;
3. 双击 `mcode.app` 打开这个 Portable 版本的 Visual Studio Code;
4. 安装 `Github Theme` 和 `Customize UI` 插件;
5. 在 `User Settings (JSON)` 里复制粘贴与方案一中设置的同样内容;
6. 在命令行中执行 `ln -s /Applications/mcode/mcode.app/Contents/Resources/app/bin/code /opt/homebrew/bin/mcode`

如此这般之后,mcode 事实上就是一个独立的极简版 VSCode,并且不妨碍正常安装的 VSCode 的使用。

另外,可以为 `mcode` 设置一个新的图标,以便容易区别:

> https://github.com/dhanishgajjar/vscode-icons

Webcatalog

现在,网上有大量的「网站」与安装在操作系统上的 App(程序)一样提供专门的服务。比如,Google 提供的就很多(实际上多大 270+ 种):

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/google-apps.png)

过去我习惯用 [Nativefier](https://github.com/nativefier/nativefier) 把一些网站打包成 MacOS App 使用,现在,直接买 [Webcatalog](https://webcatalog.io) 完成这个功能了,现在还在用 Nativefier 打包的,只剩下一个本地的 JupyterLab Service 了。Webcatalog 的 Lifetime Licence 收费 $40,挺好。看了一眼,现在我用它打包了 16 个网络服务。

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/images/webcatalog-my-apps.png)

Webcatalog 也可以通过 Homebrew 安装

```bash
brew install --cask webcatalog
```

值得一提的是,如此这般之后,我干脆不用 MacOS 上的 Mail 了,因为 Gmail 变成了 App。这里我用的最多的是,Coogle 和 Google Sheets —— 都是 Google 的。

如此这般之后,我的软件,除了极个别的之外(比如 [Mixin Desktop](https://mixin.one/messenger)),都可以用 [Homebrew](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/start-from-terminal.md) 和 Webcatalog 搞定。

Z-Shell

plugins for Oh-My-Zsh

``` bash
git clone https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
```
Add plugings in `~/.zshrc`
```bash
plugins=(git zsh-syntax-highlighting zsh-autosuggestions)
```

用 Python 脚本调用 DeepL API Pro 进电子书的行自动翻译

1. 概述

脚本跑起来的效果大致如下:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/images/deepl-api-python.gif)

一本书中文译文大约 **39 万字**的书,差不多用 **1.5 小时**就可以处理完毕(包括基本的格式编辑)。

2. 使用 jupyterlab 运行脚本进行前期工作

如何安装使用 Jupyterlab,请参照[这篇文章](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/jupyterlab.md)

Python 脚本,`ipynb` 文件请参照[这篇文章](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/deepl-automatic-html-translation.ipynb)(ipynb 文件)

3. 后期使用 VSCode 进行校对

请参照[这篇文章](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/translation-workflow.md)。

4. 示例文件

`John Law` 文件夹里是一本书,包含 `epub`、`htmlz` 以及随后工作过程中生成的若干个 `html` 文件和最终修改过的 `style.css` 文件

翻译工作环境

首先当然是 DeepL 的付费版。(国内的人,找个国外的朋友代为支付即可…… 在美国的、在日本的,都行。)

> **注意**:最佳的购买方案是购买 “For Developers” 标签内的 “DeepL API Pro”,价格仅为 $5.49/月。只有这个方案提供 API,才可以配合 VSCode 里的 DeepL 插件使用。“For individuals and teams” 里的 DeepL Pro 购买方案,提供的是 “Authentication Key for CAT tools”,不是能程序化调用的 “Authentication Key for API”…… 我竟然是在选错方案一个多月之后才反应过来。

>> **另外**:使用 DeepL API Pro 版本的购买方案之后,DeepL 桌面版依然有它的用处 —— 于是,我注册了两个账号分别付费,一个账号购买了 DeepL Pro,另外一个账号购买了 DeepL API Pro…… 于是,下文中为了批处理在 Alfred 中设置的快捷键,以及在 VSCode 中设置的快捷键,要注意区分开来。我在 Alfred 中为 “翻译当前光标所处的段落” 设置的快捷键是 `⇧ + ⌃ + P`,在 VSCode 中设置的快捷键是 `⌃ + ⌥ + ⌘ + P`。

> [〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/images/deepl-plan-for-api.png)

其次是文字编辑器的选择。我选择的是 [Visual Studio Code](https://code.visualstudio.com/) —— 这是一个面向程序员设计的纯文本编辑器,但,并非只有程序员们才是用它…… 在进行翻译的时候,它成了最好的选择 —— 因为电子书目前最常见的格式都可以转换成 `html` 文本,用 MS Word 之类的编辑器事实上是很差的选择。比如,`⌘+D` 可以选中多个相同的字符串而后对它们同时编辑 —— 这样的功能,MS Word 之类的 “专业字处理器” 根本就没有,更别说它蹩脚的正则表达式搜索替换功能了(没办法跨文件处理)…… 当然,VSCode 还可以安装各种插件,做更多事情,比如,可以做很多批处理 —— 不可或缺的功能。

电子书转换路径

我的电子书获取路径大致如下:

> Kindle > ePubor Ultimate > Calibre > htmz > vscode editing.

我都是在 Amazon 上直接买,而后在电脑上安装一个老版本的 Kindle App,用鼠标右键点击书名,下载,并不打开该电子书,而后退出 Kindle。

[ePubor Ultimate](https://www.epubor.com/) 也是个收费软件,能把旧版 Kindle 下载的电子书的 DRM 去掉;将 `awz` 文件转换成 `epub` 文件。(可参考这个[网页](https://www.epubor.com/how-to-downgrade-kindle-for-pcmac.html))

然后,再用免费软件 [Calibre](https://calibre-ebook.com/) 将 `epub` 转换成 `htmlz` 文件(一个压缩包)。(我尝试过使用命令行工具包 [pandoc](https://pandoc.org/),但,比较之后,发现 Calibre 在保留样式方面可能更好一点……)

最后,再在 Terminal 里用 `unzip` 命令将 `htmlz` 文件解压缩。

整理一下文件夹,休整并补充一下 `style.css`,配上 `toc.css` 和 `toc.js`;最终,形成一个左侧带有固定目录(方便浏览和编辑时跳转)的 `html` 文件……(这一步可以最后做,见最后一节)

清理 Calibre 生成的 html 文件

每本电子书被 Calibre 转换成 html 之后,文件内的各种 tag 分布各不相同。

为了编辑方便,经常需要 1)将诸如 `<div class="p-indent">...</div>` 或者 `<p class="xxx">...</p>` 转换成一行内,以便可以整行直接搬运到 DeepL 翻译。可以用 Jupyter 里用 Python 以及 BeautifulSoup 包完成:

``` python
import bs4
filePath = "<file's full path>"
html = open(filePath)
soup = bs4.BeautifulSoup(html.read())
# 把所有 div 的内容整理成一行
for div in soup.find_all("div", class_=["p", "p-indent", "p-blocktext"]):
div = str(div).replace("\n", "")
text = str(soup).replace("\n", "")
```

随后,可以将 text 拷贝到剪贴板,或者直接写入某个指定的文件……

另外,经常有大量没有具体意义的`<span>...</span>`。去掉他们的方法是,先用 VSCode 搜索 `<span>` 将它们替换成 `<span class="none">`,而后再用 BeautifulSoup 给去掉:

``` python
for span in soup.find_all("span", class_="none"):
span.unwrap()
```

浏览器自动重载(Auto-reload)

* 为系统安装 nodejs 和 browser-sync
* 为浏览器(Microsoft Edge 或者 Google Chrome)安装 Live Load 插件
* 在 VSCode 中用快捷键 ```Ctrl + ` ``` 呼出显示在编辑器区域下部的 Terminal,输入 `serve` 命令……

> 更多参见这篇文章:
>
> [https://medium.com/@svinkle/start-a-local-live-reload-web-server-with-one-command-72f99bc6e855](https://medium.com/@svinkle/start-a-local-live-reload-web-server-with-one-command-72f99bc6e855)

VS Code 插件

VSCode 的插件有很多,为了翻译任务,我只增加了以下三个插件。

* Chinese Translation(有时候 DeepL 会在简体中文中包含一些繁体中文内容,可以用这个插件提供的功能快速转换)
* DeepL for Visual Studio Code(DeepL 的付费用户才能用到这个插件)
* ssmacro(为 VSCode 提供 “批处理” 功能;对翻译工作来说,最重要的就是用它执行一系列的正则表达式替换)

DeepL 插件的设置

为了保留原电子书中的大量的引用链接,通常我们是在转换并清理过的 `html` 文件里工作。DeepL 的插件允许为 API 调用做一些设置,比如,`tag_handlling=xml`。

安装好 DeepL 插件之后,用快捷键 `⌘ + ,` 呼出 Settings,在 Extensions 中找到 `DeepL`,而后如下图所示进行设置:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/images/deepl-extention-settings.png)

如此这般之后,选中任何文字,都可以使用快捷键 `⌥ + t` 进行翻译。

而后,我在 `keybindings.json` 中增加了一个快捷键,调用一个 ssmacro 的批处理:

```json
{
"key": "ctrl+alt+cmd+p",
"command": "ssmacro.macro",
"args": {"file": "deepl_translate.json"},
"when": "editorTextFocus"
},
```

而 `deepl_translate.json` 的内容如下:

```json
[
{
"command": "expandLineSelection"
},
{
"command": "editor.action.duplicateSelection"
},
{
"command": "ssmacro.left"
},
{
"command": "editor.action.insertLineBefore"
},
{
"command": "ssmacro.right"
},
{
"command": "expandLineSelection"
},
{
"command": "deepl.translate"
}
]
```
以上的 Macro 是执行以下任务:

> 1. 选中当前行;
> 2. 将当前行再复制一份放在下面;
> 3. 光标挪到新复制的那一行的开头;
> 4. 在光标前增加一个空行;
> 5. 确保光标仍在新复制的那一行之内;
> 6. 选中新复制的那一行
> 7. 发送至 DeepL 等待返回结果覆盖新复制的那一行;

中文排版要点

中文字体本质上是“等宽字体”,因此排版有个特别的 “小技巧”,设定一个较小的字间距就能做到很舒服:

```css
cn {
letter-spacing: 0.1 em;
}
```

在中英文混排的时候,这比较难办…… 等我找时间研究一下 javascript 动态识别中文字符再说……

以下是我在中文排版时的 “强迫症”:

> * `"` 要相应地替换成 `“”`
> * `'` 要相应地替换成 `‘’`
> * 无论是单引号还是双引号,都要与相邻的字符之间留有一个空格;标点符号 `,。?!` 除外;
> * 数字、百分比、英文字母,与汉字之间应该应该留有空格;
> * 应用在中文字符的 “斜体” 样式,应该改成 “加重” 样式;
> * 破折号统一使用 `——`(前后有空格,除非与标点符号相邻)而非 `&mdash;` 或者 `--`;
> * 外国姓名之间的符号为 `·`;
> * ……

要满足这点强迫症,手动编辑常常近乎不可能。只能靠工具。在 VSCode 里,我是找了个叫做 `ssmacro`(Super Simple Macro)的插件,把需要的 “搜索替换正则表达式” 罗列出来,而后设置一个快捷键 —— 让这些任务 “一键完成”……

一些代码

vscode-deepl automation

DeepL 的软件上,`Insert to...` 是一个链接,并没有给出快捷键。于是,需要写个 AppleScript,模拟鼠标点击,而后可以用 Alfred 软件给这个脚本设定个快捷键(我设置的快捷键是 “ctrl+alt+cmd+p”):

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/images/alfred-applescript.png)

```applescript
tell application "Visual Studio Code"
activate
delay 2
tell application "System Events"
key code 37 using command down
delay 1
key code 8 using command down
key code 8 using command down
end tell
end tell
-- 以上是 cmd+l 选中当前整行;而后连续两次 cmd+c 将选中文字发给 DeepL

delay 5

tell application "Visual Studio Code"
activate
delay 2
tell application "System Events"
key code 124 using command down
key code 124 using command down
key code 36 using command down
end tell
end tell

-- 以上是在 VSCode 中输入两个空行

-- 以下是模拟鼠标点击,按 DeepL 上的 “Insert to...” 链接
-- 也可以将以下部分,独立出来,单独为 “Insert to...” 设置个快捷键(我设置的是 “ctrl+alt+cmd+i”)
tell application "System Events"
tell process "DeepL" to tell window 1
activate
set w_position to its position
set w_size to its size
end tell
end tell

set px to item 1 of w_position
set py to item 2 of w_position
set sx to item 1 of w_size
set sy to item 2 of w_size

tell application "System Events"
click at {px + sx - 190, py + sy - 95} -- Insert to link
end tell
```

各种为翻译工作设定的快捷键

注意:在使用 VSCode 的时候,如果某些快捷键不起作用,很可能是因为 “当前输入法处于中文输入状态” 造成的。切换成英文输入法状态就好了…… 我最初的时候,设置了个快捷键,`ctrl+cmd+alt+\\`,这个快捷键就遇到了 “与输入法” 有所冲突的情况。后来,将这个快捷键改成了 `ctrl+cmd+alt+o`,就不受输入法影响了。

`keybindings.json`

```json
[
{
"key": "ctrl+shift+9",
"command": "editor.action.insertSnippet",
"args": {"snippet": "($TM_SELECTED_TEXT$0)"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+'",
"command": "editor.action.insertSnippet",
"args": {"snippet": "“$TM_SELECTED_TEXT$0”"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+'",
"command": "editor.action.insertSnippet",
"args": {"snippet": "‘$TM_SELECTED_TEXT$0’"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+[Backslash]",
"command": "editor.action.insertSnippet",
"args": {"snippet": "【$TM_SELECTED_TEXT$0】"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+[Slash]",
"command": "editor.action.insertSnippet",
"args": {"snippet": "《$TM_SELECTED_TEXT$0》"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+[BracketRight]",
"command": "editor.action.insertSnippet",
"args": {"snippet": "「$TM_SELECTED_TEXT$0」"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+[BracketLeft]",
"command": "editor.action.insertSnippet",
"args": {"snippet": "『$TM_SELECTED_TEXT$0』"},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+alt+cmd+-",
"command": "editor.action.insertSnippet",
"args": {"snippet": " —— "},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+=",
"command": "editor.action.insertSnippet",
"args": {"snippet": " $TM_SELECTED_TEXT$0 "},
"when": "editorTextFocus&&editorHasSelection"
},
{
"key": "ctrl+shift+-",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<p></p>"},
"when": "editorTextFocus"
},
{
"key": "ctrl+alt+cmd+a",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<a href=\"\" target=\"_blank\">$TM_SELECTED_TEXT$0</a>"},
"when": "editorTextFocus&&editorHasSelection&&editorLangId==html"
},
{
"key": "shift+ctrl+b",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<strong>$TM_SELECTED_TEXT$0</strong>"},
"when": "editorTextFocus&&editorHasSelection&&editorLangId==html"
},
{
"key": "shift+ctrl+i",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<em>$TM_SELECTED_TEXT$0</em>"},
"when": "editorTextFocus&&editorHasSelection&&editorLangId==html"
},
{
"key": "shift+ctrl+u",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<u>$TM_SELECTED_TEXT$0</u>"},
"when": "editorTextFocus&&editorHasSelection&&editorLangId==html"
},
{
"key": "shift+ctrl+d",
"command": "editor.action.insertSnippet",
"args": {"snippet": "<del>$TM_SELECTED_TEXT$0</del>"},
"when": "editorTextFocus&&editorHasSelection&&editorLangId==html"
},{
"key": "ctrl+tab",
"command": "cursorRight",
"when": "editorTextFocus&&!editorHasSelection"
},
{
"key": "ctrl+alt+cmd+backspace",
"command": "editor.emmet.action.removeTag"
},
{
"key": "ctrl+shift+right",
"command": "editor.emmet.action.matchTag",
"when": "editorTextFocus&&editorLangId==html"
},
{
"key": "ctrl+shift+l",
"command": "editor.emmet.action.wrapWithAbbreviation"
},
{
"key": "cmd+k b",
"command": "workbench.action.toggleSidebarVisibility"
},
{
"key": "shift+alt+d",
"command": "editor.action.duplicateSelection"
}
,{
"key": "ctrl+alt+cmd+o",
"command": "ssmacro.macro",
"args": {"file": "regex.json"},
"when": "editorTextFocus"
}
]
```

以上的最后一段:

```json
{
"key": "ctrl+alt+cmd+o",
"command": "ssmacro.macro",
"args": {"file": "regex.json"},
"when": "editorTextFocus"
}
```

其中的 `“args”: {“file”:“regex.json”},` 有两种写法,一个是像这样用 `“file”:` 指定,那么这个文件应该在 `$HOME/.vscode/extensions/joekon.ssmacro-0.6.0/macros/` 文件夹内;第二种写法使用 `“path”:`,然后在其后设定批处理文件(`json`文件)的绝对路径。

为 ssmacro 设定的正则表达式批处理

```json
[
{
"command": "expandLineSelection"
},
{
"command": "ssmacro.replace",
"args": {
"info": "半角方括号",
"find": "\\[(.*?)\\]",
"replace": "$1",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "直引号变成弯引号",
"find": "\\s*\"(.*?)\\s*\"",
"replace": "“$1”",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "直引号变成弯引号",
"find": "\\s*'(.*?)\\s*'",
"replace": "‘$1’",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "上一步误伤的直引号",
"find": "=“(.*?)”",
"replace": "=\"$1\"",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "弯引号之前的空格",
"find": "([\u4e00-\u9fa5])“",
"replace": "$1 “",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "弯引号之后的空格",
"find": "”([\u4e00-\u9fa5])",
"replace": "” $1",
"all": false,
"reg": true,
"flag": "gm"
}
},

{
"command": "ssmacro.replace",
"args": {
"info": "中文斜体转换成中文加重",
"find": "<i (.*?)>([\u4e00-\u9fa5]+)</i>",
"replace": "<strong $1>$2</strong>",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "省略号",
"find": "\\.{2,}\\s*。*\\s*",
"replace": "…… ",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "破折号",
"find": "&mdash;|—|--",
"replace": " —— ",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "姓名之间的 ·",
"find": "([\u4e00-\u9fa5])-([\u4e00-\u9fa5])",
"replace": "$1·$2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "姓名之间的 ·",
"find": "([\u4e00-\u9fa5])-([\u4e00-\u9fa5])",
"replace": "$1·$2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "数字前的空格",
"find": "([\u4e00-\u9fa5])(\\d)",
"replace": "$1 $2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "数字后的空格 —— 含 %",
"find": "([\\d%])([\u4e00-\u9fa5])",
"replace": "$1 $2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "英文字母前的空格",
"find": "([\u4e00-\u9fa5])(\\w)",
"replace": "$1 $2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "英文字母后的空格",
"find": "(\\w)([\u4e00-\u9fa5])",
"replace": "$1 $2",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "后:斜体英文与汉字之间的空格",
"find": "([\u4e00-\u9fa5])<i",
"replace": "$1 <i",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "前:斜体英文与汉字之间的空格",
"find": "i>([\u4e00-\u9fa5])",
"replace": "i> $1",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "双引号前的逗号",
"find": ",”",
"replace": "”,",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.replace",
"args": {
"info": "逗号、句号、感叹号、问号后面多余的空格",
"find": "([,。!?]) ",
"replace": "$1",
"all": false,
"reg": true,
"flag": "gm"
}
},
{
"command": "ssmacro.right"
}
]
```

用 ssmacro 批处理进行正则表达式替换的效果大致如下:

[〔图〕](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/images/cn-regex-vscode.gif)

html 样式整理

可以把 `./../images/` 文件夹重命名为 `./assets/`,而后把 `style.css`、`toc.css`、`toc.js` 都放到 `./assets/` 文件夹中。

以下是所需文件的“示例:

> * [style.css](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/files/style.css)
> * [toc.css](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/files/toc.css)
> * [toc.js](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/files/toc.js)

把 `./../images/` 文件夹重命名为 `./assets/` 之后,记得要 search `../images/` 而后 replace `assets/`。

将以下两行插入到 `<head> </head>` 之间:
```html
<link href="./assets/style.css" rel="stylesheet" type="text/css" />
<link href="./assets/toc.css" rel="stylesheet" type="text/css" />
```

将以下五行插入 `</body>` 之间:
```html
<script src="./assets/toc.js" ></script>
<script>
console.log('load')
buildTOC('.contents', '.toc')
</script>
```

调整一下 `body` tag 之间的结构:

```html
<body>
<div class="header">

</div>
<div class="main">
<div class="toc">

</div>
<div class="contents">

</div>
</div>
</body>
```

Calibre 生成的 `style.css` 可以根据自己的偏好调整,比如,我加了一些样式,正如你在这个示例 [style.css](https://github.com/xiaolai/apple-computer-literacy/blob/229a407cdee32934e9f45eac0e8fc348165b4c12/deepl-aided-semi-automatic-book-translation/files/style.css) 里看到的那样 :

```css
.header{
background-color: #eee;
position: fixed;
/* Set the navbar to fixed position */
top: -30px;
left: -50px;
/* Position the navbar at the top of the page */
width: 120%;
/* Full width */
/* border-bottom: 1px solid #752828; */
background: url(assets/background.jpg) #C51216;
/* 并不需要这个 background.jpg 存在,只是 “占位” */
}

.header h1{
color: white;
text-align: center;
font-size: 40px;
padding-top: 30px;
}

.toc {
width: 15%; /* .toc 和 .contents 的宽度加起来应该等于 90% */
position: fixed;
overflow-x: hidden;
overflow-y: auto;
padding-left: 30px;
height: 100vh;
padding-top: 50px;
}

.contents {
margin-top: 100px; /* 这是给顶部固定横幅预留的高度 */
margin-left: 20%;
padding-top: 50px;
width: 75%; /* .toc 和 .contents 的宽度加起来应该等于 90% */
}

p{
letter-spacing: 0.1em; /* 这是中文字符排版的 “秘籍” */
font-size: 18px;
font-family: 'Kaiti SC', Georgia, 'Times New Roman', Times, serif;
}

img {
height: auto !important;
width: 95% !important;
text-align: center;
}
```

版权声明:© 超限思维 · LookMinds。本页为己方整理的亲口亲笔原稿处理稿/编者新译,非原文替代;原文版权归原作者/平台。本人原作请回原链。