OSX迁移基础配置

一、资料打包迁移:

定期整理到~/Migrations, 备份到外接硬盘。

主要为了避免存档大文件自动保存到iCloud

后期未整理的内容可以放在文档里面,同步在iCloud上

在Finder左侧添加Migrations快捷路径

代码:github/gitee/gitlab

app自存储:

wechat: 备份数据之后再恢复

DT:

本地数据库配置

  1. 安装后登陆网站激活
  2. 配置css显示:Preferences >> Web >> Style Sheet >> 选择dt_extras里面的样式表
  3. Menu >> File >> Open Database…
  4. 打开~/Migrations/DEVONThink_Databases
  5. 打开iCloud同步:Preferences >> Sync >> check iCloud(CloudKit)

这将会合并在线数据库与步骤3导入的数据库,耗时较长

PDF Expert: 作为dt中pdf的外置阅读器

typora:作为dt中md的外置阅读器

  1. picGo上传配置: Upload Images - Typora Support
  2. PicGo
  3. 快捷键配置及配置文件同步: Shortcut Keys - Typora Support

自动化脚本

  1. dt_md_export: dt_extras/scripts
tell application id "DNtp"
	set theSelection to the selection
	if theSelection is {} then error "Please select some documents."
	set md_result to ""
	repeat with this_record in theSelection
		set md_link to (("[" & name of this_record as string) & "]" & "(" & reference URL of this_record as string) & ")"
		set md_result to md_result & "- " & md_link & return & return
	end repeat
	--display dialog md_result
	set the clipboard to md_result
end tell

SingleFile: 可以将网页保存为单独文件后存入dt

Eagle: 本地数据库配置

  1. 保存路径:~/Migrations/Eagle_Libraries

xmind/mindnode/drafts/marginnote:iCloud

分类打包:

  • 图片、视频: ~/Documents/media
  • pdf等电子书: 有用的放dt,没用的删除
  • 项目资料:按照项目整理,~/Documents/Projects
  • logins: 放在~/.ssh/logins里面的登陆用脚本

二、系统重装

关机 >> 重启的同时按住cmd+R >> 磁盘工具 >> 抹除 >> 重装

重启MAC,按住cmd+R直到屏幕上出现苹果的标志和进度条,进入Recovery模式;


三、系统设置

  • 触控板拖移:系统偏好设置 >> 辅助功能 >> 指针控制 >> 触控板选项:启动拖移 > 三指拖移

  • 系统自带配置目录:

cd ~/.config

里面至少有下列配置文件夹:

  • clash
  • karabiner
  • iTerm2

四、最优安装顺序

1. ClashX

2. iTerm2

详见iterm2

3. github/gitlab ssh key

ssh-keygen -t rsa -C "your_email@example.com"

4. vim config

KuanHsiaoKuo/vim_config: my custom vim configurations

5. karabiner

  • 首先GUI配置两个按键切换:caps_lock -> left_control; right_command -> escape
  • 然后会自动生成配置文件:
~/.config/karabiner/karaginer.json
  • 将karabiner.md里面的配置文件复制进去即可

6. manico/moom/popclip/Alfred

  • manico: 配置快捷键
iTerm2: shift+space
Appstore: option+a
  • moom:设置快捷建cmd+m
  • alfred: 依次安装alfred_workflows中的workflow

7. iTerm2 Around:

  • iterm2/iterm2_around.sh

8. DT/Marginnote3/xmind

9. Jetbrains Sync

包含:IDEA、Pycharm、Webstorm、Goland等 Jetbrains有两种同步配置方式, 都是插件,首次安装时自带:

  • IDE settings sync: 使用jetbrains账号同步,可以直接同步插件
  • settings repository: 使用git同步配置,不包含插件。

注意,二者只能激活其一,其中第二种激活后会自动覆盖第一种方式。

推荐第一种方式,同步更全面无痕。

第二种是idea默认开启,需要主动去关闭:

Preferences >> Plugins >> search "Settings Repository" >> unabled

osx系统设置

  1. 指定后缀名打开方式 找一个对应后缀名的文件 >> cmd + i >> 弹窗里面修改打开方式

github开源

tproxy: TCP 连接分析工具

kevwan/tproxy: A cli tool to proxy and analyze TCP connections.

image

这是go-zero框架的一个配套网络链接分析工具。

作者在开发后端服务时,经常需要监控项目的网络流量,因此他做了这么一款工具,主要辅助他完成如下工作:

  • 监控 gRPC 连接,何时连接、何时重连;

  • 监控 MySQL 连接池,找出生命周期策略;

  • 实时监控任何 TCP 连接。

开发相关

Another Redis Desktop Manager

Another Redis Desktop Manager | 更快、更好、更稳定的Redis桌面(GUI)管理客户端,兼容Windows、Mac、Linux,性能出众,轻松加载海量键值

ClashX: 梯子

clashX

Code: 代码导出图片化工具

CleanShot 2022-08-08 at 11.39.09@2x

img

Dash: 文档查阅工具

Dash for macOS - API Documentation Browser, Snippet Manager - Kapeli

gdelmas/IntelliJDashPlugin: A smart and simple plugin that provides keyboard shortcut access for Dash, Velocity or Zeal in IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm and Android Studio.

OSX Docker

Docker Desktop - Docker

Github Desktop

GitHub Desktop | Simple collaboration from your desktop

iTerm2: 终端神器

iTerm2 - macOS Terminal Replacement

IDEA: Fleet出来之前的选择

IntelliJ IDEA:JetBrains 功能强大、符合人体工程学的 Java IDE

Fleet: 期待的下一代Jetbrains综合编辑器

JetBrains Fleet:由 JetBrains 打造的下一代 IDE

JsonHero: 一款json全功能工具

img

可以直接分享json数据

Navicat Premium | Connects to multiple databases on a single GUI

OpenVPN: vpn工具

OpenVPN

Paw:Mac平台上接口测试神器,比postman更好

Paw – The most advanced API tool for Mac

PicGo: 本地上传图床工具

PicGo: A simple & beautiful tool for pictures uploading built by vue-cli-electron-builder

picgo aws s3插件:wayjam/picgo-plugin-s3: PicGo S3 插件

Patterns: 正则表达式测试工具

Patterns — krillapps

img

SnippetsLab:脚本片段管理工具

SnippetsLab - Keep Your Code At Your Fingertips

Script Debugger: AppleScript 编辑器

Script Debugger:

Script Debugger是Macintosh计算机的源代码编辑器和调试环境,适用于AppleScript编程语言以及其他基于Apple Inc.的开放脚本体系结构的语言。它是Late Night Software的产品。

Termius: ssh连接app

Termius - SSH platform for Mobile and Desktop

image-20220709174248270

why choose

这个app是ios/osx都有的,配置信息、Snippets还可以随着账号同步。虽然付费,不过也能在有些时候解决问题. 当然,还有一点很重要,我因为订阅得早,所以一年订阅费很低。

Warp: 观望中的终端工具,少了很多自定义

Warp: The terminal for the 21st century

效率相关

Karabiner-Elements: 改键神器

Karabiner-Elements

Amphetamine: mac防休眠

Amphetamine on the App Store

Alfred: 正如其名,Mac老管家

Alfred - Productivity App for macOS

CleanShot X: 截图标注工具

CleanShot X for Mac

需要登陆网站 >> License Manager >> 获取下载链接

Downie: 视频下载神器,youtube等通吃

Downie - YouTube Video Downloader for macOS - Charlie Monroe Software

Focus: 专注效率工具

Focus - Time Management on the App Store

GIF Brewery 3: gif制作工具

「GIF Brewery 3 by Gfycat」をApp Storeで

Manico: 应用快速切换快捷键配置工具,类似hook

Manico - macOS 下的快速 App 切换器

Moom: 窗口管理工具

Moom on the App Store

MenubarX - Productivity App for macOS

MenubarX on the Mac App Store

MenubarX is a powerful menu bar browser. You can add any web pages to the menu bar just like Native Apps. It will open up a new world for Web Apps.

  • Awarded on ProductHunt Daily and Weekly

  • Reviewed as the most worthy menu bar App (@monograph)

menubarx-2

coinbase

2048

settings2

WebCatalog: 类似Menubar

WebCatalog for Mac and PC | Turn Any Websites into Real Desktop Apps | WebCatalog

MultiDock: 浮动常用工具栏

可以自定义工作流相关工具,并漂浮在屏幕顶层,方便随时点击

MultiDock: Organize your favorite folders, files and applications with Dock’s (Dragthing alternative) • MacPlus Software

MultiDock is a simple application that allows you to organize frequently used applications, documents and folders using small panels (Dock’s). MultiDock evolved as a new version of ActiveDock was being created. Some these new features might be available in the next version of ActiveDock.

img

img

image-20220618110740510

PopClip: 剪贴板效率工具

PopClip for Mac

Paste: 剪贴板管理工具

Paste - Clipboard manager for Mac, iPhone, and iPad

The Unarchiver: 压缩解压缩工具

The Unarchiver | Top Free Unarchiving Software for macOS

学习工具

Anki:抽卡识记工具

Anki - powerful, intelligent flashcards

Marginnote:基于思维导图的阅读学习工具

Marginnote

Movist: 视频播放工具

Movist

Pdf Expert: pdf阅读工具

面向 Mac 的优秀 PDF 阅读应用 | 免费试用 | PDF 点睛

Drawboard PDF: 功能全面,尤其是笔记工具

Drawboard PDF

  1. 主打iOS平台,iPad/iPhone的体验惊人
  2. 桌面端使用浏览器代替。

四、数据管理

DEVONThink: 各自数据格式一站式管理工具

DEVONtechnologies | DEVONthink, professional document and information management for the Mac and iOS

Calibre: 书籍格式转换工具

calibre - E-book management

CleanMyMac: 电脑清理工具,不过我更喜欢格盘重装

CleanMyMac X: The Only Legit Mac Cleanup App. Get a Cleaner Mac in Minutes

Eagle: 图片收集管理工具

Eagle - 图片收集及管理必备工具

TotalFinder: Finder的完美强化插件

TotalFinder is a plugin, not a replacement

About TotalFinder

输出相关

Drafts: 随手记终极解决工具

Drafts | Where Text Starts

Day One: 颜值与功能并举的日记工具

Your Journal for Life | Day One - Your Journal for Life | Day One

Ulysses: 颜值优先的长文书写工具

Ulysses

Typora: 将Markdown玩透的笔记工具

Typora 官方中文站

drawio: UML图解决方案

jgraph/drawio-desktop: Official electron build of diagrams.net

GoodNotes: 找回书写的感觉

GoodNotes | Best Note-Taking App for iPad

MindNode: 颜值不错的简单思维导图工具

Mind Map & Brainstorm Ideas - MindNode

Monodraw:ASCII图的终极解决方案

Monodraw for macOS — Helftone

Monodraw 是一款专业强大的 ASCII 文本编辑器。可以基于纯文本轻松创建漂亮的代码说明注释、终端欢迎界面等。 支持画笔及形状,可以任意绘制。你甚至可以用它绘制纯文本图表、流程图,直观地来表示算法,数据结构,二进制格式等等。 因为它们都是文本,所以可以轻松嵌入几乎任何代码中。另外,还支持导出为图像 PNG 和 SVG 图片

两类思维导图:

Xmind:

XMind思维导图 | XMind中文官方网站

Scapple:

Scapple | Literature & Latte

与Scrivener是一家 高效学习法-利用Scapple打造10倍效率的笔记 - 知乎 纸和软件结合 第一,先在A4纸上或者自己的笔记本上做即时性笔记——记录一些学习时的零散的关键信息点。 第二,回到家,使用Scapple,将这些零散的关键信息点誊抄在上面 第三,对照这些零散的关键信息点,进入专注模式,进行索引式回顾,并在Scapple写下这些关键信息点的详细内容 第四,构建这些关键信息点之间的联系。 纯软件, 不做任何即时性笔记。 第一,直接使用Scapple,进入发散模式,不断的思考能够记住的一些关键信息点。 第二,构建这些关键信息点之间的联系。 Scapple之所以非常适合做笔记,是因为它是就人体大脑的思维模式所设计的。 当你不断创建内容(Notes)时,你通常处在发散模式; 当你对照内容去思考深挖详细信息时,你通常处在专注模式; 当你在构建Notes间的连接时,你更可能处于发散模式。

Scrivener: 比Ulysses更长的文章书写工具

Scrivener | Literature & Latte

区分提要与便签

Graph-easy: ASCII DSL语言工具

Graph-easy: Ascii DSL

brew install graphviz
cpan
sudo cpan Graph:Easy

沟通协作

Slack

Slack 是未来的工作场所

ToDesk

ToDesk远程控制软件下载-电脑客户端,移动app官网下载-ToDesk官网

Trello

Trello

OmniGroup Series

The Omni Group

插件相关(DEVONThink、Alfred)

2. DEVONThink

Trickster - Your recently used files, at your fingertips!

Trickster 会记录您在Mac上使用过的文件,您可以通过菜单栏快速的访问它们。finder有最近文件的功能,但是太简陋了,Trickster可以对你最近打的过的文件进行归类,哪怕你不小心关闭了文件,你照样可以通过Trickster快速找到它。

Hook is an easy way to copy links to files, emails, web pages and more. Paste and use them anywhere. Even bidirectionally link (“hook”) items together Replace the frustration of searching your Mac with the pleasure of using contextually relevant links. Use Hook to copy robust links to anything on your Mac or elsewhere (files, emails, tasks, PDFs, web pages, etc). Paste them anywhere. Hook automatically stores your links as bookmarks and optionally syncs them in iCloud. Help – Hook

Zotero | Your personal research assistant

Zotero is a free, easy-to-use tool to help you collect, organize, cite, and share research.

3. Alfred

More

Awesome Mac

Chrome插件整理

由于Chrome的插件极其丰富,这里就单独列一篇文章

如果对某个chrome插件感兴趣,可以在插件链接后面加’/related’

工具篇

Smart TOC: 自动生成右侧TOC

Displays a table of contents for every web page, making it easier to read/navigate long articles, documentations and online books

Vimium

Omni

alyssaxuu/omni: The all-in-one tool to supercharge your productivity ⌨️

flowy: 一款用js写的自动化工具

screenity: 网页录像/截图/标注工具

animockup: 制作网页动图

学习篇

Relingo:在阅读中掌握单词

Hypothesis: 网页&PDF标注工具

一个高度可定制化的网页&PDF标注工具。具体使用可见:开源、可定制的网页批注工具——Hypothesis - 少数派

可以配合插件备份之后使用:Wayback Machine - Chrome 网上应用店

资料篇

SingleFile: 全文保存工具

Inoreader RSS Reader Extension

Zoetero Connector

开发篇

Rust 搜索插件

Rust宏可视化插件

Octotree: github侧边栏

github 三维展示

Jiffy Reader: Bionic Reader

manico快捷键组合说明

一、manico

前奏

预先将karabiner安装并配置好,再来进行组合设置。

  • 将rigit cmd映射为cmd + option + shift + control
  • 将right option映射为 shift + control + command

具体组合

下方的right cmd/option都指上方对应的配置

  • 1Password: right cmd + 1
  • Anki: right option + a (right cmd + a 唤醒alfred,在alfred里面配置)
  • App Store : option+a
  • Chrome: right cmd + c
  • Drafts: control + i
  • Eagle: right cmd + e
  • Finder: option + f
  • IDEA: right cmd + i
  • iTerm: shift + space
  • marginnote: option + m
  • OmniFocus: right cmd + o
  • PDF Expert: right cmd + p
  • Sublime: right cmd + s
  • Safari: right option + s
  • DEVONThink 3: right cmd + t
  • Typora: right option + t
  • Ulysses: cmd + u
  • WeChat: right cmd + w

组合原则

  1. 频率高的组合键用大拇指按左/右cmd
  2. 尽量将组合键分摊在两只手

二、self_host

  • trickster: ctrl + z
  • hook: right_cmd + space

python处理脚本收集

将字幕文件转为json

spaCy自然语言处理

上面那个脚本转化的文本并没有标点符号断句等内容,所以还需要用NLP来优化。 这里的核心还在于使用spaCy对文本进行自然语言处理。

源码

import re
import json
import spacy
import sys


def parse_time(time_string):
    hours = int(re.findall(r'(\d+):\d+:\d+,\d+', time_string)[0])
    minutes = int(re.findall(r'\d+:(\d+):\d+,\d+', time_string)[0])
    seconds = int(re.findall(r'\d+:\d+:(\d+),\d+', time_string)[0])
    milliseconds = int(re.findall(r'\d+:\d+:\d+,(\d+)', time_string)[0])

    return (hours * 3600 + minutes * 60 + seconds) * 1000 + milliseconds


def parse_srt(srt_string):
    srt_list = []

    for line in srt_string.split('\n\n'):
        if line != '':
            index = int(re.match(r'\d+', line).group())

            pos = re.search(r'\d+:\d+:\d+,\d+ --> \d+:\d+:\d+,\d+',
                            line).end() + 1
            content = line[pos:]
            start_time_string = re.findall(
                r'(\d+:\d+:\d+,\d+) --> \d+:\d+:\d+,\d+', line)[0]
            end_time_string = re.findall(
                r'\d+:\d+:\d+,\d+ --> (\d+:\d+:\d+,\d+)', line)[0]
            start_time = parse_time(start_time_string)
            end_time = parse_time(end_time_string)

            srt_list.append({
                'index': index,
                'content': content,
                'start': start_time,
                'end': end_time
            })

    return srt_list


def remove_modals(total_words: list):
    modal_words = ['Yeah', 'yeah', 'Yep', 'yep', 'Uh', 'uh', 'okay', 'oh', 'Um', 'um', 'right']
    # 替换为删除线
    for index, word in enumerate(total_words):
        if word in modal_words:
            total_words[index] = f"~~{word}~~"


# 从当前位置开始,前/后找到一个有效位置
def find_valid_index(words_list: list, index, direction):
    if direction == 'pre':
        while index >= 0 and words_list[index].startswith("~~"):
            index -= 1
        if index >= 0:
            return index
        else:
            return None
    elif direction == 'after':
        while index < len(words_list) - 1 and words_list[index].startswith("~~"):
            index += 1
        if index < len(words_list):
            return index
        else:
            return None
    else:
        sys.exit('方向不对')


# 去除三个以内的重复词
def delete_duplicate(words_list: list):
    for index, word in enumerate(words_list):
        if word.startswith('~~'):
            continue
        # 以index为中心点向两边找
        pre_word_third, pre_word_secondary, pre_word, word_secondary, word_third = '', '', '', '', ''
        pre_index = find_valid_index(words_list, index - 1, 'pre')
        if pre_index:
            pre_word = words_list[pre_index]
        if pre_word:
            pre_index = find_valid_index(words_list, pre_index - 1, 'pre')
            if pre_index:
                pre_word_secondary = words_list[pre_index]
        if pre_word_secondary:
            pre_index = find_valid_index(words_list, pre_index - 1, 'pre')
            if pre_index:
                pre_word_third = words_list[pre_index]
        after_index = find_valid_index(words_list, index + 1, 'after')
        if after_index:
            word_secondary = words_list[after_index]
        if word_secondary:
            after_index = find_valid_index(words_list, after_index + 1, 'after')
            if after_index:
                word_third = words_list[after_index]
        # 先判断三个词的情况:
        if [pre_word_third, pre_word_secondary, pre_word] == [word, word_secondary, word_third]:
            print([pre_word_third, pre_word_secondary, pre_word])
            words_list[index], words_list[index + 1], words_list[index + 2] = \
                f"~~{words_list[index]}~~", f'~~{words_list[index + 1]}~~', f'~~{words_list[index + 2]}~~'
        elif [pre_word_secondary, pre_word] == [word, word_secondary]:
            print([pre_word_secondary, pre_word])
            words_list[index], words_list[index + 1] = \
                f"~~{words_list[index]}~~", f'~~{words_list[index + 1]}~~'
        elif pre_word == word:
            print(pre_word)
            words_list[index] = f"~~{words_list[index]}~~"
        # print(pre_word_third, pre_word_secondary, pre_word, word, word_secondary, word_third)
    return words_list


def parse_sentence(srt_strings: list):
    raw_total_words = ' '.join([item['content'] for item in srt_strings]).split(' ')
    total_words = [item.strip() for item in raw_total_words]
    # 借助python的默认用法:容器类型(列表、字典、对象等)在函数参数是传地址,原生类型(字符串、数字等)在函数参数是传值。
    remove_modals(total_words)
    delete_duplicate(total_words)
    # python -m spacy download en_core_web_sm
    nlp = spacy.load('en_core_web_sm')
    doc = nlp(' '.join(total_words))
    # for sent in doc.sents:
    #     print(sent.text_with_ws.replace(' ', ' '))
    #     print('\n')
    # print('#' * 50)
    sents = [sent.text_with_ws.replace('  ', ' ') for sent in doc.sents]
    return sents


if __name__ == "__main__":
    # srt_filename = 'Substrate Execute Block Code Walkthrough with Joe Petrowski and Shawn Tabrizi.srt'
    srt_filename = "Intro to Substrate codebase and FRAME pallet deep-dive with Joe Petrowski and Shawn Tabrizi.srt"
    title = srt_filename.split('.')[0]
    json_out_filename = srt_filename.replace('.srt', '.json')
    md_out_filename = srt_filename.replace('.srt', '.md')
    srt = open(srt_filename, 'r', encoding="utf-8").read()
    parsed_srt = parse_srt(srt)
    # parse_txt(parsed_srt)
    sentences = parse_sentence(parsed_srt)
    # open(json_out_filename, 'w', encoding="utf-8").write(
    #     json.dumps(parsed_srt, indent=2, sort_keys=True))
    # open(txt_out_filename, 'w', encoding='utf-8').write(
    #     '\n'.join([item['content'] for item in parsed_srt])
    # )
    content = f"# {title}\n" + '\n\n'.join(sentences)
    open(md_out_filename, 'w', encoding='utf-8').write(content)

ffmpeg合并视频文件

import os
import re
import sys
import subprocess
from subprocess import CalledProcessError


# brew install ffmpeg


def supported_merge(files, target_dir, merged_name):
    """
    ffmpeg只支持默认格式合并:
    Unsupported audio codec. Must be one of mp1, mp2, mp3, 16-bit pcm_dvd, pcm_s16be, ac3 or dts.
    :param files:
    :param target_dir:
    :return:
    """
    merge_cmd = " ffmpeg -i 'concat:%s' -c copy %s/%s.mpg"
    files_arg = '|'.join(files)
    # 合并mpg
    merge_status = os.system(merge_cmd % (files_arg, target_dir, merged_name))
    # 转为mp4
    if merge_status == 0:
        convert_status = os.system(
            f"ffmpeg -i {target_dir}/{merged_name}.mpg -y -qscale 0 -vcodec libx264 {target_dir}/{merged_name}.mp4")
    else:
        sys.exit('合并视频出错')
    if convert_status != 0:
        sys.exit('转化视频出错')
    os.system(f"rm -rf {target_dir}/*.mpg")
    # os.system(f"ffmpeg -i {target_file}.mpg {target_file}.MP4")


def mp4_to_mpg(file_list):
    """
    文件名问题:
    1. 空格
    2. 括号: 英文括号需要加'\'
    2. 竖线:需要替换
    :param file_list:
    :return:
    """
    for index, mp4 in enumerate(file_list):
        file_name = mp4.replace('.mp4', '')
        status = os.system(f'ffmpeg -i {mp4} -qscale 4 {file_name}.mpg')
        print(f"{index + 1}/{len(file_list)}: {status} {file_name}.mpg")


def subprocess_run(cmd: str):
    try:
        subprocess.run(cmd, shell=True, check=True, capture_output=True)
    except CalledProcessError as e:
        sys.exit(f'执行{cmd} 失败: {e}')
    except Exception as e:
        sys.exit(e)


def get_title_pic(title, pic_path):
    """ffmpeg加文字水印
    drawtext:绘制文本,也就是文字水印,相关参数第一个似乎要写=,其它参数写:。默认字体 Sans
    fontfile:字体文件
    > [Mac 电脑查看字体文件位置 | 温欣爸比的博客](https://wxnacy.com/2019/04/03/mac-fonts-path/)
    text:文字水印内容
    fontsize:水印字体大小,直接填数字
    box --是否使用背景框,默认为0
    boxcolor --背景框的颜色
    borderw --背景框的阴影,默认为0
    bordercolor --背景框阴影的颜色
    """
    target_pic_path = pic_path
    if not pic_path.endswith('.jpg'):
        pic_format = pic_path.split('.')[-1]
        jpg_pic_path = pic_path.replace(pic_format, 'jpg')
        convert_cmd = f"ffmpeg -i {pic_path} {jpg_pic_path}"
        subprocess_run(convert_cmd)
        print(convert_cmd)
        target_pic_path = jpg_pic_path
        rm_convert_jpg_cmd = f"rm {target_pic_path}"
    else:
        rm_convert_jpg_cmd = None
    output_path = f"{'/'.join(pic_path.split('/')[:-1])}/{title}_video_cover.jpg"
    # x=w-tw-th:y=h-th, 文本的位置,放置图片右下方位置;w、h 表示原图的宽、高;tw、th 表示文本宽高;在减去th 作为间距
    drawtext_config = {
        # "fontfile": "MiSans-Normal.ttf",
        "fontfile": "/System/Library/Fonts/PingFang.ttc",
        "text": title,
        "x": "110",
        "y": "250",
        "fontsize": "38",
        "fontcolor": "black",
        "shadowy": "0"
    }
    drawtext = ':'.join([f"{key}={value}" for key, value in drawtext_config.items()])
    insert_cmd = f'ffmpeg  -i {target_pic_path}  -vf drawtext={drawtext} -y {output_path}'
    subprocess_run(insert_cmd)
    print(insert_cmd)
    if rm_convert_jpg_cmd:
        subprocess_run(rm_convert_jpg_cmd)
    return output_path


def get_cover_video(video_path):
    mp3_path = video_path.replace('.mp4', '.mp3')
    extract_mp3_cmd = f"ffmpeg -i {video_path} -f mp3 -vn {mp3_path}"
    subprocess_run(extract_mp3_cmd)
    video_name = video_path.split('/')[-1]
    video_dir = '/'.join(video_path.split('/')[:-1])
    title = '-'.join(video_name.split('.')[:-1])
    pic_path = video_path.replace(".mp4", ".jpg")
    cover_path = get_title_pic(title, pic_path)
    cover_video = f"{video_dir}/{video_name}_covered.mp4"
    convered_mp4_cmd = f"ffmpeg -loop 1 -i {cover_path} -i {mp3_path} -c:a copy -c:v libx264 -shortest {cover_video}"
    subprocess_run(convered_mp4_cmd)
    print(convered_mp4_cmd)
    subprocess_run(f"rm {mp3_path}")
    subprocess_run(f"rm {cover_path}")
    return cover_video


def merge(target_dir, covered=False):
    print('*' * 20, target_dir)
    os.popen(f"rm -rf {target_dir}/*.mpg")
    cmd_res = os.popen(f'ls {target_dir}/*.mp4').read()
    output_file = target_dir.split("/")[-1]
    file_list = [file for file in cmd_res.split('\n') if file]
    if covered:
        file_list = [get_cover_video(file) for file in file_list]
    pattern = re.compile(r'(\d+)')
    file_list.sort(key=lambda x: int(pattern.findall(x)[-2]))
    try:
        mp4_to_mpg(file_list)
    except Exception:
        sys.exit('转化分视频出错!')

    mpg_cmd_res = os.popen(f'ls {target_dir}/*.mpg').read()
    mpg_file_list = [mpg_file for mpg_file in mpg_cmd_res.split('\n') if mpg_file]
    mpg_file_list.sort(key=lambda x: int(pattern.findall(x)[0]))

    try:
        supported_merge(mpg_file_list, target_dir, output_file)
        if covered:
            subprocess_run(f"rm {target_dir}/*_covered.mp4")
    except Exception:
        print("使用前记得调整一下文件名: 空格、括号等")


def main():
    # if len(sys.argv) == 1:
    #     sys.exit("请传入待合并视频文件夹📁目录")
    # else:
    #     target_dir = sys.argv[1]
    # target_dirs = [target_dir]
    target_dirs = ['']
    for item in target_dirs:
        merge(item, covered=True)


if __name__ == "__main__":
    main()

IINA与ffmpeg给视频添加章节

ffmpeg

ffmpeg -i part1.mp4 -f ffmetadata part1.txt
ffmpeg -i part1.mp4 -i part1.txt -map_metadata 1 -codec copy part1_insert.mp4

mpv screenshot template

Info

screenshot-template: %{filename}-%p

  1. 按照视频文件名先分段,方便统一存放

本来打算用screenshot-directory参数,但是要报错,就算了

  1. %p: 截屏的时间,可以排序。这样方便后续按时间插入新章节。

CleanShot 2022-09-06 at 21.52.28@2x

思路

@startuml
title
    视频教材化
    主要结合IINA、MPV和FFMPEG给视频文件添加章节
end title
participant mpv[
    =MPV内核
]
actor 手工操作 as mannual
participant iina[
    =IINA播放器
]
participant ffmpeg[
    =ffmpeg工具
    ----
    python脚本
    主要处理视频
    添加章节书签
]
mpv -> iina: mpv内核指令
iina -> iina: 修改截图格式
note left
    偏好设置
    高级
    启用高级设置
    勾选记录日志、使用mpv的OSD
    额外mpv选项:screenshot-template %n%f-%p
    注意每次修改格式都要重启
end note
mannual-> iina: 使用快捷键截图1
mannual-> iina: 使用快捷键截图2
mannual-> iina: ...
mannual-> iina: 使用快捷键截图n
mannual-> mannual: 手动添加章节名称
iina -> ffmpeg: 开始处理截图文件夹
note right
1. 遍历文件夹,获取文件列表
2. 将文件名依次处理,提取出时间,生成时间表
3. 手动给时间表添加标题
end note
ffmpeg -> ffmpeg: 处理文件夹的文件,生成对应视频文件的章节时间表
note left
0:23:20 Start
0:40:30 First Performance
0:40:56 Break
1:04:44 Second Performance
1:24:45 Crowd Shots
1:27:45 Credit
end note
ffmpeg -> ffmpeg: 根据时间表生成视频章节文件
note left
;FFMETADATA1
major_brand=isom
minor_version=512
compatible_brands=isomiso2avc1mp41
encoder=Lavf59.16.100

[CHAPTER]
TIMEBASE=1/1000
START=1
END=448000
title=The Pledge
end note
ffmpeg -> ffmpeg: 将章节文件压入视频文件,生成新视频文件
note left
ffmpeg -i part1.mp4 -i part1.txt -map_metadata 1 -codec copy part1_insert.mp4
end note

@enduml

源码

"""
给视频文件添加章节书签
"""

import re
import os
import sys
import subprocess
from subprocess import CalledProcessError

def times_chapters(time_path: str, save_path: str):
    """
    1. save_path: 保存在视频文件目录中。
    :param time_path:
    :param save_path:
    :return:
    """
    chapters = list()

    with open(time_path, 'r') as f:
        line_pattern = re.compile(r"(\d):(\d{2}):(\d{2}) (.*)")
        for line in f:
            if line.strip():
                hrs, mins, secs, title = line_pattern.findall(line.strip())[0]
                hrs, mins, secs = int(hrs), int(mins), int(secs)
                minutes = (hrs * 60) + mins
                seconds = secs + (minutes * 60)
                timestamp = (seconds * 1000)
                chap = {
                    "title": title,
                    "startTime": timestamp
                }
                chapters.append(chap)

    text = """;FFMETADATA1
major_brand=isom
minor_version=512
compatible_brands=isomiso2avc1mp41
encoder=Lavf59.16.100

    """

    for index, chap in enumerate(chapters):
        title = chap['title']
        start = chap['startTime']
        if index + 1 < len(chapters):
            end = chapters[index + 1]['startTime'] - 1
        else:
            end = start + 10000
        """
        [CHAPTER]
        TIMEBASE=1/1000
        START={start}
        END={end}
        title={title}
        
        """
        chapter = ["[CHAPTER]", "TIMEBASE=1/1000", f"START={start}", f"END={end}", f"title={title}", "\n"]
        text += '\n'.join(chapter)
    file_name = re.findall(r'(\d.*?\.mp4)', time_path)[0]
    file_name = file_name.split('/')[-1]
    chapters_path = f"{save_path}/{file_name}.txt"
    if os.path.exists(chapters_path):
        with open(chapters_path, 'r') as f:
            raw_text = f.read()
    else:
        raw_text = ''
    if text != raw_text:
        with open(chapters_path, "w") as f:
            f.write(text)
        return chapters_path
    else:
        return None


def gen_timetable(screenshots_path: str):
    """
    配合IINA的截图格式:
    screenshot-template: %{filename}-%p-
    0:23:20 Start
    0:40:30 First Performance
    0:40:56 Break
    1:04:44 Second Performance
    1:24:45 Crowd Shots
    1:27:45 Credits
    :param screenshots_path:
    :return:
    """
    info_pattern = re.compile(r'(\d.*?\.mp4)-(\d+:\d{2}:\d{2})-(.*?).png')
    ls_png_cmd = f"ls {screenshots_path}/*.png"
    try:
        png_cmd_res = subprocess.run(ls_png_cmd, shell=True, check=True, capture_output=True)
    except CalledProcessError as e:
        png_cmd_res = e
    if png_cmd_res.returncode == 0:
        png_list = png_cmd_res.stdout.decode().split('\n')
        png_infos = {}
        for png in png_list:
            png_info = info_pattern.findall(png)
            if png_info:
                video, timestamp, title = png_info[0]
                # 去掉截图归类目录
                # 例如:130-139.tokio-runtime/130-139.tokio-runtime.mp4-00:00:13-第一节-概要介绍.png
                video = video.split('/')[-1]
                if not title:
                    title = '未命名章节'
                if not png_infos.get(video):
                    png_infos[video] = []
                png_infos[video].append([timestamp, title])
        # 按照第二个时间点元素排序
        files = []
        for video, chapters in png_infos.items():
            file_path = f"{screenshots_path}/{video}.txt"
            chapters.sort(key=lambda item: item[0].split(':'))
            with open(file_path, 'w') as f:
                for timestamp, chapter_name in chapters:
                    f.writelines(f"{timestamp} {chapter_name}\n ")
            files.append(file_path)
        return files
    else:
        sys.exit(f"执行指令{ls_png_cmd}出错:{png_cmd_res.stderr.decode()}")


def categorized_screenshots(root_screen_directory):
    info_pattern = re.compile(r'(\d.*?)\.mp4-(\d+:\d{2}:\d{2})-(.*?).png')
    ls_png_cmd = f"ls {root_screen_directory}/*.png"
    try:
        png_cmd_res = subprocess.run(ls_png_cmd, shell=True, check=True, capture_output=True)
    except CalledProcessError as e:
        png_cmd_res = e
    if png_cmd_res.returncode == 0:
        png_list = png_cmd_res.stdout.decode().split('\n')
        file_titles = []
        for png in png_list:
            png_info = info_pattern.findall(png)
            if png_info:
                video_title, timestamp, title = png_info[0]
                if video_title and video_title not in file_titles:
                    file_titles.append(video_title)
        # 新建文件夹并整合截图
        for title in file_titles:
            dir_path = f"{root_screen_directory}/{title}"
            if not os.path.exists(dir_path):
                os.popen(f"mkdir {dir_path}")

            os.popen(f"mv {root_screen_directory}/{title}.*.png {dir_path}/")
    dir_res = os.popen(f"ls -d {root_screen_directory}/*/")
    dirs = dir_res.read().split('\n')
    return [item[:-1] for item in dirs]


def main(s_dir):
    timetables = gen_timetable(s_dir)
    chapter_files = []
    for timetable in timetables:
        chapter_path = times_chapters(timetable, video_path)
        if chapter_path:
            chapter_files.append(chapter_path)

    for chapter_file in chapter_files:
        video_name = re.findall(r'(\d.*?)\.mp4', chapter_file)[0]
        edit_video_path = f"{video_path}/{video_name}.mp4"
        inserted_video_path = f"{video_path}/{video_name}-chapters.mp4"
        """
        -y: 默认覆盖, 但是这里载入章节文件不可以in-place修改。
        -i: input
        -codec: 编解码
        -map_metadata 1: 只匹配头部内容,只能在第一次添加时生效
        -map_chapters 1: 匹配章节,在后续修改章节时需要加上
        """
        merge_command = f"ffmpeg -y -i {edit_video_path} -i {chapter_file} -map_metadata 1 -map_chapters 1 -codec copy {inserted_video_path}"
        delete_command = f"rm {edit_video_path}"
        mv_command = f"mv {inserted_video_path} {edit_video_path}"
        os.system(merge_command)
        os.system(delete_command)
        os.system(mv_command)


if __name__ == "__main__":
    timefile = ''
    chapter_file = ''
    if len(sys.argv) != 3:
        sys.exit('请按顺序加入截图文件夹路径和视频文件路径')
    else:
        ss_path, video_path = sys.argv[1], sys.argv[2]
    # times_chapters(timefile, chapter_file)
    screenshot_dirs = categorized_screenshots(ss_path)
    for screenshot_dir in screenshot_dirs:
        if screenshot_dir:
            main(screenshot_dir)

主力App深度使用

Alfred使用

workflows collection

直接打开本分支路径下,materials/alfred_workflows里面的内容分别双击即可安装

change log

更新到v5版本的新功能

接下来主要介绍关于任务开发的更新,其他还有许多细节可以看看官方网页

模块化

Alfred 5’s Example Prefab

更多内置功能,并会在未来提供全新的任务开发工具

Alfred’s new Automation Tasks object configuration

支持直接在任务中调用Shortcuts

Run macOS Shortcuts in your Workflows

参考资源

复制url快捷动作修改

  • 用javascript写的,使用oascript执行

CleanShot 2022-08-03 at 20.37.41@2x

ObjC.import('stdlib');

const NIL = $();

class Browser {
    constructor(bundleId) {
        this.app = Application(bundleId);
        this.key = {
            currentTab: 'currentTab',
            title: 'title',
            url: 'url'
        };
    }

    hasWindow() {
        return this.app.running() && this.app.windows.length;
    }

    get currentTab() {
        if (this.hasWindow()) {
            return this.app.windows.at(0)[this.key.currentTab]();
        } else {
            return;
        }
    }

    get currentTabInfo() {
        var tab = this.currentTab;

        if (tab) {
            return {
                title: tab[this.key.title](),
                url: tab[this.key.url]()
            };
        } else {
            return {};
        }
    }
}

class Chrome extends Browser {
    constructor() {
        super('com.google.Chrome');
        this.key.currentTab = 'activeTab';
    }
}

class Safari extends Browser {
    constructor() {
        super('com.apple.Safari');
        this.key.title = 'name';
    }
}

class SafariPreview extends Browser {
    constructor() {
        super('com.apple.SafariTechnologyPreview');
        this.key.title = 'name';
    }
}

class Alfred {
    static get dataPath() {
        return $.getenv('alfred_workflow_data');
    }

    static generateOutput(data, templates) {
        const regExp = /\$\{([^}]+)\}/;
        let match;

        const items = templates.map(template => {
            let text = template.format;

            if (text.match(/^function/)) {
                text = eval(`(${text})`)(data);
            } else {
                while (match = regExp.exec(text)) {
                    text = text.replace(match[0], data[match[1]]);
                }
            }

            return {
                arg: text,
                subtitle: text,
                text,
                title: template.title
            }
        });

        return JSON.stringify({
            items
        });
    }
}

class App {
    constructor() {
        this.dataPath = Alfred.dataPath;
        // 这里是默认配置路径,删除之后才会执行initConfig()之后重新配置
        this.configPath = `${this.dataPath}/config.json`;
        console.log('配置路径:', this.configPath)
        if (!this.hasConfig()) {
            this.initConfig();
        }
    }

    hasConfig() {
        return $.NSFileManager.defaultManager.fileExistsAtPath(this.configPath);
    }

    initConfig() {
        var fileManager = $.NSFileManager.defaultManager;
        var config = JSON.stringify([
            {"format": "${url}", "title": "URL"},
            {"format": "${title}", "title": "Title"},
            {"format": "<a href=\"${url}\">${title}</a>", "title": "Anchor"},
            {"format": "[${title}](${url})", "title": "Markdown"},
            {"format": "[[${url} ${title}]]", "title": "Plantuml"}
            ]
        );
        console.log(config)
        var error = $();
        fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(this.dataPath, true, NIL, error);
        fileManager.createFileAtPathContentsAttributes(this.configPath, config, NIL);
    }

    get data() {
        var processes = Application('System Events').processes;
        var frontmost = processes.whose({frontmost: {'=': true}}).name().toString();

        if (frontmost === 'Google Chrome') {
            return new Chrome().currentTabInfo;
        } else if (frontmost === 'Safari') {
            return new Safari().currentTabInfo;
        } else if (frontmost === 'Safari Technology Preview') {
            return new SafariPreview().currentTabInfo;
        } else {
            if (processes.byName('Google Chrome').exists()) {
                return new Chrome().currentTabInfo;
            } else if (processes.byName('Safari').exists()) {
                return new Safari().currentTabInfo;
            } else if (processes.byName('Safari Technology Preview').exists()) {
                return new SafariPreview().currentTabInfo;
            }
        }
    }

    get templates() {
        // console.log($.NSString.stringWithContentsOfFile(this.configPath).js)
        return JSON.parse($.NSString.stringWithContentsOfFile(this.configPath).js) || [];
    }

    run() {
        var data = this.data;
        var templates = this.templates;
        if (!data || !templates) {
            return;
        }

        return Alfred.generateOutput(data, templates);
    }
}

function run() {
    return new App().run();
}

Anki使用维护技巧

牌组设计理念

以主题为真实牌组

以Rust编程学习为例,这里可以将Rust作为一个牌组名称

使用标签分为子组

一个主题包含方方面面,这些方面加上标签之后,可以组合出自己想要着重学习的特色筛选牌组

  1. 选中某个标签,按下cmd+g创建筛选牌组
  2. 接着加入细节
CleanShot 2022-09-16 at 20.13.58@2x
  1. 可以查看更多细节

Filtered Decks - Anki Manual

自定义Anki模版

由于本人最为习惯md语法,再加上mermaid、语法高亮等需求,所以折腾一下,制作了一个anki卡片模版: showdown-hightlight-mermaid. 另外在《marginnote使用自定义模版》一文中的折腾过程,添加了一个MNLink的字段。

正面模版

image-20220606234758347

<div class="section">
    <div class="Description md-content"></div>
</div>

<script>
    function addStylesheet(src, callback) {
    var s = document.createElement('link');
    s.rel = 'stylesheet';
    s.href = src;
    s.onload = callback;
    document.head.appendChild(s);
}
    function addScript(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.type = "text/javascript";
    s.onload = callback;
    document.body.appendChild(s);
}

    function addMermaid() {
    // 开始mermaid配置
    addScript(mermaidUrl, function () {
        let config = {
            startOnLoad: true,
            theme: 'neutral',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'Basis'
            },
            securityLevel: 'loose'
        }
        //mermaid.initialize(config)
        mermaid.init()
    });
}

    function replaceAllWhitespaceWithSpace(str) {
    return str.replace(/[\t\v\f \u00a0\u2000-\u200b\u2028-\u2029\u3000]/g, ' ');
}
    // anki本地存放多媒体文件路径: ~/Library/Application Support/Anki2/
    <account>/collection.media
        var highlightcssUrl = "_highlight.default.min.css";
        var showdownsCssUrl = "_showdowns.min.css"
        var showdownUrl = "_showdown.min.js";
        var showdownsUrl = "_showdowns.min.js";
        // https://cdn.bootcss.com/mermaid/8.0.0-rc.8/mermaid.min.js
        var mermaidUrl = "_mermaid.min.js";
        var highlightjsUrl = "_highlight.min.js";
        addStylesheet(highlightcssUrl, function () {});
        addStylesheet(showdownsCssUrl, function () {});
        addScript(showdownUrl, function () {
            addScript(highlightjsUrl, function () {
                function processShowdownDivs() {
                    var showdownConverter = new showdown.Converter({tables: true}); // 打开表格支持
                    showdownConverter.setFlavor('github');
                    document.querySelectorAll('div.md-content').forEach((div) => {
                        var rawText = div.innerText.replace(/<\/div>/g, ""); // div.innerHTML.replace(/<\/div>/g, ""); //innerText;
                        var classes = div.className.replace(/md-content/g, "");
                        var text = replaceAllWhitespaceWithSpace(rawText); //.replace(/<br>|<div>/g, "\n");
                        var html = showdownConverter.makeHtml(text);
                        var newDiv = document.createElement('div');
                        newDiv.innerHTML = html;
                        newDiv.className = classes;

                        newDiv.querySelectorAll('pre code').forEach((block) => {
                            hljs.highlightBlock(block);
                        });

                        div.parentNode.insertBefore(newDiv, div.nextSibling);
                        div.style.display = 'none';
                        addMermaid();
                    });
                };

                processShowdownDivs();
            });

        });

</script>

背面模版

image-20220606234940109



<hr id=answer>

<div class="section">
    <div id="back" class="Description md-content">感悟:</br></div>
</div>

<div class="section">
    <div id="back" class="Description md-content">回答: </br></div>
</div>

<div class="section">
    <div id="back" class="Description md-content">来源: </br></div>
</div>

说明

  1. anki本地存放多媒体文件路径:
~/Library/Application Support/Anki2/<account>/collection.media
  1. 相关js文件可在github main分支的scripts/anki_md_js里面找到

drafts深度使用技巧

使用技巧

双向链接

官方的叫法是 Wiki-Style Cross-Linking,这是一个很不错的功能,方便同一个主题的草稿下跳转,既可以链接文章,也可以进行关键词搜索。先在草稿中输入 [[,然后 Drafts 就会自动跳出待选的草稿标题,点击即可创建跳转链接。

相关actions

模版写作

草稿引用

在版本 29 更新中,更新了一个名为「Insert Full Text of Other Drafts」的功能,翻译过来就是草稿全文的引用。它的语法和标准 Markdown 有些类似,在 Markdown 中引用是一个 >,而 Drafts 中如果需要对某个草稿进行全文引用,可以输入 << 进行选择引用。输入两个 < 之后,Drafts 弹出了草稿选择列表,选择需要引用插入的草稿,Drafts 就会直接将这段文本复制进来,而不用手动切会草稿列表,复制之后再粘贴过来。如果在 Drafts 中之前有很多零碎的想法,在需要将这些想法汇总,写成具有条理性的文章,那么这个功能就可以帮用户快速引用其他草稿。

动作收集

md格式化

只支持macOS

npm install -g prettier 

preview

自定义: 需要pro版本

打开开发者模式

自定义语法高亮

自定义主题

// See online documentation for examples // https://docs.getdrafts.com/docs/actions/scripting String.prototype.format = function () { if (arguments.length == 0) return this; var param = arguments[0]; var s = this; if (typeof (param) == ‘object’) { for (var key in param) s = s.replace(new RegExp(“\{” + key + “\}”, “g”), param[key]); return s; } else { for (var i = 0; i < arguments.length; i++) s = s.replace(new RegExp(“\{” + i + “\}”, “g”), arguments[i]); return s; } } const addToc = content => { const headerLines = content.split(‘\n’).filter(line => /^#+\s+1+/.test(line)) if (headerLines.length == 0) { alert(“No Markdown headers (e.g. ## Header) found”) return } const tocLines = [] let lastLevel = 0 for (let i = 0; i < headerLines.length; i++) { const splitMatch = headerLines[i].match(/^(#+)\s+(.)$/) // - 2 assumes the first header is h2 const level = splitMatch[1].length - 2 if (level < 0) { alert(“h1 headers (#) are not compatible with Table of Contents. Please use h2 headers (##) and below.”) return null } if (level > lastLevel + 1) { alert(“Cannot make a table of contents if header levels are skipped, e.g. ## followed by ####”) return } lastLevel = level const headerText = splitMatch[2] // tocLines.push(“ “.repeat(level) + “ “ + headerText + “test_toc”) tocLines.push(“{0}* {1}”.format(“ “.repeat(level), headerText, headerText)) } if (tocLines[0][0] != “*”) { alert(“The first header must be a h2 (##)”) return }

// 为了和github上传自动添加toc的脚本一致
let startMatch = content.match(/<!--ts-->/)
let endMatch = content.match(/<!--te-->/)
if (startMatch == null && endMatch == null) {
    const firstHeaderMatch = content.match(/^(#+)\s+(.*)$/m)
    content = `${content.substring(0, firstHeaderMatch.index)}<!--ts--><!--te-->\n\n${content.substring(firstHeaderMatch.index)}`
    startMatch = content.match(/<!--ts-->/)
    endMatch = content.match(/<!--te-->/)
}
if (startMatch == null || endMatch == null) {
    alert("You need both <!--ts--> and <!--te--> in your draft to place a table of contents")
    return
}
if (endMatch.index < startMatch.index) {
    alert("<!--ts--> must come before <!--te-->")
    return
}
const startPos = startMatch.index + startMatch[0].length
const endPos = endMatch.index
return `${content.substring(0, startPos)}\n${tocLines.join("\n")}\n${content.substring(endPos)}`

}

const newBody = addToc(draft.lines.slice(1).join(“\n”)) if (newBody != null) { draft.content = ${draft.lines[0]}\n${newBody} draft.update() }

sigil epub 编辑器

来源

karabiner配置说明

路径

~/.config/karabiner

karabiner.json

  1. Disable command + Q in web browser
  2. Change right_option to shift+control+command
  3. Change right_command to command+control+option+shift, press alone be escape
  4. Change left_cotnril+hjkl to arrow keys
  5. Change left_control+0/$/d/u to home/end/page_down/page_up
  6. Mapping [left_option={1-0,-,=}] to {F1-F10, F11, F12}
{
  "global": {
    "check_for_updates_on_startup": true,
    "show_in_menu_bar": true,
    "show_profile_name_in_menu_bar": false
  },
  "profiles": [
    {
      "complex_modifications": {
        "parameters": {
          "basic.simultaneous_threshold_milliseconds": 50,
          "basic.to_delayed_action_delay_milliseconds": 500,
          "basic.to_if_alone_timeout_milliseconds": 1000,
          "basic.to_if_held_down_threshold_milliseconds": 500,
          "mouse_motion_to_scroll.speed": 100
        },
        "rules": [
          {
            "description": "Disable command + Q in web browser",
            "manipulators": [
              {
                "conditions": [
                  {
                    "bundle_identifiers": [
                      "^org\\.mozilla\\.firefox$",
                      "^com\\.google\\.Chrome$",
                      "^com\\.apple\\.Safari$"
                    ],
                    "type": "frontmost_application_if"
                  }
                ],
                "from": {
                  "key_code": "q",
                  "modifiers": {
                    "mandatory": [
                      "command"
                    ],
                    "optional": [
                      "caps_lock"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "vk_none"
                  }
                ],
                "type": "basic"
              }
            ]
          },
          {
            "description": "Change right_option to shift+control+command",
            "manipulators": [
              {
                "from": {
                  "key_code": "right_option"
                },
                "to": [
                  {
                    "key_code": "left_shift",
                    "modifiers": [
                      "left_control",
                      "left_command"
                    ]
                  }
                ],
                "type": "basic"
              }
            ]
          },
          {
            "description": "Change right_command to command+control+option+shift,press alone be escape",
            "manipulators": [
              {
                "from": {
                  "key_code": "right_command",
                  "modifiers": {
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "left_option",
                    "modifiers": [
                      "left_command",
                      "left_control",
                      "left_shift"
                    ]
                  }
                ],
                "to_if_alone": [
                  {
                    "key_code": "escape"
                  }
                ],
                "type": "basic"
              }
            ]
          },
          {
            "description": "Change left_control+hjkl to arrow keys",
            "manipulators": [
              {
                "from": {
                  "key_code": "h",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "left_arrow"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "j",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "down_arrow"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "k",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "up_arrow"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "l",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "right_arrow"
                  }
                ],
                "type": "basic"
              }
            ]
          },
          {
            "description": "Change left_control+0/$/d/u to home/end/page_down/page_up (rev 2)",
            "manipulators": [
              {
                "from": {
                  "key_code": "0",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "home"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "$",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "end"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "d",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "page_down"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "u",
                  "modifiers": {
                    "mandatory": [
                      "left_control"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "page_up"
                  }
                ],
                "type": "basic"
              }
            ]
          },
          {
            "description": "Mapping [left_option-{1-0,-,=} to {F1-F10,F11,F12}",
            "manipulators": [
              {
                "from": {
                  "key_code": "1",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f1"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "2",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f2"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "3",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f3"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "4",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f4"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "5",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f5"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "6",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f6"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "7",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f7"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "8",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f8"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "9",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f9"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "0",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f10"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "hyphen",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f11"
                  }
                ],
                "type": "basic"
              },
              {
                "from": {
                  "key_code": "equal_sign",
                  "modifiers": {
                    "mandatory": [
                      "left_option"
                    ],
                    "optional": [
                      "any"
                    ]
                  }
                },
                "to": [
                  {
                    "key_code": "f12"
                  }
                ],
                "type": "basic"
              }
            ]
          }
        ]
      },
      "devices": [],
      "fn_function_keys": [
        {
          "from": {
            "key_code": "f1"
          },
          "to": [
            {
              "key_code": "display_brightness_decrement"
            }
          ]
        },
        {
          "from": {
            "key_code": "f2"
          },
          "to": [
            {
              "key_code": "display_brightness_increment"
            }
          ]
        },
        {
          "from": {
            "key_code": "f3"
          },
          "to": [
            {
              "key_code": "mission_control"
            }
          ]
        },
        {
          "from": {
            "key_code": "f4"
          },
          "to": [
            {
              "key_code": "launchpad"
            }
          ]
        },
        {
          "from": {
            "key_code": "f5"
          },
          "to": [
            {
              "key_code": "illumination_decrement"
            }
          ]
        },
        {
          "from": {
            "key_code": "f6"
          },
          "to": [
            {
              "key_code": "illumination_increment"
            }
          ]
        },
        {
          "from": {
            "key_code": "f7"
          },
          "to": [
            {
              "key_code": "rewind"
            }
          ]
        },
        {
          "from": {
            "key_code": "f8"
          },
          "to": [
            {
              "key_code": "play_or_pause"
            }
          ]
        },
        {
          "from": {
            "key_code": "f9"
          },
          "to": [
            {
              "key_code": "fastforward"
            }
          ]
        },
        {
          "from": {
            "key_code": "f10"
          },
          "to": [
            {
              "key_code": "mute"
            }
          ]
        },
        {
          "from": {
            "key_code": "f11"
          },
          "to": [
            {
              "key_code": "volume_decrement"
            }
          ]
        },
        {
          "from": {
            "key_code": "f12"
          },
          "to": [
            {
              "key_code": "volume_increment"
            }
          ]
        }
      ],
      "name": "Default profile",
      "parameters": {
        "delay_milliseconds_before_open_device": 1000
      },
      "selected": true,
      "simple_modifications": [
        {
          "from": {
            "key_code": "caps_lock"
          },
          "to": [
            {
              "key_code": "left_control"
            }
          ]
        }
      ],
      "virtual_hid_keyboard": {
        "caps_lock_delay_milliseconds": 0,
        "country_code": 0,
        "indicate_sticky_modifier_keys_state": true,
        "keyboard_type": "ansi",
        "mouse_key_xy_scale": 100
      }
    }
  ]
}

参考资源

关于分层

缘起

对于一些核心主力深度使用的app,比如Omni系列,Jetbrains系列,我觉得完全值得专门设置一层按键

关于分层

Hyper 键只有一颗,用久了总有键位冲突不够用的那天,比如我既想用 S 键触发 Search,又想用它激活 Sorted 3。利用层(layer)的概念,可以让键盘上的每个键都能成为独一无二的修饰键。

所谓层

所谓层,可以理解为按下某个键后,键盘上其他键的功能随之发生变化,例如下图就是按下 option 键后键盘的变化,我们可以称之为「option 层」。

img

其他可以作为分层键的

其他可作为 modifier key 的按键有:

, . space Tab

参考资源

goodnotes小技巧

添加超链接

Adding external links – GoodNotes Support

add_external_link

  1. 使用文本框工具输入文本
  2. 在编辑状态下选中链接文本
  3. 弹出菜单中会出现链接选项

在浏览器随时查看

Marginnote深度使用整理

小技巧

朗读模式

MN的朗读模式本质上是对划选高亮内容形成的卡片进行朗读,这样就有许多细节操作可以添加。比如给卡片添加标题、添加评论、修改卡片内容等。

Marginnote支持将勾画的重点进行朗读,并且可以后台运行并朗读。这一点在iPhone上尤为令我动心。之前我主要用微信读书听书,但是微信读书在朗读技术书籍的时候有个问题,总要将代码部分内容也读出来,这就让我不容易抓住重点。

到了Marginnote这里就巧妙地将这个问题解决:只朗读勾画的重点内容。

要注意选左边的三个小点

  • macOS:

image-20220608000253594

image-20220608000328467

  • iOS:

image-20220608000350355

image-20220608000408181

多屏模式

打开定位功能

CleanShot 2022-06-08 at 11.53.24@2x

cmd + n 打开新窗口

多屏功能无法将卡片集中在当前焦点

裁边要点

在使用marginnote制作卡片时,由于页头的文字会被选进去,可以使用裁边功能去掉

卡片制作规范

卡片标题

  1. 需要加上编号

卡片内容

  1. 全部识别为文本

  2. 使用md语法改写:主要为了导出到Anki之后,可以直接用自制md卡牌模版渲染

卡片评论

卡片追加

Mdbook电子书发布工具使用说明

使用要点

基本结构

tree -L 2                                                                                                                                                                                                                              ─╯
.
├── README.md # 项目基本说明
├── bin # mdbook可执行文件
│   └── mdbook
├── book.toml # 书籍基本信息配置
├── mermaid-init.js # mermaid用到的js文件
├── mermaid.min.js # mermaid用到的js文件
├── mytheme # 书籍用到的主题
│   ├── FontAwesome
│   ├── ayu-highlight.css
│   ├── book.js
│   ├── clipboard.min.js
│   ├── css
│   ├── favicon.png
│   ├── favicon.svg
│   ├── fonts
│   ├── head.hbs
│   ├── header.hbs
│   ├── highlight.css
│   ├── highlight.js
│   ├── index.hbs
│   ├── mod.rs
│   ├── playground_editor
│   ├── redirect.hbs
│   ├── searcher
│   └── tomorrow-night.css
├── scripts # 一些文章里面提及的脚本文件
│   ├── anki_md_js
│   ├── gh-md-toc
│   ├── toc_generator.sh
│   ├── update_toc
│   └── update_toc_raw
├── smart-anchor.js
└── src # 书籍内容主体
    ├── SUMMARY.md # 目录页,唯一可以添加跳转的地方
    ├── app_deepin
    ├── app_extensions
    ├── app_plugin_list.md
    ├── imgs
    ├── macos_essentials.md
    ├── macos_ios_tips.md
    ├── overview.md
    └── shortcuts_keymaps_config.md

13 directories, 29 files

Summary

要注意,mdbook中所有文章跳转链接只能放在Summary中。

图片资源与git lfs

git lfs使用场景

Git LFS 是 Github 开发的一个 Git 的扩展,用于实现 Git 对大文件的支持. 比如在游戏开发过程中,设计资源占用了很大一部分空间. 像png,psd等文件是二进制(blob) 的,体积也很庞大.但git的diff/patch等是基于文件行的.对于二进制文件来说. git需要存储每次commit的改动.每次当二进制文件修改,发生变化的时候. 都会产生额外的提交量.导致clone和pull的数据量大增.在线仓库的体积也会迅速增长.

LFS(Large File Storage) 就是为了解决这一问题而产生的工具.

  • 它将你所标记的大文件保存至另外的仓库,而在主仓库仅保留其轻量级指针.
  • 那么在你检出版本时,根据指针的变化情况下更新对应的大文件.而不是在本地保存所有版本的大文件

对mdbook的影响

因为mdbook默认是在src里面直接引用静态资源,所以如果用git lfs打开对应的资源存储就会导致发布后的github pages找不到静态资源。

Rust特供功能

隐藏代码行

fn main() {
    let x = 5;
    let y = 6;

    println!("{}", x + y);
    
}

Rust Playground页面执行

默认支持

#![allow(unused)]

fn main() {
    println!("Hello, World!");
}

指定不支持

let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("failed to read line");
println!("Hello {}!", name);

包含文件自动渲染为md

全文件包含

```
{{#include ../../scripts/update_toc_raw}}
```

渲染后:

find . -type f -name '*.md' > temp
mds=`sort temp | uniq`
for md in $mds:
do
  if echo $md | grep -q -E '\.md$'
  then
    echo $md
    scripts/gh-md-toc --insert --no-backup $md
  else
    echo $md' not md'
  fi
done
rm temp

指定行数

  1. 指定一行
```
{{#include ../../scripts/update_toc_raw:1}}
```

渲染后:

find . -type f -name '*.md' > temp
  1. 指定一行开始
```
{{#include ../../scripts/update_toc_raw:1:}}
```

渲染后:

find . -type f -name '*.md' > temp
mds=`sort temp | uniq`
for md in $mds:
do
  if echo $md | grep -q -E '\.md$'
  then
    echo $md
    scripts/gh-md-toc --insert --no-backup $md
  else
    echo $md' not md'
  fi
done
rm temp
  1. 指定范围
```
{{#include ../../scripts/update_toc_raw:1:5}}
```

渲染后:

find . -type f -name '*.md' > temp
mds=`sort temp | uniq`
for md in $mds:
do
  if echo $md | grep -q -E '\.md$'
  1. 指定到某行
```
{{#include ../../scripts/update_toc_raw::6}}
```

渲染后:

find . -type f -name '*.md' > temp
mds=`sort temp | uniq`
for md in $mds:
do
  if echo $md | grep -q -E '\.md$'
  then

指定锚点部分

打开行数

[output.html.playground]
editable = false         # allows editing the source code
copyable = true          # include the copy button for copying code snippets
copy-js = true           # includes the JavaScript for the code editor
line-numbers = false     # displays line numbers for editable code
runnable = true          # displays a run button for rust code

line-numbers Display line numbers on editable sections of code. Requires both editable and copy-js to be true. Defaults to false.

插入代码

插入可运行代码: 只支持rust

页面直接编辑代码: *, editable

mdbook主题修改

Theme - mdBook Documentation

基本页面介绍

 tree mytheme -L 1                                                                                                                                ─╯
mytheme
├── FontAwesome
├── ayu-highlight.css
├── book.js
├── clipboard.min.js
├── css
├── favicon.png
├── favicon.svg
├── fonts
├── head.hbs
├── header.hbs
├── highlight.css
├── highlight.js
├── index.hbs
├── mod.rs
├── playground_editor
├── redirect.hbs
├── searcher
└── tomorrow-night.css

5 directories, 13 files
  • index.hbs is the handlebars template.
  • head.hbs is appended to the HTML section.
  • header.hbs content is appended on top of every book page.
  • css/ contains the CSS files for styling the book.
  • css/chrome.css is for UI elements.
  • css/general.css is the base styles.
  • css/print.css is the style for printer output.
  • css/variables.css contains variables used in other CSS files.
  • book.js is mostly used to add client side functionality, like hiding / un-hiding the sidebar, changing the theme, …
  • highlight.js is the JavaScript that is used to highlight code snippets, you should not need to modify this.
  • highlight.css is the theme used for the code highlighting.
  • favicon.svg and favicon.png the favicon that will be used. The SVG version is used by newer browsers.

mdbook高级用法

关于book

  1. 首先,这是mdbook serve/build之后生成的静态网站目录
  2. src,和Summary同级的目录,就是网站根目录
  3. src之外的内容不会被自动加入到book,所以无法访问。
  4. 这里有三个办法解决静态文件访问的问题:
    • 生成book之后再复制进去,不过每次都需要重新复制
    • 把静态文件放在src里面,将会自动复制进去
    • 只对于js和css文件,可以用book的additional-css/js参数配置进去

关于mdbook serve panit-失败

这可能是由于本地电脑开了太多程序占用资源,mdbook serve资源不足,重启电脑可解决

关于主题修改(theme)

  1. 在book.toml指定主题路径
  2. 只有指定文件名才会被用来渲染网页

Theme - mdBook Documentation

关于markdown table

mdbook原生不支持table

可以添加preprocessor:mdbook-extended-markdown

格式注意

  1. 其实就是类似ASCII渲染,所见即所得
  2. 每一行长度需要一致, 所以注意不要中英文混合
  3. 每一行之间要有分割线

```extended-markdown-table

|          |                                      Tool                                   |
|          |------------------|----------------------|-----------------------------------|
|          |                  | Markdown Tables      | Extended Markdown Tables          |
| Feature  |------------------|----------------------|-----------------------------------|
| Support  |                  |                      | Horizontal      |        ✓        |
|          | Merged cells     |          ✗           |-----------------|-----------------|
|          |                  |                      | Vertical        |        ✓        |

```

```extended-markdown-table

| Macros                     | Define                                                         | Usage                | note   | Example    |
|----------------------------|----------------------------------------------------------------|----------------------|--------|------------|
| Declarative Macro          | #[macro_export]/macro_rules! macro_name{}                      | macro_name!()        |        | println!   |
|----------------------------|----------------------------------------------------------------|----------------------|--------|------------|
| Function Macro             | #[proc_macros]/pub fn macro_name                               | macro_name!()        |        |            |
|----------------------------|----------------------------------------------------------------|----------------------|--------|------------|
| Derive Macro               | #[proc_macros_derive(DeriveMacroName)]/pub  fn other_fn_name   | DeriveMacroName!()   |        |            |
|----------------------------|----------------------------------------------------------------|----------------------|--------|------------|
| Attritubte Macro           |                                                                |                      |        |            |

```

mdbook插件推荐

自动检查

Michael-F-Bryan/mdbook-linkcheck: A backend for mdbook which will check your links for you.

自动生成

mattico/global-search: Global search for a collection of MDBooks

mdbook-toc

badboy/mdbook-toc: A preprocessor for mdbook to add inline Table of Contents support.

mdbook-pagetoc: 添加页内侧边栏toc

JorelAli/mdBook-pagetoc: A page table of contents for mdBook mdbook-toc-sample Chapter 1 - Sample

mdbook-open-on-gh

badboy/mdbook-open-on-gh: mdbook preprocessor to add a open-on-github link on every page

book-summary

Automatically creates a SUMMARY.md file for your book (mdbook/gitbook)

dvogt23/book-summary: 📔Book auto-summary 🦀🖤 (gitbook/mdBook)

mdbook-suto-gen-summary

knightflower1989/mdbook-auto-gen-summary: mdbook auto-gen-summary

mdbook-transcheck

dalance/mdbook-transcheck: Checker for translated mdbook

mdbook-man

vv9k/mdbook-man: Generate manual pages from mdBooks!

mdbook-bookimport: 使用标记块引入其他文件内容

mdbook自带的include语法同时支持行数和标记来引入文件内容

tailwind/mdbook-bookimport: Import code/text from other files into your mdbook - without the link rot.

md2tex

A small utility to convert markdown files to tex. Forked from md2pdf, with an added focus on mdbook conversions. Also with the goal of eventually contributing back upstream.

  • Used by mdbook-latex to generate PDF’s.

lbeckman314/md2tex: A fork of tforgione’s awesome md2pdf library, catered for mdbook.

mdbook-checklist

ANSSI-FR/mdbook-checklist: mdbook preprocessor for generating checklists and indexes

mdbook-chapter-path: 可以用来生成面包屑导航

mdBook Tag

dylanowen/mdbook-tag

mdbook toc: 自动生成toc

cargo install mdbook-toc

说两句

不过我主要用github action自动解析后插入生成,这样用起来感觉更方便本地修改

mdbook-footnote: 可以用于生成引用内容

mdBook-template: 不需要,直接修改主题

sgoudham/mdbook-template: A mdbook preprocessor that allows the re-usability of template files with dynamic arguments

trpl-zh-cn-pdf

KaiserY/trpl-zh-cn: Rust 程序设计语言(2021 edition 施工中)

me1ting/trpl-zh-cn-pdf: trpl-zh-cn的mdBook风格的pdf,带全书签

mdbook-cms: 自动生成Summary

this will also walk your mdbook src dir and generate the book summary in /path/to/your/mdbook/src/SUMMARY.md

AlongWY/mdbook-cms: A preprocessor bring cms to mdbook.

mdbook-open-on-gh: 添加打开github分支的功能

可以在页面底部添加对应源文件的超链接

mdbook-readme: 解决readme与index不一致的问题

为什么需要转化

mdbook生成的目录菜单,最上方的链接是指向index.html. 但是网址根目录又指向README.md。这里需要统一

mdbook-readme - crates.io: Rust Package Registry

mdbook-cmdrun: 提供强悍的终端执行功能

该插件内置了下列编译器,可以直接执行代码

  1. Shell
total 88K
drwxr-xr-x 4 runner docker 4.0K Nov 27 15:02 .
drwxr-xr-x 4 runner docker 4.0K Nov 27 15:02 ..
-rw-r--r-- 1 runner docker 1.2K Nov 27 15:02 IINA_deepin.md
drwxr-xr-x 2 runner docker 4.0K Nov 27 15:02 OmniGroups
-rw-r--r-- 1 runner docker 1.1K Nov 27 15:02 alfred.md
-rw-r--r-- 1 runner docker   23 Nov 27 15:02 app_deepin.md
-rw-r--r-- 1 runner docker 2.9K Nov 27 15:02 drafts.md
-rw-r--r-- 1 runner docker  716 Nov 27 15:02 goodnotes.md
-rw-r--r-- 1 runner docker 1.7K Nov 27 15:02 jetbrains_ide.md
drwxr-xr-x 2 runner docker 4.0K Nov 27 15:02 karabiner
-rw-r--r-- 1 runner docker 2.1K Nov 27 15:02 marginnote_deepin.md
-rw-r--r-- 1 runner docker  27K Nov 27 15:02 mdbook_deepin.md
-rw-r--r-- 1 runner docker  238 Nov 27 15:02 picGo_deepin.md
-rw-r--r-- 1 runner docker  611 Nov 27 15:02 sigil_epub_editor.md
-rw-r--r-- 1 runner docker 2.5K Nov 27 15:02 tampermonkey.md
-rw-r--r-- 1 runner docker  677 Nov 27 15:02 typora_deepin.md
  1. Bash Script
<!-- cmdrun ../../materials/cmdrun/script.sh>
  1. Python3

Generated subtitle

This comes from the script.py file

Since I’m at in a scripting language,

I can compute whatever I want

  1. Rust
#![allow(unused)]
fn main() {
/ < / ! / - / - / cmdrun cmdrun/script.rs - ->
}

配置与替换

mdbook-fluent: 可以用配置文件进行整理

JakubKoralewski/mdbook-fluent: mdBook preprocessor for variable interpolation using the Fluent language

关于fluent

fluent主要是用来本地化配置

  1. book.toml可以用dir参数配置查找fluent文件的目录路径
  2. 目前暂未试验成功
\{\{\#\fluent ../../../materials/global.motto}}
\{\{\#\fluent global.hello}}

mdbook-variables: 在book.toml配置全局变量

# book.toml
[preprocessor.variables.variables]
motto = "保持批判,有所取舍,知行合一,方见真我"
# here
\{\{motto}}

保持批判,有所取舍,知行合一,方见真我

mdbook-regex: 对内容进行正则替换

可以看作是mdbook-variables的升级版

绘图

mdBook Graphviz: 支持graphviz的dot语言

dylanowen/mdbook-graphviz

https://github.com/badboy/mdbook-open-on-gh)

svgbob plugin for mdbook

boozook/mdbook-svgbob: SvgBob mdbook preprocessor which swaps code-blocks with neat SVG.

mdbook-skill-tree: 添加技能树渲染

mdbook-chart: 添加c3.js图表渲染功能

主要是通过添加额外js、css文件

mdbook-puml: plantuml渲染

不再使用,会导致markdown无法渲染表格;其功能可以被mdbook-kroki覆盖

比mdbook-plantuml更好用 mdbook-puml - crates.io: Rust Package Registry

绘图合集:kroki

image-20220715114804075

IntelliPikchr: IDEA内置插件

Split editor with preview pane for .pikchr files, using kroki.io or self-hosted server for rendering

mdbook-kroki-preprocessor: 支持kroki渲染

kroki可以看作多种图表语言的统一接口

md语法

The code block’s language has to be kroki-.

  • kroki-mermaid
  • kroki-plantuml
cargo install mdbook-kroki-preprocessor

自动渲染

mdbook-admonish

tommilligan/mdbook-admonish: A preprocessor for mdbook to add Material Design admonishments.

mdbook-curly-quotes

mdBook preprocessor that replaces straight quotes with curly quotes, except within code blocks or code spans. It does the same as the curly-quotes option of the mdBook HTML renderer. The only advantage is that it can be applied to any renderer. arminha/mdbook-curly-quotes: mdBook preprocessor that replaces straight quotes with curly quotes

mdbook-tera

基于tera模版引擎渲染 avitex/mdbook-tera: Tera preprocessor for mdBook Keats/tera: A template engine for Rust based on Jinja2/Django

sgoudham/mdbook-template

可以自定义页脚的图像

sgoudham/mdbook-template: A mdbook preprocessor that allows the re-usability of template files with dynamic arguments

zjp-CN/mdbook-theme

提供更多主题自定义选项

mdbook-mark: 渲染高亮标签

blazood/mdbook-mark: this is a mdbook preprocessor which can render ==== to

mdbook-all-the-markdowns

all-the-things

bombsimon/mdbook-all-the-markdowns: 🗃️ Preprocessor for mdbook to render all the markdowns!

NOBLES5E/mdbook-wikilink: Support for wikilinks on mdBook.

mdbook-page-styles

ABCsOf/mdbook-page-styles: An mdbook preprocessor to apply styles to specific pages and elements.

mdbook-note

Aedius/mdbook-note: preprocessor for mdbook to add organized chapter containing fragment from the rest of the book

mdbook-section-validator

younata/mdbook-section-validator: mdBook preprocessor for defining conditionally valid sections

mdbook-quiz: 添加在线测验功能

自动生成

该插件会在src自动创建生成mdbook-quiz目录,里面包含embed.css和embed.js

cargo install mdbook-quiz
git clone https://github.com/willcrichton/mdbook-quiz
cd mdbook-quiz
cargo install --path .

配置方式

You can configure mdbook-quiz by adding options to the [preprocessor.quiz] section of book.toml. The options are:

  1. validate (boolean): If true, then mdbook-quiz will validate your quiz TOML files using the validator.js script installed with mdbook-quiz. You must have NodeJS installed on your machine and PATH for this to work.
  2. fullscreen (boolean): If true, then a quiz will take up the web page’s full screen during use.
  3. cache-answers (boolean): If true, then the user’s answers will be saved in their browser’s localStorage. Then the quiz will show the user’s answers even after they reload the page.

注意⚠️

使用说明

  1. 该插件默认只是在src里面自动生成mdbook-quiz, 里面包含必须但js和css文件
  2. 默认情况下只能在src目录下生效,与mdbook-quiz同级。
  3. 目前改成直接从book.toml引入,就可以全局使用
  4. 注意引入测试文件的代码行上下需要为空行

\{\{\#\quiz ../../materials/quizzes/rust-variables.toml}}

\{\{\#\quiz ../../materials/quizzes/quiz.toml}}

题型说明

测试题类型

[[questions]]
type = "MultipleChoice"
prompt.prompt = "What does it mean if a variable `x` is immutable?"
prompt.choices = [
  "`x` is stored in the immutable region of memory.",
  "After being defined, `x` can be changed at most once.",
  "`x` cannot be changed after being assigned to a value.",
  "You cannot create a reference to `x`."
]
answer.answer = 2
context = """
Immutable means "not mutable", or not changeable.
"""

[[questions]]
type = "ShortAnswer"
prompt.prompt = "What is the keyword used after `let` to indicate that a variable can be mutated?"
answer.answer = "mut"
context = """
For example, you can make a mutable variable `x` by writing: `let mut x = 1`.
"""

[[questions]]
type = "Tracing"
prompt.program = """
fn main() {
  let x = 1;
  println!("{x}");
  x += 1;
  println!("{x}");
}
"""
answer.doesCompile = false
answer.lineNumber = 4
context = """
This is a compiler error because line 4 tries to mutate `x` when `x` is not marked as `mut`.
"""

{{#quiz ../../materials/quizzes/rust-variables.toml}}

{{#quiz ../../materials/quizzes/quiz.toml}}

其他格式

playscript: 戏剧脚本格式

unevil-rs: 与mdbook无关,只是单独用来写ppt

oknozor/unveil-rs: Unveil Rs is a tool to create presentations from markdown inspired by reveal.js, mdbook and zola.

在线示例

Gooseberry - a Knowledge Base for the Lazy

一个很棒的工具,可以直接将mdbook转为知识库

out-of-cheese-error/gooseberry: A command line utility to generate a knowledge base from Hypothesis annotations

obsidian_example-2

ppt: 可以切换ppt还是markdown

这个插件将html算是玩的比较深入

举例(windows-alt+p|osx-option+p切换)

举例

An Interesting Thing

Press alt+p to toggle which version is displayed. Open the console to see the notes printed there

Here is a much longer explanation about what this interesting thing is and how interesting you might find it.

To elaborate, it is extremely interesting.

A list of things

  • Fact one is intriguing
  • Fact two is piquing my interest
  • Fact three has me down right flabbergasted
  • Fact four is almost obscene
  • web-only

image-20220716181352654

  • Slides-only

    image-20220716181430206

  • notes

    image-20220716181503831

本地示例

这里是默认内容,web-only

这里是slides-only: 待完成内容

  • Fact one is intriguing
  • Fact two is piquing my interest
  • Fact three has me down right flabbergasted
  • Fact four is almost obscene

资源链接

picGo设置指南

github图床设置

  1. 新建一个仓库

仓库必须为public,否则只能存储不能外部访问

  1. 生成访问token: 点击右上角用户头像 > Developer settings > Personal access tokens
  2. 配置PicGo

typora使用规范

图片管理

考虑到隐私和公共写作需求,对于文章内的图片管理主要分成两种:

  1. 首先全部默认放在本地
  2. 准备发布之前将文章内的图片上传一下并切换为线上地址

如何批量上传本地图片

Upload Images - Typora Support

下列操作将会将当前文章里面的图片全部上传,但是不影响其他文章的图片

image-20220609111713871

使用mermaid绘图

typora内置了mermaid绘图的支持。

iTerm2配置

Status Bar: 很多内容,值得管理

下载并设置环境变量

git clone git@github.com:KuanHsiaoKuo/apple_power_user.git
cd apple_power_user
pwd # 输出的值用于配置环境变量
# ~/.bashrc 或者 ~/.zshrc
export APU=<pwd value>
export VC=$APU/src/app_extensions/iterm2_around/vim_config
export ZC=$APU/src/app_extensions/iterm2_around/zsh_config

由于我用的是zsh,所以这里就修改~/.zshrc

三种设置环境变量的区别

  1. 单纯export:仅对当前登陆的终端有效
  2. 在.bashrc文件中export: 对当前登陆用户有效
  3. 在/etc/profile文件中export: 对所有用户都有效

iterm2同步配置方式

设置同步方式

iTerm2 >> Preferences >> General >> Preferences >> Load prefernces from a custom folder or URL

注意选择手动保存。

指向下载的文件夹

同步范围

  1. 基础颜色配置
  2. profiles自动登陆服务器配置

但是自动输入密码的文件在~/.ssh/logins,需要另外同步

环境套件资料


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  
  
  
  vim
  zsh
  
  Oh
  my
  zsh
  Tmux
  +
  config
  +
  plugins
  HomeBrew
  +
  Plugins
  iTerm2
  +
  config
  +
  plugins

A. Homebrew Around

  1. The Missing Package Manager for macOS (or Linux) — Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  1. Around: brew install xxx

osx系统更新了clang++, 一些老版本的python无法安装,比如3.7.5。 pyenv install 3.10.3就没问题

B. tmux配置:tmux_config.md

C. zsh/Oh my zsh + plugins

  1. iterm_around.sh未完善,请一条条执行
python3 -m pip install --upgrade pip
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/kuanhsiaokuo/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
brew tap homebrew/cask-fonts
# 下方指令比较耗时,安装之后如果没有生效,就修改Iterm2的fonts为Meslo
# Profiles >> Open Profiles >> Edit Profiles... >> Text >> Fonts
brew install --cask font-hack-nerd-font
brew install tmux
brew install lsd
pip3 install tldr
brew install graphviz
cpan
sudo cpan Graph:Easy
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-history-substring-search ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-history-substring-search
git clone https://github.com/zsh-users/zsh-completions ${ZSH_CUSTOM:-${ZSH:-~/.oh-my-zsh}/custom}/plugins/zsh-completions
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
echo "source $ZC/custom_config" >> ~/.zshrc
source ~/.zshrc
p10k configure

D. vim配置

修改vimrc

sh $VC/source_vimrc.sh
# $VC/source_vimrc.sh
# 在vimrc里面添加source
echo 'source $VC/basic' >> ~/.vimrc
echo 'source $VC/fold_break' >> ~/.vimrc
echo 'source $VC/leader_key' >> ~/.vimrc
echo 'source $VC/tab_key' >> ~/.vimrc

source filename 与 sh filename 及./filename执行脚本的区别在那里呢?

1.当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有“.“是用来表示当前目录的。

2.sh filename 重新建立一个子shell,在子shell中执行脚本里面的语句,该子shell继承父shell的环境变量,但子shell新建的、改变的变量不会被带回父shell,除非使用export。

3.source filename:这个命令其实只是简单地读取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell。那么脚本里面所有新建、改变变量的语句都会保存在当前shell里面。(当这个shell关闭后就失效了)

进入vim,会自动激活~/.vimrc

关于colorscheme设置为solarized(分支已经包含,可以不用下载)

  • 下载vim主题
git clone git://github.com/altercation/vim-colors-solarized.git  
cp vim-colors-solarized/colors/solarized.vim ~/.vim/colors/ 
  • 配置
colorscheme solarized 

主要分为这几个部分:

  • basic
  • fold_break
  • leader_key
  • tab_key
  • cscope_conf

zsh_config使用

首先安装zsh

sudo apt-get install zsh

接着安装oh my zsh

wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh

或者安装:

chmod u+x oh_my_zsh_install.sh
./oh_my_zsh_install.sh

zsh-config

我的zsh配置

在指定目录git clone之后,在~/.zshrc添加一行

source ~/Developer/spare_projects/apple_power_user/src/app_extensions/iterm2_around/zsh_config/custom_config¬

然后执行指令:

# 可能需要切换到zsh
source ~/.zshrc

zsh-syntax-hightlighting插件安装

git clone git://github.com/zsh-users/zsh-syntax-highlighting.git $ZSH_CUSTOM/plugins/zsh-syntax-highlighting
# 然后在custom_config里面对plugins添加这个插件

zsh-autosuggestion

git clone https://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions

安装powerlevel10k主题

  • 下载主题
git clone https://github.com/romkatv/powerlevel10k.git $ZSH_CUSTOM/themes/powerlevel10k
  • custom-config配置主题
ZSH_THEME="powerlevel10k/powerlevel10k"
POWERLEVEL9K_MODE="awesome-patched"
  • 重新配置p10k
p10k configure
  • 安装字体:默认情况下激活zshrc时会自动安装

ubuntu

apt-get install fonts-powerline
  • macos
https://github.com/powerline/fonts/blob/master/SourceCodePro/Source%20Code%20Pro%20for%20Powerline.otf
https://github.com/Falkor/dotfiles/blob/master/fonts/SourceCodePro%2BPowerline%2BAwesome%2BRegular.ttf

nerd fonts使用

  • 下载
git clone https://github.com/ryanoasis/nerd-fonts.git
  • 安装
./install.sh
  • iterm2设置喜欢的字体

一些终端小工具的安装,非zsh/oh-my-zsh

ubuntu:

wget https://github.com/Peltoche/lsd/releases/download/0.17.0/lsd_0.17.0_amd64.deb
sudo dpkg -i lsd_0.17.0_amd64.deb

tmux配置

OSX

# 解绑前缀,改为和screen一样的
unbind C-b
set -g prefix C-a
# bind a reload key
bind r source-file ~/.tmux.conf ; display-message "Config reloaded.."
# 切换分窗格方式
bind | split-window -h
bind - split-window -v
# 重新按照vi习惯定义方向键
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# 交换窗格
bind ^u swapp -U
bind ^d swapp -D
# 将window的起始设置为1
set -g base-index 1
# 将pane的起始下标设为1
set -g pane-base-index 1
# 设置pane编号显示时间
set -g display-panes-time 2000 #2s
# UI 样式调整
setw -g window-status-current-fg white
setw -g window-status-current-bg red
setw -g window-status-current-attr bright
set -g status-justify left
setw -g monitor-activity on
# 开始美化状态栏

# tmux插件管理器
# List of plugins
#  要装的插件直接在这里写就可以了
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-prefix-highlight'
# 这两个插件是备份tmux会话与自动备份
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# 打开会话自动保存
set -g @continuum-restore 'on'
# 默认每隔15分钟备份一次,这里改成半个小时
set -g @continuum-save-interval '30'
set -g @plugin 'tmux-plugins/tmux-online-status'
# 添加状态栏电池显示插件
set -g @plugin 'tmux-plugins/tmux-battery'
# 添加tmux侧边栏, prefix-tab
set -g @plugin 'tmux-plugins/tmux-sidebar'
# tmux窗格管理
set -g @plugin 'tmux-plugins/tmux-pain-control'

# Other examples:
# set -g @plugin 'github_username/plugin_name'
# set -g @plugin 'git@github.com/user/plugin'
# set -g @plugin 'git@bitbucket.com/user/plugin'



# 关于复制方式
#set-window-option -g mode-keys vi
#bind-key -t vi-copy 'v' begin-selection
#bind-key -t vi-copy 'y' copy-selection

# 状态栏统一设置
# Update the status line every sixty seconds
set -g status-interval 60
# Center the window list in the status line
set -g status-justify centre
# enable activity alerts
setw -g monitor-activity on
# Displays a message in the message area when there is activity in another window
set -g visual-activity on
set -g status-left-length 200
set -g status-right-length 200
##H
#Hostname of local host
##h
#Hostname of local host without the domain name
##F
#Current window flag
##I
#Current window index
##P
#Current pane index
##S
#Current session name
##T
#Current window title
##W
#Current window name
###
#A literal #
##(shell-command)
#First line of the shell command’s output
##[attributes]
#Color or attribute change
set -g status-left "session:#S window:#W pane:#P"
# 设置电量状态所用的图标
set -g @batt_charged_icon "😎"
set -g @batt_charging_icon "👍"
set -g @batt_discharging_icon "👎"
set -g @batt_attached_icon "😐"
set -g @batt_full_charge_icon "🌕 "
set -g @batt_high_charge_icon "🌖 "
set -g @batt_medium_charge_icon "🌗 "
set -g @batt_low_charge_icon "🌘 "
set -g status-right '#{battery_status_bg} Batt: #{battery_icon} #{battery_percentage} #{battery_remain} | Continuum status: #{continuum_status} | Online: #{online_status} | %a %h-%d %H:%M '
# 添加powerline支持
source "/usr/local/bin/powerline/powerline/bindings/tmux/powerline.conf"
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'
# bind a reload key
bind r source-file ~/.tmux.conf ; display-message "Config reloaded.."
# 切换分窗格方式
bind | split-window -h
bind - split-window -v
# 重新按照vi习惯定义方向键
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# 将window的起始设置为1
set -g base-index 1
# 将pane的起始下标设为1
set -g pane-base-index 1
# UI 样式调整
setw -g window-status-current-fg white
setw -g window-status-current-bg red
setw -g window-status-current-attr bright
set -g status-justify left
setw -g monitor-activity on
# 开始美化状态栏

# tmux插件管理器
# List of plugins
#  要装的插件直接在这里写就可以了
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-prefix-highlight'
# 这两个插件是备份tmux会话与自动备份
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# 打开会话自动保存
set -g @continuum-restore 'on'
# 默认每隔15分钟备份一次,这里改成半个小时
set -g @continuum-save-interval '30'
set -g @plugin 'tmux-plugins/tmux-online-status'
# 添加状态栏电池显示插件
set -g @plugin 'tmux-plugins/tmux-battery'
# 添加tmux侧边栏, prefix-tab
set -g @plugin 'tmux-plugins/tmux-sidebar'
# tmux窗格管理
set -g @plugin 'tmux-plugins/tmux-pain-control'

# Other examples:
# set -g @plugin 'github_username/plugin_name'
# set -g @plugin 'git@github.com/user/plugin'
# set -g @plugin 'git@bitbucket.com/user/plugin'



# 关于复制方式
#set-window-option -g mode-keys vi
#bind-key -t vi-copy 'v' begin-selection
#bind-key -t vi-copy 'y' copy-selection

# 状态栏统一设置
# Update the status line every sixty seconds
set -g status-interval 60
# Center the window list in the status line
set -g status-justify centre
# enable activity alerts
setw -g monitor-activity on
# 设置窗口名字不再自动变化
set-option -g allow-rename off
# 设置窗格名字
set-option -g pane-border-format " #P: #{pane_current_command} "
# Enable names for panes
set -g pane-border-status top
# Displays a message in the message area when there is activity in another window
set -g visual-activity on
set -g status-left-length 100
set -g status-right-length 200
set -g status-left "session:#S window:#I pane:#P"
# 设置电量状态所用的图标
set -g @batt_charged_icon "😎"
set -g @batt_charging_icon "👍"
set -g @batt_discharging_icon "👎"
set -g @batt_attached_icon "😐"
set -g @batt_full_charge_icon "🌕 "
set -g @batt_high_charge_icon "🌖 "
set -g @batt_medium_charge_icon "🌗 "
set -g @batt_low_charge_icon "🌘 "
set -g status-right '#{battery_status_bg} Batt: #{battery_icon} #{battery_percentage} #{battery_remain} | Continuum status: #{continuum_status} | Online: #{online_status} | %a %h-%d %H:%M '
# 添加powerline支持
#source "/usr/local/lib/python3.6/site-packages/powerline/bindings/tmux/powerline.conf"
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'

# 设置resurrect保存窗格的内容page
set -g @resurrect-capture-pane-contents 'on'
# for vim
set -g @resurrect-strategy-vim 'session'

# ----------------------------tricks-------------
# displays "prefix" (in red) in statusline when prefix is pressed
set -g status-left "#[bg=red]#{s/root//:client_key_table}"
# view current pane history (including colors) with "less" in new window
bind-key u capture-pane -S - -E - -e -b lesshist \; new-window -n "history" 'tmux show-buffer -b lesshist| less -R +G'

Linux(Simplified)

# 解绑前缀,改为和screen一样的
unbind C-b
set -g prefix C-a
# 切换分窗格方式
bind | split-window -h
bind - split-window -v
# 重新按照vi习惯定义方向键
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# 交换窗格
bind ^u swapp -U
bind ^d swapp -D
# 将window的起始设置为1
set -g base-index 1
# 将pane的起始下标设为1
set -g pane-base-index 1
# 设置pane编号显示时间
set display-panes-time 2000 #2s
# UI 样式调整
setw -g window-status-current-fg white
setw -g window-status-current-bg red
setw -g window-status-current-attr bright
set -g status-justify left
setw -g monitor-activity on

vim专业使用

Macros

对于临时的复杂操作,可以使用宏。这里举例一下

  1. 浏览模式下按 q
  2. 选择一个 mark, 比如 e
  3. 开始记录批量操作
  4. 按 q 退出宏记录
  5. :echo @e 或者:reg @e 可以查看宏记录
  6. 编辑修改:打开新的 vim,“ep, 编辑修改,复制,“eyy
  7. 列出所有的宏::reg
  8. 清除指定宏::let @e=‘’

相关资料

VimScript

vim本身提供一种脚本语言,帮助进行个性化操作。

相关资料

场景一:繁琐内容处理

我比较喜欢在idea里面写markdown文档,但是idea格式化mdbook的include语法时会出现问题, 自动添加空格导致语法失效。

这里自己写了一个vimscript解决这个问题,正好举例如何使用。

代码内容

function! MdbookIncludeSyntaxFormatInWholeBuffer()
    let include_replace = {
      \ '{{ #': '{{#',
      \ '# include': '#include',
      \ 'include\.\.': 'include\ \.\.',
      \ '\/ ': '\/',
      \ ' \/': '\/',
      \ ': ': ':',
      \ ' }}': '}}'
    \ }
    let l = 1
    for line in getline(1,"$")
        if stridx(line,  'include') > -1
            let replaced_line = line
            for [substitute_key, substituted] in items(include_replace)
                "echo l.replaced_line
                "echo l.substitute_key.substituted
                "call setline(l, substitute(line, substitute_key, substituted, "g"))
                let replaced_line = substitute(replaced_line, substitute_key, substituted, "g")
            endfor
            call setline(l, replaced_line)
        endif
        let l = l + 1
    endfor
    "保存文件
    write
    "退出vim
    exit
endfunction
"将会在source的时候直接执行
"call AddSpaceBeforeEqualInWholeBuffer()
"source之后将会自定义一个指令
command Ir call MdbookIncludeSyntaxFormatInWholeBuffer()

使用说明

  1. vim内:命令模式输入Ir
  2. 终端内:vim -c 'Ir' <target_file>

MacOS X 专用命令行梳理

open

pbcopy and pbpaste

tree -L 1 | pbcopy

mdfind

screencapture

launchctl

say

diskutil

brew

列表清单

快捷操作

TabAuto-complete file and folder names
Ctrl + AGo to the beginning of the line you’re currently typing on
Ctrl + EGo to the end of the line you’re currently typing on
Ctrl + UClear the line before the cursor
Ctrl + KClear the line after the cursor
Ctrl + WDelete the word before the cursor
Ctrl + TSwap the last two characters before the cursor
Esc + TSwap the last two words before the cursor
Ctrl + LClear the screen
Ctrl + CKill whatever you’re running
Ctrl + DExit the current shell
Option + →Move cursor one word forward
Option + ←Move cursor one word backward
Ctrl + FMove cursor one character forward
Ctrl + BMove cursor one character backward
Ctrl + YPaste whatever was cut by the last command
Ctrl + ZPuts whatever you’re running into a suspended background process
Ctrl + _Undo the last command
Option + Shift + Cmd + CCopy plain text
Shift + Cmd + VPaste the selection
exitEnd a shell sessio

基础操作

/ (Forward Slash)Top level directory
. (Single Period)Current directory
.. (Double Period)Parent directory
~ (Tilde)Home directory
sudo [command]Run command with the security privileges of the super user
nano [file]Opens the Terminal editor
open [file]Opens a file
[command] -hGet help about a command
man [command]Show the help manual of the command
Change Directory
cdHome directory
cd [folder]Change directory, e.g. cd Documents
cd ~Home directory
cd/Root of the drive
cd -Previous directory or folder you last browsed
pwdShow your working directory
cd..Move up to the parent directory
cd../..Move up two levels

list

lsDisplay the name of files and subdirectories in the directory
ls -CForce multi-column output of the listing
ls -aList all entries including those with .(period) and ..(double period)
ls -1Output the list of files in one entry per line format
ls -FDisplay a / (slash) immediately after each path that is a directory, * (asterisk) after executable programs or scripts, and @ after a symbolic link
ls -SSort files or entries by size
ls -lList in a long format. Includes file mode, owner and group name, date and time file was modified, pathname, and more
ls -l /List of the file system from root with symbolic links
ls -ltList the files sorted by time modified (most recent first)
ls -lhLong listing with human readable file sizes in KB, MB, or GB
ls -loList the file names with size, owner, and flags
ls -laList detailed directory contents, including hidden files

文件磁盘

duList usage for each subdirectory and its contents
du -sh [folder]Human readable output of all files in a directory
du -sDisplay an entry for each specified file
du -sk* | sort -nrList files and folders, totaling the size including the subfolders. Replace sk* with sm* to list directories in MB
df -hCalculate your system’s free disk space
df -HCalculate free disk space in powers of 1,000 (as opposed to 1,024)

参考资源

IINA深度使用

简介

Project IINA,是一个基于 mpv、契合 macOS 设计风格、力求做到最佳用户体验、轻便且功能强大的视频播放器项目。

MPV指令定制与配置文件

截图格式自定义

Info

screenshot-template: %{filename}-%p

  1. 按照视频文件名先分段,方便统一存放

本来打算用screenshot-directory参数,但是要报错,就算了

  1. %p: 截屏的时间,可以排序。这样方便后续按时间插入新章节。

CleanShot 2022-09-06 at 21.52.28@2x

设置播放速度

Info

Meta+[ multiply speed 0.5 Meta+] add speed 0.25 Alt+Meta+[ multiply speed 0.9091 Alt+Meta+] multiply speed 1.1 Meta+\ set speed 1.0

  1. 非关键内容快速过
  2. 关键内容放慢速度

完整配置文件

Jetbrains系列IDE共性与特性介绍

共性

快捷键整理

python配置虚拟环境

  1. cmd+; -> 新增虚拟环境
  2. add configuration -> 将虚拟环境配置给当前项目

可以配置远程虚拟环境/docker环境

CleanShot 2022-10-19 at 16.37.06@2x

Tab方式打开项目

由于本人喜欢一个窗口打开多个项目,然后用tab方式来进行项目切换,所以专门找了一下设置方式:

  1. macOS设置:系统偏好设置 > 通用 > 首选以标签页方式打开 > 始终

CleanShot 2022-06-30 at 11.00.02@2x

全局有效

注意:这个设置对其他文档类app也有效

  1. Jetbrains设置是否新窗口打开

配置代理

image-20220702163846633

指定项目root

由于idea等默认需要一个source root,所以有时候打开项目的路径不是它可用的,就可以自己右键指定文件目录设置为source root

image-20220926110436737

Omni系列产品介绍

参考资源

OmniPlan介绍

img

基础流程

  1. 确定项目的基本信息和控制项
  2. 编写任务分解
  3. 为每一个任务确定他的投人
  4. 添加资源,把资源分配到任务中去
  5. 确定每一项工作任务的先后顺序和关系
  6. 自动排程后检查每一项资源的使用倩况

完善/维护流程

复查

  1. 检查任务间的关联是否符合预期一一网络视图
  2. 使用“显示安排影响因素”和“检查器“确认调整后的任务关联
  3. 计划是否有优化空间一一甘特图直接调整任务

增加注释

  1. 补充说明任务是什么
  2. 多方合作时,标明需要其他方的何种资源的支持

常用快捷键

  • 切换检查视图:cmd+shift+i(info)

小技巧

导出选择

主要还是按照任务、资源、项目大纲、网络图这四块分别导出后再合并

任务安排

image-20220626155900015

资源使用

image-20220626155615091

大纲视图

网络视图

容忍期

容忍期

有时候可能某些任务需要间接交替完成,这时候就需要设置容忍期

报告选择

参考资源

OmniFocus介绍

参考资源

OmniGraffle介绍

参考资源

OmniOutliner介绍

参考资源

油猴深度使用

精选脚本

Userscript-plus: 显示当前网站可用油猴脚本

jae-jae/Userscript-Plus: Show current site all UserJS,The easier way to install UserJs for Tampermonkey. 显示当前网站的所有可用Tampermonkey脚本

  • Automatically appear in the lower right corner, recommend scripts for you, and will automatically disappear after 10 seconds
  • Filter the top 50 script with the highest score
  • The script list supports search filtering
  • The script list supports custom sorting
  • Supports one-click installation script
  • Support for viewing script details
  • Support access to the script home page and author home page
  • Click the close button, the current site this session all the pages will no longer appear prompt box
  • A prompt box is displayed only when found available script for the current site
  • i18n international multilingual support.(Locale contributions are welcomed!)
  • Vue + iView UI design smooth and beautiful

集锦

参考资源

工作流整理

主要介绍多app之间如何协同工作

关于marginnote使用自定义模版

由于marginnote自带的模版太简单,所以找了一下如何使用自定义模版导出

一、自定义模版导出:不可行

二、自动在anki中修改模版

  • 对照字段更换模版可行
  • 需要解决MNLink的超链接问题
  • HTML Window source - AnkiWeb
  • showdown卡片模版添加MNLink字段
  • 只要卡片标题不修改,就不会覆盖更新
  • 正面备注都会出现在标题
  • 背面备注都在back里面

最终结果放在《自定义anki模版》

多媒体资料章节化工作流

缘起

一直以来我主要倾向于读文本资料来学习,其实人的接收讯息方式还有视觉和听觉,遂决定整理出一套将多媒体资料进行管理的想法。

这里的多媒体主要指视频、音频和图片,其中图片的管理主要是用github图床+eagle。而视频和音频一旦过长,在寻找知识点的时候就很麻烦,经过验证,发现可以用ffmpeg给多媒体文件的方式添加章节。

Step1. 相关视频/音频合并-ffmpeg

Step2. 使用IINA结合MPV的指令自动化创建章节

Step3. 将章节文本压入到多媒体文件-ffmpeg

Step4. 播放工具选择

  • 电脑端可以选择IINA,基于MPV
  • 移动端选择VLC Player

这里再放一下二者的区别:

关于音频文件处理

可以添加图片,将mp3转为mp4

# 转化图片格式
ffmpeg -i 07.ownership.webp 07.ownership.jpg
# 提取mp3
ffmpeg -i 07.ownership.mp4 -f mp3 -vn 07.ownership.mp3
# 合并为mp4
ffmpeg -loop 1 -i 07.ownership.jpg -i 07.ownership.mp3 -c:a copy -c:v libx264 -shortest out.mp4

Checklist