├── .gitignore
├── 5-docker
├── .env
├── mysql
│ └── my.cnf
├── srs
│ └── rtc2rtmp.conf
└── compose.yml
├── 1-system
├── 3-command.zsh
├── zsh-vi-mode.zsh
├── main.zsh
├── .gitconfig
├── 1-env.zsh
├── cursor-state.zsh
├── vi-basic.zsh
├── 2-aliases.zsh
├── .zimrc
├── .nvim.vim
├── .commitlintrc.js
├── .zshrc
└── .vimrc
├── 3-js
├── index.md
├── package.json
├── word-sort.js
├── bili-danmu.js
├── pnpm-lock.yaml
├── diary-stats.js
└── diary-stats-utools.js
├── 6-chrome
└── stylish
│ ├── 1-现代 JS 教程.css
│ ├── 3-语雀.css
│ └── 2-打字测试.css
├── 4-shell
└── syncFileConfig.sh
├── README.md
└── 2-vscode
├── extensions.txt
├── keybindings.json
└── settings.json
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | **/tmp
3 | dist
4 | build
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/5-docker/.env:
--------------------------------------------------------------------------------
1 | # mysql 数据库配置
2 | MYSQL_ROOT=root
3 | MYSQL_ROOT_PASSWORD=password
4 |
--------------------------------------------------------------------------------
/1-system/3-command.zsh:
--------------------------------------------------------------------------------
1 | # 自定义命令
2 |
3 | # 新建目录并进入
4 | nd() {
5 | mkdir -p -- "$1" &&
6 | cd -P -- "$1"
7 | }
8 |
--------------------------------------------------------------------------------
/3-js/index.md:
--------------------------------------------------------------------------------
1 | > 1
2 |
3 | - Austria
4 | - athens
5 | - directory
6 | - experience
7 |
8 | > 2
9 |
10 | - age
11 | - name
12 | - sex
13 |
--------------------------------------------------------------------------------
/1-system/zsh-vi-mode.zsh:
--------------------------------------------------------------------------------
1 | # 提升 ZVM 切换速度
2 | KEYTIMEOUT=50
3 |
4 | bindkey -M vicmd "H" vi-beginning-of-line
5 | bindkey -M vicmd "L" vi-end-of-line
6 |
--------------------------------------------------------------------------------
/6-chrome/stylish/1-现代 JS 教程.css:
--------------------------------------------------------------------------------
1 | .main_width-limit {
2 | max-width: 1080px;
3 | }
4 |
5 | pre,
6 | code {
7 | font-family: 'Input Mono Freeze' !important;
8 | }
9 |
--------------------------------------------------------------------------------
/1-system/main.zsh:
--------------------------------------------------------------------------------
1 | source ~/.config/zsh/1-env.zsh
2 | source ~/.config/zsh/2-aliases.zsh
3 | source ~/.config/zsh/3-command.zsh
4 | source ~/.config/zsh/zsh-vi-mode.zsh
5 |
--------------------------------------------------------------------------------
/3-js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "dependencies": {
4 | "axios": "^1.7.2",
5 | "clipboardy": "^4.0.0",
6 | "number-precision": "^1.6.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/1-system/.gitconfig:
--------------------------------------------------------------------------------
1 | # This is Git's per-user configuration file.
2 | [user]
3 | name = fengstats
4 | email = feng2860984180@163.com
5 | [core]
6 | ignorecase = false
7 | quotepath = false
8 |
--------------------------------------------------------------------------------
/1-system/1-env.zsh:
--------------------------------------------------------------------------------
1 | # 导出环境变量
2 |
3 | export LC_ALL=en_US.UTF-8
4 | export LANG=en_US.UTF-8
5 |
6 | # proxy
7 | export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890
8 |
--------------------------------------------------------------------------------
/1-system/cursor-state.zsh:
--------------------------------------------------------------------------------
1 | # 配置终端光标状态
2 |
3 | # NOTE: 用于每次新的命令行始终保持细条光标样式,可以覆盖 VS Code 的终端光标样式
4 | # 终端启动的时候使用细条光标(竖条)
5 | echo -ne '\e[5 q'
6 |
7 | # 每个新的提示(对话)都使用细条光标
8 | preexec() {
9 | echo -ne '\e[5 q'
10 | }
11 | _fix_cursor() {
12 | echo -ne '\e[5 q'
13 | }
14 | precmd_functions+=(_fix_cursor)
15 |
--------------------------------------------------------------------------------
/1-system/vi-basic.zsh:
--------------------------------------------------------------------------------
1 | bindkey -v
2 | # 不同模式下切换光标状态: 细条 或者 块状
3 | function zle-keymap-select {
4 | if [[ ${KEYMAP} == vicmd ]] || [[ $1 = 'block' ]]; then
5 | echo -ne '\e[1 q'
6 | elif [[ ${KEYMAP} == main ]] || [[ ${KEYMAP} == viins ]] || [[ ${KEYMAP} = '' ]] || [[ $1 = 'beam' ]]; then
7 | echo -ne '\e[5 q'
8 | fi
9 | }
10 | zle -N zle-keymap-select
11 |
--------------------------------------------------------------------------------
/6-chrome/stylish/3-语雀.css:
--------------------------------------------------------------------------------
1 | /* 笔记内容:中心区域 */
2 | .ne-paragraph-spacing-relax.ne-typography-classic,
3 | .ne-viewer.ne-paragraph-spacing-relax.ne-typography-classic .ne-viewer-body {
4 | font-family: Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif,
5 | Segoe UI;
6 | }
7 |
8 | /* 左侧目录 */
9 | .catalogTreeItem-module_CatalogItem_xkX7p
10 | .catalogTreeItem-module_content_fLFbS
11 | .catalogTreeItem-module_titleWrapper_sFyDt
12 | .catalogTreeItem-module_title_snpKw {
13 | font-family: Arial;
14 | }
15 |
--------------------------------------------------------------------------------
/5-docker/mysql/my.cnf:
--------------------------------------------------------------------------------
1 | # 数据库配置文件:可以配置存储引擎,字符集,最大连接数等等
2 | # utf8mb4: 更广泛的字符编码和表情符号
3 |
4 | [mysqld]
5 | # 兼容 8.0 之前的客户端服务
6 | default-authentication-plugin=mysql_native_password
7 |
8 | # 设置服务器字符编码
9 | character-set-server=utf8mb4
10 | collation-server=utf8mb4_unicode_ci
11 |
12 | # 忽略数据表名大小写:该属性只有初始化构建时才生效
13 | # lower_case_table_names=1
14 |
15 | # 最大允许传输包大小
16 | max_allowed_packet=20M
17 |
18 | # 最大连接数
19 | max_connections=5000
20 |
21 | [mysql]
22 | host=localhost
23 | # user=test
24 | # password=test
25 | # 设置客户端默认字符集
26 | default-character-set=utf8mb4
27 |
28 | [client]
29 | port=3306
30 | default-character-set=utf8mb4
31 |
--------------------------------------------------------------------------------
/1-system/2-aliases.zsh:
--------------------------------------------------------------------------------
1 | # 配置别名命令
2 |
3 | alias sshroot='ssh root@fenglive.icu'
4 | alias so='source ~/.zshrc && exec zsh'
5 |
6 | # 系统
7 | alias ra='ranger'
8 | alias q='exit'
9 | alias x='exit'
10 | alias c='clear'
11 | alias o='open .'
12 | alias yp='copypath'
13 | alias cz='czg'
14 |
15 | # Git
16 | alias gs='git status'
17 | alias gad='git add .'
18 | alias gcm="git commit -m"
19 | alias gpull='git pull'
20 | alias gpush='git push'
21 |
22 | # 显示当前目录信息
23 | alias l='exa'
24 | alias ll='exa -1'
25 | alias ls='exa -lbF --git'
26 | alias lt='exa --tree --level=2'
27 | alias la='exa -lbhHigUmuSa --time-style=long-iso --git --color-scale'
28 |
--------------------------------------------------------------------------------
/1-system/.zimrc:
--------------------------------------------------------------------------------
1 | # 内置扩展
2 | zmodule environment
3 | zmodule input
4 | zmodule termtitle
5 | zmodule utility
6 | zmodule completion
7 | zmodule git-info
8 | zmodule duration-info
9 | zmodule prompt-pwd
10 | zmodule magicmace
11 |
12 | # 其他扩展
13 | zmodule romkatv/powerlevel10k
14 | zmodule zsh-users/zsh-completions
15 | zmodule zsh-users/zsh-autosuggestions
16 | zmodule zsh-users/zsh-history-substring-search
17 | zmodule zdharma-continuum/fast-syntax-highlighting
18 | zmodule supercrabtree/k
19 | zmodule hlissner/zsh-autopair
20 | zmodule jeffreytse/zsh-vi-mode
21 |
22 | # oh-my-zsh 的扩展
23 | # clipboard 里面有个命令(copyclip)是 copypath 需要用的,所以必须先加载进来
24 | zmodule ohmyzsh/ohmyzsh --root lib --source clipboard.zsh
25 | zmodule ohmyzsh/ohmyzsh --root plugins/copypath
26 | zmodule ohmyzsh/ohmyzsh --root plugins/autojump
27 |
--------------------------------------------------------------------------------
/3-js/word-sort.js:
--------------------------------------------------------------------------------
1 | // 单词排序脚本
2 |
3 | import fs from 'fs'
4 | import path from 'path'
5 | import { fileURLToPath } from 'url'
6 |
7 | // 在 ES Module 里面不能直接用 __dirname 麻烦死我了
8 | // NOTE: 因为我在 package.json 中配置 type: module
9 | const _fileName = fileURLToPath(import.meta.url)
10 | const filePath = process.argv.slice(2)[0] || path.join(path.dirname(_fileName), 'index.md')
11 | const data = fs.readFileSync(filePath, 'utf8')
12 |
13 | let text = ''
14 | let match = null
15 | // const regex = /(> .*)\n([\s\S]*?)(?=\n{2}|$)/g
16 | const regex = /(>.*)\n([\s\S]*?)(?=(>.*)|$)/g
17 | while ((match = regex.exec(data)) !== null) {
18 | // 匹配出所有的单词
19 | const title = match[1]
20 | const words = match[2].match(/\w+/g)
21 | text += title + '\n\n- ' + words.sort().join('\n- ') + '\n\n'
22 | }
23 |
24 | // 写入文件
25 | fs.writeFileSync(filePath, text, 'utf8')
26 |
--------------------------------------------------------------------------------
/5-docker/srs/rtc2rtmp.conf:
--------------------------------------------------------------------------------
1 |
2 | listen 1935;
3 | max_connections 1000;
4 | daemon off;
5 | srs_log_tank console;
6 |
7 | http_server {
8 | enabled on;
9 | listen 8080;
10 | dir ./objs/nginx/html;
11 | }
12 |
13 | http_api {
14 | enabled on;
15 | }
16 | stats {
17 | network 0;
18 | }
19 | rtc_server {
20 | enabled on;
21 | listen 8000; # UDP port
22 | # @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
23 | candidate $CANDIDATE;
24 | }
25 |
26 | vhost __defaultVhost__ {
27 | rtc {
28 | enabled on;
29 | # @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtmp-to-rtc
30 | rtmp_to_rtc on;
31 | # @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtc-to-rtmp
32 | rtc_to_rtmp on;
33 | # https://github.com/ossrs/srs/issues/2677
34 | # https://github.com/ossrs/srs/issues/3102
35 | pli_for_rtmp 0.5;
36 | }
37 |
38 | http_remux {
39 | enabled on;
40 | mount [vhost]/[app]/[stream].flv;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/6-chrome/stylish/2-打字测试.css:
--------------------------------------------------------------------------------
1 | /* 整个打字区域 */
2 | #content {
3 | margin-top: 66px;
4 | height: 720px !important;
5 | }
6 |
7 | /* 所有行 */
8 | #content .typing .text {
9 | font-family: Input Mono Freeze !important;
10 | height: 0.5em;
11 | border: 0 !important;
12 | border-bottom: 1px solid #ccc;
13 | }
14 |
15 | /* 输入框 */
16 | #content .typing input {
17 | height: 0;
18 | font-family: Input Mono Freeze !important;
19 | z-index: -999;
20 | }
21 |
22 | /* 正在输入的行 */
23 | #content div.typing_on,
24 | #content div.typing_on div {
25 | background-color: #fff !important;
26 | }
27 | #content div.typing_on div > span {
28 | position: relative;
29 | }
30 | #content div.typing_on .green:last-child:after,
31 | #content div.typing_on .red:last-child:after {
32 | content: '';
33 | position: absolute;
34 | left: auto;
35 | width: 0.6em;
36 | height: 1.3em;
37 | border-bottom: 0.15em solid #0984e3;
38 | /* animation: sparkle 0.6s infinite; */
39 | }
40 |
41 | /* 一闪一闪的动画 */
42 | @keyframes sparkle {
43 | 0% {
44 | opacity: 1;
45 | }
46 | 50% {
47 | opacity: 0.5;
48 | }
49 | 100% {
50 | opacity: 1;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/4-shell/syncFileConfig.sh:
--------------------------------------------------------------------------------
1 | # system path
2 | userPath="/Users/feng"
3 | vscodeSystemPath="${userPath}/Library/Application Support/Code/User"
4 | zshPath="${userPath}/.config/zsh"
5 |
6 | # my config path
7 | configPath="${userPath}/codebase/utils/config"
8 | systemPath="${configPath}/1-system"
9 | vsocdePath="${configPath}/2-vscode"
10 | pathArr=(${systemPath} ${vsocdePath})
11 |
12 | # 自动校验创建目录
13 | for item in "${pathArr[@]}"; do
14 | if [ ! -d "${item}" ]; then
15 | mkdir -p "${item}"
16 | echo "${item} 路径目录创建成功!"
17 | fi
18 | done
19 |
20 | # gitconfig
21 | cat ${userPath}/.gitconfig >${systemPath}/.gitconfig
22 | # czg
23 | cat ${userPath}/.commitlintrc.js >${systemPath}/.commitlintrc.js
24 | # vim
25 | cat ${userPath}/.vim/vimrc >${systemPath}/.vimrc
26 | cat ${userPath}/.vim/nvim.vim >${systemPath}/.nvim.vim
27 | # zimrc
28 | cat ${userPath}/.zimrc >${systemPath}/.zimrc
29 | # zshrc
30 | cat ${userPath}/.zshrc >${systemPath}/.zshrc
31 | # other zsh
32 | # NOTE: -f 参数代表强制覆盖,若想递归复制可以添加 -r 参数
33 | cp -f ${zshPath}/* ${systemPath}/
34 |
35 | # VS Code
36 | # NOTE: 双引号用于解析变量,双引号内的变量可以被扩展,而单引号内的变量则不会被扩展
37 | # 这里需要再添加一个双引号才能特殊处理带有空格的目录/文件名
38 | # grep -v 取反,简单做下数据脱敏(key)-e 指定多个模式
39 | grep -v -e "secret" -e "baidu.comate.license" "${vscodeSystemPath}/settings.json" >${vsocdePath}/settings.json
40 | cat "${vscodeSystemPath}/keybindings.json" >${vsocdePath}/keybindings.json
41 |
42 | echo "
✅ 同步 config 配置文件完成!
"
43 |
--------------------------------------------------------------------------------
/5-docker/compose.yml:
--------------------------------------------------------------------------------
1 | # docker compose 版本
2 | version: '3.7'
3 |
4 | services:
5 | # 服务名称
6 | mysql:
7 | # 镜像
8 | image: mysql:8.0
9 | # docker 重启后容器也跟着重启
10 | restart: always
11 | # 构建容器后所执行的命令
12 | command:
13 | # 服务器加了个更广泛的字符编码和表情符号,在 my.cnf 可覆盖
14 | # --character-set-server=utf8mb4
15 | # --collation-server=utf8mb4_unicode_ci
16 | # --lower-case-table-names=1 # NOTE: 忽略数据表名大小写:该属性只有初始化构建时才生效,my.cnf 无法覆盖,必须重新配置 mysql 服务
17 | # 端口映射
18 | ports:
19 | - 3306:3306
20 | # 卷体积映射:docker compose 的好处就是可以使用相对路径
21 | volumes:
22 | # 配置文件:需要本地目录存在这个文件
23 | - ./mysql/conf/my.cnf:/etc/my.cnf
24 | # 数据目录:本地存在目录即可
25 | - ./mysql/data:/var/lib/mysql
26 | # 环境变量
27 | environment:
28 | # 用户密码
29 | MYSQL_USER: ${MYSQL_ROOT}
30 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
31 | # 时区
32 | TZ: Asia/Shanghai
33 |
34 | srs:
35 | image: registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
36 | restart: always
37 | environment:
38 | # 在 srs 内部配置文件用得上,比如 rtc2rtmp.conf
39 | # - CANDIDATE=$(ifconfig en6 inet | grep 'inet ' | awk '{print $2}') # TODO: 有点问题,有空再看
40 | - CANDIDATE=192.168.1.2 # NOTE: 写死的 ip 可能会变,注意检查
41 | command:
42 | ./objs/srs -c conf/rtc2rtmp.conf
43 | ports:
44 | - 8080:8080
45 | - 1935:1935
46 | - 1985:1985
47 | - 8000:8000/udp
48 | volumes:
49 | # NOTE: 这种方式你要确保本地有 conf 和 objs 以及内部配置文件信息
50 | - ./srs/conf:/usr/local/srs/conf
51 | - ./srs/objs:/usr/local/srs/objs
52 | # 这里直接 volume 名字即可
53 | # - srs_conf:/usr/local/srs/conf
54 | # - srs_objs:/usr/local/srs/objs
55 |
56 | # 在 docker run 命令使用 Docker 内的 Volumes 时 Dokcer 会自动创建好
57 | # 但在 compose 内不行,要先在顶层先定义 volumes 名称用于创建
58 | # volumes:
59 | # srs_conf:
60 | # srs_objs:
61 |
--------------------------------------------------------------------------------
/1-system/.nvim.vim:
--------------------------------------------------------------------------------
1 | " Settings
2 | " ===============================================
3 | set clipboard=unnamedplus
4 | set clipboard=unnamed
5 | set ignorecase smartcase
6 | set ttimeout ttimeoutlen=10
7 |
8 | " Key Map
9 | " ===============================================
10 | let mapleader=" "
11 | " nmap j gj
12 | " nmap k gk
13 | " 临时解决一下折叠行自动展开问题
14 | map J 4gj
15 | map K 4gk
16 | nmap '' ysiw'
17 | nmap "" ysiw"
18 | noremap H ^
19 | noremap L g_
20 | nnoremap U
21 | nnoremap vv viw
22 | nnoremap die ggdG
23 | nnoremap vie ggvG
24 | nnoremap df V$%d
25 | nnoremap iw V$%
26 | nnoremap yf V$%y
27 | nnoremap ; :nohl
28 | vnoremap p "_dP
29 | " vnoremap '' S'
30 |
31 | " VS Code Notify
32 | " ===============================================
33 | " basic
34 | nnoremap e call VSCodeNotify('workbench.action.toggleSidebarVisibility')
35 | nnoremap l call VSCodeNotify('workbench.action.toggleAuxiliaryBar')
36 | nnoremap s call VSCodeNotify('workbench.action.files.save')
37 | nnoremap q call VSCodeNotify('workbench.action.closeActiveEditor')
38 | nnoremap w call VSCodeNotify('workbench.action.files.saveWithoutFormatting')
39 | nnoremap e call VSCodeNotify('workbench.action.toggleSidebarVisibility')
40 | " editor
41 | nnoremap s call VSCodeNotify('leap.find')
42 | nnoremap zj call VSCodeNotify('editor.gotoNextFold')
43 | nnoremap zk call VSCodeNotify('editor.gotoPreviousFold')
44 | nnoremap zc call VSCodeNotify('editor.fold')
45 | nnoremap zo call VSCodeNotify('editor.unfold')
46 | nnoremap zC call VSCodeNotify('editor.foldAll')
47 | nnoremap zO call VSCodeNotify('editor.unfoldAll')
48 | " nnoremap gj call VSCodeNotify('cursorMove', { 'to': 'down', 'by': 'wrappedLine', 'value': v:count1 })
49 | " nnoremap gk call VSCodeNotify('cursorMove', { 'to': 'up', 'by': 'wrappedLine', 'value': v:count1 })
50 | " nnoremap i call VSCodeNotify('extension.toggleBool')
51 |
52 | " Plugins
53 | " ===============================================
54 | call plug#begin('~/.vim/plugged')
55 | Plug 'gcmt/wildfire.vim'
56 | Plug 'tpope/vim-surround'
57 | call plug#end()
58 |
--------------------------------------------------------------------------------
/3-js/bili-danmu.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const request = axios.create({
4 | headers: {
5 | 'User-Agent':
6 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
7 | Referer: 'https://www.bilibili.com/',
8 | },
9 | })
10 |
11 | request.interceptors.response.use(
12 | (response) => response.data,
13 | (err) => {
14 | console.log(err)
15 | },
16 | )
17 |
18 | let count = 100
19 |
20 | async function sendReq() {
21 | // 三个变量需要控制
22 | // msg 弹幕
23 | // cookie
24 | // csrf 验证
25 | // roomid 房间号
26 |
27 | const msg = count--
28 | const roomid = '24337535'
29 | const csrf = 'd9869c210ec46e4a22c7b49e7b6c8bef'
30 |
31 | const res = await request({
32 | url: 'https://api.live.bilibili.com/msg/send',
33 | method: 'POST',
34 | headers: {
35 | cookie: `Hm_lpvt_8a6e55dbd2870f0f5bc9194cddf32a02=1719750073; Hm_lvt_8a6e55dbd2870f0f5bc9194cddf32a02=1719750073; PVID=6; browser_resolution=1756-1001; CURRENT_FNVAL=4048; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjAwMDkyNjgsImlhdCI6MTcxOTc1MDAwOCwicGx0IjotMX0.4xLm1sY2H4sdDOGHHFDtPSfCH4hAl2cL5cQDJ0vy8jk; bili_ticket_expires=1720009208; bp_t_offset_3546561336314420=948808372184940544; home_feed_column=5; b_lsid=4510F78D8_19069176086; enable_web_push=DISABLE; header_theme_version=CLOSE; sid=6ugtopg9; LIVE_BUVID=AUTO7017141061232796; DedeUserID=3546561336314420; DedeUserID__ckMd5=7d88b7f3940d5e75; SESSDATA=8dad6bc2%2C1729657772%2Cbe34b%2A41CjCfxU8MV6b9uHoy_rynrikLq0BIEXzAWKKulelMMSIe7BMnG9U0DZcC-BYTL945GdYSVnpEQ1dIMGFVSVZfWXFSUjhueVpzcUc0b2hPY3JfYWQ4ajBveEFBRkpVblFGSTJlbU1QZElnQ3hmRS1rTEUwVl9KR1pLRkVHUXJCc1piLVF1TW11WHl3IIEC; bili_jct=d9869c210ec46e4a22c7b49e7b6c8bef; FEED_LIVE_VERSION=V_WATCHLATER_PIP_WINDOW3; buvid_fp=e91b03d2e1ed017e755baff80ded460c; _uuid=9DD9BE11-EA53-D4E9-FCFC-E6D1AB5E2DE527149infoc; buvid4=DC6A0D8F-FBA1-1AE6-7E3D-2662B1421CD227327-024042604-szwJdP2i5gLa6D9G20NMIw%3D%3D; rpdid=|(u)~m~Y)uku0J'u~||YJ|lYu; b_nut=1700630560; buvid3=14B1BF0D-524D-B89C-BBBF-0E8C47F5FFEE60432infoc`,
36 | 'Content-Type': 'application/x-www-form-urlencoded',
37 | },
38 | data: {
39 | msg,
40 | csrf,
41 | roomid,
42 | // 下面这几个固定的,但是必须要发
43 | fontsize: 25,
44 | color: 5816798,
45 | rnd: 1719748133,
46 | },
47 | })
48 |
49 | if (res.code === 0) {
50 | console.log(`弹幕: ${msg} 发送成功 ✅`)
51 | } else {
52 | console.log(`弹幕: ${msg} 发送失败 ❌`)
53 | console.log(res)
54 | }
55 | }
56 |
57 | function getRandomNum(min, max) {
58 | const num = Math.floor(Math.random() * (max - min + 1)) + min
59 | console.log(num)
60 | return num
61 | }
62 |
63 | sendReq()
64 |
65 | setInterval(() => {
66 | sendReq()
67 | }, 22000)
68 |
--------------------------------------------------------------------------------
/1-system/.commitlintrc.js:
--------------------------------------------------------------------------------
1 | // .commitlintrc.js
2 |
3 | module.exports = {
4 | rules: {
5 | // @see: https://commitlint.js.org/#/reference-rules
6 | },
7 | prompt: {
8 | alias: {
9 | fd: 'docs: fix typos',
10 | ur: 'docs: update README',
11 | cu: 'chore: update',
12 | },
13 | messages: {
14 | type: '选择你要提交的类型 :',
15 | scope: '选择一个提交范围(可选):',
16 | customScope: '请输入自定义的提交范围 :',
17 | subject: '填写简短精炼的变更描述 :\n',
18 | body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
19 | breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
20 | footerPrefixesSelect: '选择关联issue前缀(可选):',
21 | customFooterPrefix: '输入自定义issue前缀 :',
22 | footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
23 | confirmCommit: '是否提交或修改commit?',
24 | },
25 | types: [
26 | { value: 'feat', name: 'feat: ✨ 新增功能 | A new feature' },
27 | { value: 'fix', name: 'fix: 🐛 修复缺陷 | A bug fix' },
28 | { value: 'docs', name: 'docs: 📝 文档更新 | Documentation only changes' },
29 | { value: 'style', name: 'style: 💄 代码格式 | Changes that do not affect the meaning of the code' },
30 | { value: 'refactor', name: 'refactor: ♻️ 代码重构 | A code change that neither fixes a bug nor adds a feature' },
31 | { value: 'perf', name: 'perf: ⚡️ 性能提升 | A code change that improves performance' },
32 | { value: 'test', name: 'test: ✅ 测试相关 | Adding missing tests or correcting existing tests' },
33 | { value: 'build', name: 'build: 📦️ 构建相关 | Changes that affect the build system or external dependencies' },
34 | { value: 'ci', name: 'ci: 🎡 持续集成 | Changes to our CI configuration files and scripts' },
35 | { value: 'revert', name: 'revert: ⏪️ 回退代码 | Revert to a commit' },
36 | { value: 'chore', name: 'chore: 🛠 其他修改 | Other changes that do not modify src or test files' },
37 | ],
38 | useEmoji: false,
39 | emojiAlign: 'center',
40 | useAI: false,
41 | aiNumber: 1,
42 | themeColorCode: '',
43 | scopes: [],
44 | allowCustomScopes: true,
45 | allowEmptyScopes: true,
46 | customScopesAlign: 'bottom',
47 | customScopesAlias: 'custom',
48 | emptyScopesAlias: 'empty',
49 | upperCaseSubject: false,
50 | markBreakingChangeMode: false,
51 | allowBreakingChanges: ['feat', 'fix'],
52 | breaklineNumber: 100,
53 | breaklineChar: '|',
54 | skipQuestions: [],
55 | issuePrefixes: [
56 | // 如果使用 gitee 作为开发管理
57 | { value: 'link', name: 'link: 链接 ISSUES 进行中' },
58 | { value: 'closed', name: 'closed: 标记 ISSUES 已完成' },
59 | ],
60 | customIssuePrefixAlign: 'top',
61 | emptyIssuePrefixAlias: 'skip',
62 | customIssuePrefixAlias: 'custom',
63 | allowCustomIssuePrefix: true,
64 | allowEmptyIssuePrefix: true,
65 | confirmColorize: true,
66 | maxHeaderLength: Infinity,
67 | maxSubjectLength: Infinity,
68 | minSubjectLength: 0,
69 | scopeOverrides: undefined,
70 | defaultBody: '',
71 | defaultIssues: '',
72 | defaultScope: '',
73 | defaultSubject: '',
74 | },
75 | }
76 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 前言
2 |
3 | 🤩 一些配置文件 ➕ 主题预览 ➕ 字体推荐
4 |
5 | > VS Code
6 |
7 | - [settings.json](./2-vscode/settings.json) · 系统配置文件
8 | - [keybindings.json](./2-vscode/keybindings.json) · 键盘快捷键映射配置文件
9 |
10 | > 系统
11 |
12 | - [nvim](./1-system/.nvim.vim) | [vimrc](./1-system/.vimrc) | [zimrc](./1-system/.zimrc) | [zshrc](./1-system/main.zsh)
13 | - [Zimfw](https://github.com/zimfw/zimfw) 一个比 oh-my-zsh 更轻量级更快的 zsh 配置框架
14 |
15 | 主题
16 |
17 | > 常用
18 |
19 | - Default Light Modern - 浅色自带。
20 | - [Maple Theme](https://marketplace.visualstudio.com/items?itemName=subframe7536.theme-maple) - 深色好看!色彩搭配超细节很舒服!
21 |
22 | > 其他
23 |
24 | - [Spacegray VSCode](https://marketplace.visualstudio.com/items?itemName=ionutvmi.spacegray-vscode) - 深色平替。
25 | - [GitHub Plus Theme](https://marketplace.visualstudio.com/items?itemName=thenikso.github-plus-theme) - 浅色,群友推荐。
26 | - [Moegi Theme](https://marketplace.visualstudio.com/items?itemName=ddiu8081.moegi-theme) - 深浅皆用,Diu 大佬写的主题。
27 | - [Github Dark Classic Theme](https://marketplace.visualstudio.com/items?itemName=BerriJ.github-vscode-theme-dark-classic) - 深色,GitHub 主题还是很舒服的。
28 | - [JetBrains Fleet Dark](https://marketplace.visualstudio.com/items?itemName=FranzGollhammer.jb-fleet-dark) - 深色,Fleet Dark,对于 Fleet 编辑器主题还原度非常高了 👍🏻
29 | - [Evondev Dracula](https://marketplace.visualstudio.com/items?itemName=evondev.dracula-high-contrast) - 深色,对比度高,定位和写代码更清晰,能给人一种极客的感觉 ⚡
30 | - [Vitesse Theme](https://marketplace.visualstudio.com/items?itemName=antfu.theme-vitesse) - 深浅皆用,托尼写的!整体配色扁平,但是看久了感觉有点暗,部分细节需要自己处理下。
31 | - [Panda Theme](https://marketplace.visualstudio.com/items?itemName=tinkertrain.theme-panda) - 深色,也是扁平的粉青配色,但是已经很久没有更新了,有些颜色细节适配的不是特别好。
32 |
33 | 字体
34 |
35 | > 常用
36 |
37 | - [Liga SFMono Nerd Font](https://github.com/shaunsingh/SFMono-Nerd-Font-Ligaturized) - zx 哥推荐,看起来不错,体验中...
38 | - [Input Mono](https://input.djr.com/) - 托尼推荐!用了好久了。
39 | - [Maple Font](https://github.com/subframe7536/maple-font) - 带连字和控制台图标的圆角等宽字体。
40 | - [JetBrains Mono Font](https://github.com/JetBrains/JetBrainsMono) - 方方正正的,很适合写代码。
41 |
42 | > 其他
43 |
44 | - Monaco - 来源于 Mac 系统自带。
45 | - [Fira Code](https://github.com/tonsky/FiraCode) - 带连字。
46 | - [Comic Shanns Font](https://github.com/shannpersand/comic-shanns) - 很酷的字体。
47 | - [IBM Plex Mono](https://github.com/IBM/plex)
48 |
49 | > 字体工具网站
50 |
51 | - [FontFreeze](https://mutsuntsai.github.io/fontfreeze/) - 冻结字体的变体功能生成 ttf,可以导入 Input Mono 试试。
52 | - [Ligaturizer](https://github.com/ToxicFrog/Ligaturizer/) - 把连字添加到其他不支持连字的字体内。
53 |
54 | 常用主题
55 |
56 |
57 |
58 |
59 |
60 |
61 | 其他主题
62 |
63 | 
64 | 
65 | 
66 | 
67 | 
68 |
--------------------------------------------------------------------------------
/2-vscode/extensions.txt:
--------------------------------------------------------------------------------
1 | akamud.vscode-theme-onedark
2 | aminer.codegeex
3 | andrejunges.handlebars
4 | antfu.file-nesting
5 | antfu.goto-alias
6 | antfu.iconify
7 | antfu.icons-carbon
8 | antfu.theme-vitesse
9 | antfu.unocss
10 | asvetliakov.vscode-neovim
11 | atdow.vue-jumper
12 | baiducomate.comate
13 | be5invis.vscode-custom-css
14 | beardedbear.beardedtheme
15 | berrij.github-vscode-theme-dark-classic
16 | bierner.github-markdown-preview
17 | bierner.markdown-checkbox
18 | bierner.markdown-emoji
19 | bierner.markdown-footnotes
20 | bierner.markdown-mermaid
21 | bierner.markdown-preview-github-styles
22 | bierner.markdown-yaml-preamble
23 | bradlc.vscode-tailwindcss
24 | brandonkirbyson.vscode-animations
25 | capaj.vscode-standardjs-snippets
26 | catppuccin.catppuccin-vsc-icons
27 | chensuiyi.fn-map
28 | christian-kohler.npm-intellisense
29 | christian-kohler.path-intellisense
30 | cipchk.cssrem
31 | codeium.codeium
32 | csstools.postcss
33 | cuixiaorui.cvim
34 | cweijan.dbclient-jdbc
35 | cweijan.vscode-mysql-client2
36 | davidbwaters.macos-modern-theme
37 | dbaeumer.vscode-eslint
38 | ddiu8081.moegi-theme
39 | degreat.fonted
40 | donjayamanne.githistory
41 | drcika.apc-extension
42 | eamodio.gitlens
43 | ecmel.vscode-html-css
44 | ellreka.tailwindcss-highlight
45 | emmanuelbeziat.vscode-great-icons
46 | esbenp.prettier-vscode
47 | evan-buss.font-switcher
48 | evondev.dracula-high-contrast
49 | exodiusstudios.comment-anchors
50 | fabiospampinato.vscode-diff
51 | file-icons.file-icons
52 | fittentech.fitten-code
53 | formulahendry.auto-close-tag
54 | formulahendry.auto-rename-tag
55 | formulahendry.code-runner
56 | foxundermoon.shell-format
57 | franzgollhammer.jb-fleet-dark
58 | github.vscode-pull-request-github
59 | heybourn.headwind
60 | humao.rest-client
61 | intellsmi.comment-translate
62 | ionutvmi.path-autocomplete
63 | ionutvmi.spacegray-vscode
64 | jasonlhy.hungry-delete
65 | jbockle.jbockle-format-files
66 | kaiqun.tencent-cloud-translate
67 | kakumei.ts-debug
68 | kc.danmaku
69 | kevinmcgowan.typescriptimport
70 | kisstkondoros.vscode-gutter-preview
71 | leetcode.vscode-leetcode
72 | lehni.vscode-fix-checksums
73 | letrieu.expand-region
74 | lihuiwang.vue-alias-skip
75 | meganrogge.template-string-converter
76 | mgmcdermott.vscode-language-babel
77 | mhutchie.git-graph
78 | mikestead.dotenv
79 | mkxml.vscode-filesize
80 | moetype.moe-panda-theme
81 | mrcrowl.easy-less
82 | ms-azuretools.vscode-docker
83 | ms-ceintl.vscode-language-pack-zh-hans
84 | ms-vscode.live-server
85 | ms-vsliveshare.vsliveshare
86 | murloccra4ler.leap
87 | muuvmuuv.vscode-sundial
88 | naumovs.color-highlight
89 | nicoespeon.hocus-pocus
90 | octref.vetur
91 | oderwat.indent-rainbow
92 | phoenisx.cssvar
93 | pkief.material-icon-theme
94 | pmneo.tsimporter
95 | pucelle.vscode-css-navigation
96 | quick-lint.quick-lint-js
97 | redguardtoo.matchit
98 | remisa.shellman
99 | rsbondi.highlight-words
100 | shd101wyy.markdown-preview-enhanced
101 | silesky.toggle-boolean
102 | simonhe.fast-jump
103 | simonhe.lazy-install
104 | simonhe.to-tailwindcss
105 | simonhe.to-ts-type
106 | simonhe.unot
107 | simonhe.vscode-alias-jump
108 | simonhe.vscode-tailwind-magic
109 | streetsidesoftware.code-spell-checker
110 | stringham.move-ts
111 | styled-components.vscode-styled-components
112 | subframe7536.theme-maple
113 | tal7aouy.icons
114 | techer.open-in-browser
115 | thenikso.github-plus-theme
116 | tinkertrain.theme-panda
117 | tomoki1207.pdf
118 | usernamehw.errorlens
119 | visualstudioexptteam.vscodeintellicode
120 | vscodevim.vim
121 | vue.volar
122 | wejectchan.vue3-snippets-for-vscode
123 | withfig.fig
124 | wix.vscode-import-cost
125 | wraith13.bracket-lens
126 | xabikos.javascriptsnippets
127 | xadillax.viml
128 | xyz.local-history
129 | yandeu.five-server
130 | yoavbls.pretty-ts-errors
131 | yummygum.city-lights-icon-vsc
132 | yzhang.markdown-all-in-one
133 | zhuangtongfa.material-theme
134 |
--------------------------------------------------------------------------------
/1-system/.zshrc:
--------------------------------------------------------------------------------
1 | # Fig pre block. Keep at the top of this file.
2 | # [[ -f "$HOME/.fig/shell/zshrc.pre.zsh" ]] && builtin source "$HOME/.fig/shell/zshrc.pre.zsh"
3 |
4 | # fzf
5 | # ---------
6 | if [[ ! "$PATH" == */opt/homebrew/opt/fzf/bin* ]]; then
7 | PATH="${PATH:+${PATH}:}/opt/homebrew/opt/fzf/bin"
8 | fi
9 | export FZF_DEFAULT_OPTS='--bind=ctrl-t:top,change:top --bind ctrl-e:down,ctrl-u:up'
10 | # export FZF_DEFAULT_OPTS='--bind ctrl-e:down,ctrl-u:up --preview "[[ $(file --mime {}) =~ binary ]] && echo {} is a binary file || (ccat --color=always {} || highlight -O ansi -l {} || cat {}) 2> /dev/null | head -500"'
11 | # export FZF_DEFAULT_COMMAND='ag --hidden --ignore .git -g ""'
12 | export FZF_DEFAULT_COMMAND='fd'
13 | export FZF_COMPLETION_TRIGGER='\'
14 | export FZF_TMUX=1
15 | export FZF_TMUX_HEIGHT='80%'
16 | export fzf_preview_cmd='[[ $(file --mime {}) =~ binary ]] && echo {} is a binary file || (ccat --color=always {} || highlight -O ansi -l {} || cat {}) 2> /dev/null | head -500'
17 | # Auto-completion
18 | # ---------------
19 | # [[ $- == *i* ]] && source "/opt/homebrew/opt/fzf/shell/completion.zsh" 2> /dev/null
20 | # Key bindings
21 | # ------------
22 | source "/opt/homebrew/opt/fzf/shell/key-bindings.zsh"
23 |
24 |
25 | # Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
26 | # Initialization code that may require console input (password prompts, [y/n]
27 | # confirmations, etc.) must go above this block; everything else may go below.
28 | if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
29 | source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
30 | fi
31 |
32 | # Remove older command from the history if a duplicate is to be added.
33 | setopt HIST_IGNORE_ALL_DUPS
34 | # Remove path separator from WORDCHARS.
35 | WORDCHARS=${WORDCHARS//[\/]}
36 | # Disable automatic widget re-binding on each precmd. This can be set when
37 | # zsh-users/zsh-autosuggestions is the last module in your ~/.zimrc.
38 | ZSH_AUTOSUGGEST_MANUAL_REBIND=1
39 | # Set what highlighters will be used.
40 | # See https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/docs/highlighters.md
41 | ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets)
42 |
43 |
44 | # Zim
45 | ZIM_HOME=${ZDOTDIR:-${HOME}}/.zim
46 | # Download zimfw plugin manager if missing.
47 | if [[ ! -e ${ZIM_HOME}/zimfw.zsh ]]; then
48 | if (( ${+commands[curl]} )); then
49 | curl -fsSL --create-dirs -o ${ZIM_HOME}/zimfw.zsh \
50 | https://github.com/zimfw/zimfw/releases/latest/download/zimfw.zsh
51 | else
52 | mkdir -p ${ZIM_HOME} && wget -nv -O ${ZIM_HOME}/zimfw.zsh \
53 | https://github.com/zimfw/zimfw/releases/latest/download/zimfw.zsh
54 | fi
55 | fi
56 | # Install missing modules, and update ${ZIM_HOME}/init.zsh if missing or outdated.
57 | if [[ ! ${ZIM_HOME}/init.zsh -nt ${ZDOTDIR:-${HOME}}/.zimrc ]]; then
58 | source ${ZIM_HOME}/zimfw.zsh init -q
59 | fi
60 | # Initialize modules.
61 | source ${ZIM_HOME}/init.zsh
62 | zmodload -F zsh/terminfo +p:terminfo
63 | # Bind ^[[A/^[[B manually so up/down works both before and after zle-line-init
64 | for key ('^[[A' '^P' ${terminfo[kcuu1]}) bindkey ${key} history-substring-search-up
65 | for key ('^[[B' '^N' ${terminfo[kcud1]}) bindkey ${key} history-substring-search-down
66 | for key ('k') bindkey -M vicmd ${key} history-substring-search-up
67 | for key ('j') bindkey -M vicmd ${key} history-substring-search-down
68 | unset key
69 |
70 |
71 | # fnm
72 | eval "$(fnm env --use-on-cd)"
73 |
74 |
75 | # pnpm
76 | export PNPM_HOME="/Users/feng/Library/pnpm"
77 | case ":$PATH:" in
78 | *":$PNPM_HOME:"*) ;;
79 | *) export PATH="$PNPM_HOME:$PATH" ;;
80 | esac
81 |
82 |
83 | # To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
84 | [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
85 |
86 | # Fig post block. Keep at the bottom of this file.
87 | # [[ -f "$HOME/.fig/shell/zshrc.post.zsh" ]] && builtin source "$HOME/.fig/shell/zshrc.post.zsh"
88 |
89 | # 加载我的 zsh 配置
90 | source ~/.config/zsh/main.zsh
91 |
92 | typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet
93 | typeset -g POWERLEVEL9K_INSTANT_PROMPT=off
94 |
--------------------------------------------------------------------------------
/1-system/.vimrc:
--------------------------------------------------------------------------------
1 | " ================================================================
2 | " 基本设置
3 | " ================================================================
4 | " vim 时, normal/insert 模式下光标的显示状态
5 | " let &t_ut=''
6 | " let &t_SI = "\]50;CursorShape=1\x7"
7 | " let &t_SR = "\]50;CursorShape=2\x7"
8 | " let &t_EI = "\]50;CursorShape=0\x7"
9 |
10 | " NOTE: 可更改 Terminal + iTerm2 + VS Code 终端通过 vim 命令操作文件的光标样式
11 | let &t_SI = "\e[5 q" "SI = INSERT mode
12 | let &t_SR = "\e[4 q" "SR = REPLACE mode
13 | let &t_EI = "\e[1 q" "EI = NORMAL mode (ELSE)
14 |
15 | " 可以让你在 vim 编辑时使用鼠标进行操作
16 | set mouse=a
17 | " 显示普通模式未完成的指令(一般在右下角)
18 | set showcmd
19 | " 解决插入模式下删除键不能删除的问题
20 | set backspace=indent,eol,start
21 | " 命令模式按下 Tab 键, 展示候选词
22 | set wildmenu
23 | " 打通系统 cv 和 vim
24 | " 系统剪切板 -> vim
25 | set clipboard=unnamedplus
26 | " vim -> 系统剪切板
27 | set clipboard=unnamed
28 | " 解决插入模式 -> 普通模式延迟显示的问题
29 | set ttimeout ttimeoutlen=10
30 | " 位置标识记录 | 关闭文件后再次打开, 光标会回到你上一次离开的位置
31 | au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
32 | " 保留文件视图更改的状态
33 | " autocmd BufWrite * mkview
34 | " autocmd BufWinLeave * mkview
35 | " autocmd BufRead * silent loadview
36 |
37 | " ================================================================
38 | " 编辑器设置 | editor
39 | " ================================================================
40 | " 显示行号
41 | set number
42 | " 显示光标行和列信息
43 | " set ruler
44 | " 显示相对行号
45 | " set relativenumber
46 | " 突出当前行显示
47 | set cursorline
48 | " 底部命令行状态栏显示在底部倒数第二行位置 | 设置 0 关闭
49 | set laststatus=2
50 | " 显示语法高亮
51 | syntax enable
52 | syntax on
53 | " 显示多余的符号替换 Tab(>---), 空格(^), 换行(¬)
54 | " set list
55 | " set listchars=tab:>-,trail:^ ",eol:¬
56 | " 开启自动缩进
57 | set autoindent
58 | " 智能缩进
59 | set smartindent
60 | " 发生错误时不要响铃, 也不要闪烁
61 | set noerrorbells
62 | set belloff=all
63 | " 单行内容超出窗口时自动换行显示
64 | set wrap
65 | " 编辑模式下时按一个 Tab 键相当于输入 2 个空格
66 | set tabstop=2
67 | " 格式化时缩进尺寸为 2 个空格, 即 >>、<< 、==(取消全部缩进)时, 每一级的字符数
68 | set shiftwidth=2
69 | " 让 vim 把连续的空格视为一个 Tab, 删除时可以一次删掉一个 Tab 的空格数量
70 | set softtabstop=2
71 | " 把制表符转换为多个空格, 具体空格数量参考 tabstop 和 shiftwidth
72 | set expandtab
73 | " 垂直滚动时, 光标距离顶部/底部的行数 | 保持在你的可视区域的行数
74 | set scrolloff=5
75 | " 在行和段的开始处智能使用 Tab
76 | set smarttab
77 | " 命令行历史记录数量
78 | set history=200
79 | " 自动切换工作目录
80 | " set autochdir
81 | " 合并两行中文时, 不在中间加空格
82 | " set formatoptions+=B
83 | " 合并行时不添加多余空格
84 | " set nojoinspaces
85 |
86 | " ================================================================
87 | " 编码设置
88 | " ================================================================
89 | " 设置 vim 内部默认编码
90 | set encoding=utf-8
91 | " 设置编辑文件时的编码
92 | set fileencoding=utf-8
93 | " 设置 vim 能识别的编码
94 | set fileencodings=ucs-bom,utf-8,cp936,gb18030,gb2312,big5,cuc-jp,cuc-kr,latin
95 | " 设置终端模式(非 GUI 模式)下的编码
96 | set termencoding=utf-8
97 | " 防止特殊符号无法显示
98 | " set ambiwidth=double
99 |
100 | " ================================================================
101 | " 文件设置
102 | " ================================================================
103 | " 自动检测文件类型和缩进格式, 并根据文件类型加载插件
104 | filetype plugin indent on
105 | " 文件被外部改动后, 自动加载
106 | set autoread
107 | " 不生成备份文件
108 | " set nobackup
109 | " 不生成临时文件
110 | " set noswapfile
111 | " 不生成 undo 文件
112 | " set noundofile
113 | " 生成 undo (缓存) 文件, 设置目录位置 | 退出文件后还能记忆之前的操作, 比如 u
114 | " 还原上次的操作更改项, 坏处是会生成很多缓存文件
115 | set undofile
116 | set undodir=~/.vim/undodir
117 |
118 | " ================================================================
119 | " 搜索匹配
120 | " ================================================================
121 | " 高亮显示匹配到的括号
122 | set showmatch
123 | " 高亮显示搜索到的关键字
124 | set hlsearch
125 | " 即时搜索 | 即边搜边高亮
126 | set incsearch
127 | " 智能大小敏感, 若有字母大写, 敏感, 否则不敏感
128 | set ignorecase smartcase
129 |
130 | " ================================================================
131 | " 操作习惯 | 快捷键
132 | " ================================================================
133 | " 将 键配置为 space | 空格
134 | let mapleader = " "
135 | " 快速上下移动 | 这里使用递归因为 jk 都被我改了
136 | map J 5j
137 | map K 5k
138 | " 对于很长的行, vim 会自动换行, 此时 j 或者 k 就会一下跳很多行
139 | " 使用 gk/gj 可以避免跳过多行, 但是不方便, 所以做了如下映射:
140 | noremap k gk
141 | noremap j gj
142 | " 光标移动到所在行开头/结尾
143 | noremap H ^
144 | noremap L $
145 | " 返回上次光标所在位置 | 可跨文件
146 | " nnoremap gk
147 | " 与 gk 相反
148 | " nnoremap gj
149 | " 将查找所在行内容居中显示 | 目前通过 easymotion 替代了
150 | " nnoremap n nzz
151 | " nnoremap N Nzz
152 | " 按 U 执行 redo
153 | nnoremap U
154 | " 在可视模式下使用 p 粘贴时不替换寄存器内容, 这里是利用了黑洞寄存器,
155 | " 将选中内容删除到黑洞寄存器, 然后再执行大写P, 在行尾时会有点bug, 但基本满足需求
156 | vnoremap p "_dP
157 | " 取消搜索高亮
158 | nnoremap ; :nohl
159 | " 可视模式下按 y 将内容写入系统寄存器
160 | " vnoremap y "+y
161 | " 可视模式下按 x 将内容写入(剪切到)系统寄存器
162 | " vnoremap x "+x
163 | " 按 p 将系统寄存器中的内容粘贴出来
164 | " nnoremap p "+p
165 | " 打开一个新的标签页
166 | " map tu :tabe
167 | " 切换左右标签页
168 | " map th :-tabnext
169 | " map tl :+tabnext
170 | " map tx :r !figlet
171 | " 保存
172 | " nnoremap s :w
173 | " nnoremap S :w
174 | " 退出
175 | nnoremap q :q
176 | nnoremap Q :q
177 | " 上下左右分屏
178 | " nnoremap sk; :set nosplitbelow:split
179 | " nnoremap sj; :set splitbelow:split
180 | " nnoremap sh; :set nosplitright:vsplit
181 | " nnoremap sl; :set splitright:vsplit
182 | " 聚焦上下左右分屏
183 | nnoremap l l
184 | nnoremap h h
185 | nnoremap j j
186 | nnoremap k k
187 | " 上下 -> 左右分屏
188 | " nnoremap sv tH
189 | " 上下 -> 上下分屏
190 | " nnoremap sh tK
191 | " 开启/关闭 单词拼写检查
192 | " nnoremap sc :set spell!
193 | " 通过设置一个自定义占位符, 然后按"两次空格"来快速定位更改 | placeholder
194 | " map /<++>:nohl"_c4l
195 | " 刷新全局 vimrc 配置 | 系统会根据文件等级依次往下找
196 | nnoremap R :source $MYVIMRC
197 | " 每次进入一个新文件时先执行取消高亮命令 | 防止上次在此文件的高亮结果再次显示造成视觉干扰
198 | exec "nohl"
199 |
200 | " ================================================================
201 | " 插件引入 | vim-plug
202 | " ================================================================
203 | call plug#begin('~/.vim/plugged')
204 | " 底部状态栏增强
205 | Plug 'itchyny/lightline.vim'
206 | " PaperColor 主题 (亮/暗)
207 | Plug 'nlknguyen/papercolor-theme'
208 | " Molokai 主题(暗色)
209 | Plug 'tomasr/molokai'
210 | " Dracula 主题(暗色), 后面的配置表示将主题装在 dracula 文件夹下
211 | Plug 'dracula/vim', { 'as': 'dracula' }
212 | " 扩展多光标功能
213 | " hint: 这个插件已经被 deprecated 了
214 | " Plug 'terryma/vim-multiple-cursors'
215 | Plug 'mg979/vim-visual-multi', {'branch': 'master'}
216 | " 扩展 . 的功能
217 | " Plug 'tpope/vim-repeat'
218 | " easymotion | 移动指令增强
219 | " Plug 'easymotion/vim-easymotion"
220 | " 通过 enter 键来快速选择包含块内容(text-objects), 再次按下会继续扩大包含块
221 | Plug 'gcmt/wildfire.vim'
222 | " 通过选中内容后按 S 快速添加成对符号, 也支持删除与更改, ds/cs, 与 wildfire 搭配有奇效
223 | Plug 'tpope/vim-surround'
224 | " hint: 这个 plug#end() 一定要记得写啊!!!坑死我啦!!!找了好久的 bug
225 | call plug#end()
226 |
227 | " ================================================================
228 | " 插件相关设置
229 | " ================================================================
230 | "
231 | " lightline.vim
232 | let lightline = {
233 | \ 'colorscheme': 'PaperColor',
234 | \ }
235 |
236 | " PaperColor.vim
237 | let g:PaperColor_Theme_Options = {
238 | \ 'theme': {
239 | \ 'default.dark': {
240 | \ 'transparent_background': 1
241 | \ }
242 | \ }
243 | \ }
244 |
245 | " theme
246 | set background=dark
247 | " colorscheme molokai
248 | " colorscheme dracula
249 | colorscheme PaperColor
250 |
251 | " wildfire
252 | " nmap f (wildfire-quick-select)
253 |
254 | " easymotion
255 | " 替换原生 / 查找
256 | " map / (easymotion-sn)
257 | " 替换原生 n/N 查找
258 | " map n (easymotion-next)zz
259 | " map N (easymotion-prev)zz
260 | " 实现类似 vim-sneak 的双字符查找快速移动
261 | " nmap s (easymotion-s2)
262 | " 上下方向行首字母快速移动
263 | " map j (easymotion-j)
264 | " map k (easymotion-k)
265 |
266 | " ================================================================
267 | " ================================================================
268 |
--------------------------------------------------------------------------------
/3-js/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | axios:
12 | specifier: ^1.7.2
13 | version: 1.7.2
14 | clipboardy:
15 | specifier: ^4.0.0
16 | version: 4.0.0
17 | number-precision:
18 | specifier: ^1.6.0
19 | version: 1.6.0
20 |
21 | packages:
22 |
23 | asynckit@0.4.0:
24 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
25 |
26 | axios@1.7.2:
27 | resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
28 |
29 | clipboardy@4.0.0:
30 | resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==}
31 | engines: {node: '>=18'}
32 |
33 | combined-stream@1.0.8:
34 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
35 | engines: {node: '>= 0.8'}
36 |
37 | cross-spawn@7.0.3:
38 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
39 | engines: {node: '>= 8'}
40 |
41 | delayed-stream@1.0.0:
42 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
43 | engines: {node: '>=0.4.0'}
44 |
45 | execa@8.0.1:
46 | resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
47 | engines: {node: '>=16.17'}
48 |
49 | follow-redirects@1.15.6:
50 | resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
51 | engines: {node: '>=4.0'}
52 | peerDependencies:
53 | debug: '*'
54 | peerDependenciesMeta:
55 | debug:
56 | optional: true
57 |
58 | form-data@4.0.0:
59 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
60 | engines: {node: '>= 6'}
61 |
62 | get-stream@8.0.1:
63 | resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
64 | engines: {node: '>=16'}
65 |
66 | human-signals@5.0.0:
67 | resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
68 | engines: {node: '>=16.17.0'}
69 |
70 | is-docker@3.0.0:
71 | resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
72 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
73 | hasBin: true
74 |
75 | is-inside-container@1.0.0:
76 | resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
77 | engines: {node: '>=14.16'}
78 | hasBin: true
79 |
80 | is-stream@3.0.0:
81 | resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
82 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
83 |
84 | is-wsl@3.1.0:
85 | resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
86 | engines: {node: '>=16'}
87 |
88 | is64bit@2.0.0:
89 | resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==}
90 | engines: {node: '>=18'}
91 |
92 | isexe@2.0.0:
93 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
94 |
95 | merge-stream@2.0.0:
96 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
97 |
98 | mime-db@1.52.0:
99 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
100 | engines: {node: '>= 0.6'}
101 |
102 | mime-types@2.1.35:
103 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
104 | engines: {node: '>= 0.6'}
105 |
106 | mimic-fn@4.0.0:
107 | resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
108 | engines: {node: '>=12'}
109 |
110 | npm-run-path@5.3.0:
111 | resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
112 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
113 |
114 | number-precision@1.6.0:
115 | resolution: {integrity: sha512-05OLPgbgmnixJw+VvEh18yNPUo3iyp4BEWJcrLu4X9W05KmMifN7Mu5exYvQXqxxeNWhvIF+j3Rij+HmddM/hQ==}
116 |
117 | onetime@6.0.0:
118 | resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
119 | engines: {node: '>=12'}
120 |
121 | path-key@3.1.1:
122 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
123 | engines: {node: '>=8'}
124 |
125 | path-key@4.0.0:
126 | resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
127 | engines: {node: '>=12'}
128 |
129 | proxy-from-env@1.1.0:
130 | resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
131 |
132 | shebang-command@2.0.0:
133 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
134 | engines: {node: '>=8'}
135 |
136 | shebang-regex@3.0.0:
137 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
138 | engines: {node: '>=8'}
139 |
140 | signal-exit@4.1.0:
141 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
142 | engines: {node: '>=14'}
143 |
144 | strip-final-newline@3.0.0:
145 | resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
146 | engines: {node: '>=12'}
147 |
148 | system-architecture@0.1.0:
149 | resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==}
150 | engines: {node: '>=18'}
151 |
152 | which@2.0.2:
153 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
154 | engines: {node: '>= 8'}
155 | hasBin: true
156 |
157 | snapshots:
158 |
159 | asynckit@0.4.0: {}
160 |
161 | axios@1.7.2:
162 | dependencies:
163 | follow-redirects: 1.15.6
164 | form-data: 4.0.0
165 | proxy-from-env: 1.1.0
166 | transitivePeerDependencies:
167 | - debug
168 |
169 | clipboardy@4.0.0:
170 | dependencies:
171 | execa: 8.0.1
172 | is-wsl: 3.1.0
173 | is64bit: 2.0.0
174 |
175 | combined-stream@1.0.8:
176 | dependencies:
177 | delayed-stream: 1.0.0
178 |
179 | cross-spawn@7.0.3:
180 | dependencies:
181 | path-key: 3.1.1
182 | shebang-command: 2.0.0
183 | which: 2.0.2
184 |
185 | delayed-stream@1.0.0: {}
186 |
187 | execa@8.0.1:
188 | dependencies:
189 | cross-spawn: 7.0.3
190 | get-stream: 8.0.1
191 | human-signals: 5.0.0
192 | is-stream: 3.0.0
193 | merge-stream: 2.0.0
194 | npm-run-path: 5.3.0
195 | onetime: 6.0.0
196 | signal-exit: 4.1.0
197 | strip-final-newline: 3.0.0
198 |
199 | follow-redirects@1.15.6: {}
200 |
201 | form-data@4.0.0:
202 | dependencies:
203 | asynckit: 0.4.0
204 | combined-stream: 1.0.8
205 | mime-types: 2.1.35
206 |
207 | get-stream@8.0.1: {}
208 |
209 | human-signals@5.0.0: {}
210 |
211 | is-docker@3.0.0: {}
212 |
213 | is-inside-container@1.0.0:
214 | dependencies:
215 | is-docker: 3.0.0
216 |
217 | is-stream@3.0.0: {}
218 |
219 | is-wsl@3.1.0:
220 | dependencies:
221 | is-inside-container: 1.0.0
222 |
223 | is64bit@2.0.0:
224 | dependencies:
225 | system-architecture: 0.1.0
226 |
227 | isexe@2.0.0: {}
228 |
229 | merge-stream@2.0.0: {}
230 |
231 | mime-db@1.52.0: {}
232 |
233 | mime-types@2.1.35:
234 | dependencies:
235 | mime-db: 1.52.0
236 |
237 | mimic-fn@4.0.0: {}
238 |
239 | npm-run-path@5.3.0:
240 | dependencies:
241 | path-key: 4.0.0
242 |
243 | number-precision@1.6.0: {}
244 |
245 | onetime@6.0.0:
246 | dependencies:
247 | mimic-fn: 4.0.0
248 |
249 | path-key@3.1.1: {}
250 |
251 | path-key@4.0.0: {}
252 |
253 | proxy-from-env@1.1.0: {}
254 |
255 | shebang-command@2.0.0:
256 | dependencies:
257 | shebang-regex: 3.0.0
258 |
259 | shebang-regex@3.0.0: {}
260 |
261 | signal-exit@4.1.0: {}
262 |
263 | strip-final-newline@3.0.0: {}
264 |
265 | system-architecture@0.1.0: {}
266 |
267 | which@2.0.2:
268 | dependencies:
269 | isexe: 2.0.0
270 |
--------------------------------------------------------------------------------
/3-js/diary-stats.js:
--------------------------------------------------------------------------------
1 | // 初始版本,请移步:https://github.com/fengstats/diary-duration-stats
2 |
3 | import fs from 'fs'
4 | import path from 'path'
5 |
6 | // 匹配模式
7 | const modeMap = {
8 | // 默认匹配,也就是所有标题都会匹配
9 | free: 'FREE',
10 | // 自定义匹配,会过滤掉除了在 includeTitleList 中的其他标题
11 | custom: 'CUSTOM',
12 | // 临时匹配,与默认匹配一样,只不过输出格式有点差别,可以在执行脚本时开启
13 | temp: 'TEMP',
14 | }
15 | // 前后缀括号映射
16 | const bracketMap = { '': '', '**': '**', '(': ')', '(': ')' }
17 |
18 | let matchMode = modeMap['free']
19 | // 是否需要插入模板格式信息,用于匹配替换,默认开启
20 | let isInsertTemplate = true
21 | // 文件总时长
22 | let fileTotalTime = 0
23 |
24 | // 固定插件标题
25 | const insertTitle = 'Record'
26 | // 需要匹配的标题列表
27 | const includeTitleList = ['重要', '生活', '休闲']
28 | // 需要排除的目录或者文件
29 | const excludeFileList = []
30 | // 是否写入文件,默认开启
31 | const isSaveFile = true
32 | // 是否删除未匹配到内容的标题,默认关闭
33 | const isRemoveTitle = false
34 |
35 | // 时间转换:分钟转换为 h+min/h/min,可选前后缀参数
36 | function minToTimeStr(t, bracket = '**') {
37 | // 没有值返回空字符串
38 | if (t === 0) return ''
39 |
40 | const h = Math.floor(t / 60)
41 | const m = Math.floor(t % 60)
42 | // 0 的情况返回空字符串
43 | // 不满 10 补 0
44 | // 小时不补 0(感觉不好看,不直观)
45 | const hStr = h === 0 ? '' : h + 'h'
46 | const mStr = m === 0 ? '' : String(m).padStart(2, '0') + 'min'
47 |
48 | return bracket + hStr + mStr + bracketMap[bracket]
49 | }
50 |
51 | // 时间转换:分钟转换为 00:00 形式
52 | function minToTime(time) {
53 | const h = String(Math.floor(time / 60)).padStart(2, '0')
54 | const m = String(Math.floor(time % 60)).padStart(2, '0')
55 | return h + ':' + m
56 | }
57 |
58 | ;(function () {
59 | function setup() {
60 | const args = process.argv.slice(2)
61 | const inputPath = args[0]
62 | const filePathList = []
63 |
64 | // 选择匹配模式,如果有值说明匹配到了
65 | if (modeMap[args[1]]) matchMode = modeMap[args[1]]
66 |
67 | // 异常处理
68 | if (!inputPath) {
69 | console.log('请先传入一个文件/文件夹')
70 | return
71 | } else if (!fs.existsSync(inputPath)) {
72 | console.log('没有找到这个文件/文件夹~')
73 | return
74 | }
75 |
76 | // 如果是文件直接执行
77 | if (fs.statSync(inputPath).isFile()) {
78 | run(inputPath)
79 | return
80 | }
81 |
82 | // TODO: 下面就是目录的情况了,目前没有支持递归扫描,只支持该目录第一层 md 文件
83 |
84 | // 读取所有文件名
85 | const files = fs.readdirSync(inputPath)
86 | for (let file of files) {
87 | // 过滤不是 md 的文件或者被排除的文件
88 | if (path.extname(file) !== '.md' || excludeFileList.includes(file)) continue
89 | // 合并为完整路径
90 | const filePath = path.join(inputPath, file)
91 | // 将扫描到的文件添加到文件列表(排除一些文件和目录)
92 | if (fs.statSync(filePath).isFile()) filePathList.push(filePath)
93 | }
94 |
95 | // 遍历文件列表开始执行
96 | filePathList.forEach((filePath) => {
97 | run(filePath)
98 | })
99 | }
100 |
101 | // 数据初始化
102 | function initData(isTmpMode) {
103 | // 在临时模式下默认不插入
104 | isInsertTemplate = !isTmpMode
105 | fileTotalTime = 0
106 | }
107 |
108 | // 录入数据
109 | function addData(dataList, title, insertContent, matchContent, result, statsTime = 0, options = {}) {
110 | dataList.push({
111 | // 标题
112 | title,
113 | // 插入模板需要的内容
114 | insertContent,
115 | // 替换匹配需要的内容
116 | matchContent,
117 | // 替换结果
118 | result,
119 | // 此标题下的统计时长
120 | statsTime,
121 | // 一些其他的可选参数
122 | ...options,
123 | })
124 | }
125 |
126 | // 启动
127 | function run(filePath) {
128 | // 文件内容
129 | let text = fs.readFileSync(filePath, 'utf8')
130 |
131 | if (!text) {
132 | console.log('这是一个空文件噢~')
133 | return
134 | }
135 |
136 | // 是否为临时模式
137 | const isTmpMode = matchMode === modeMap['temp']
138 | // 在处理前通过正则校验提取旧日记的总时长
139 | const oldTotalTimeList = text.match(/\n> 总时长:\*\*(\d+h)?(\d+min)?.*\*\*/) ?? []
140 | const oldTotalTime = parseInt(oldTotalTimeList[1] || '0') * 60 + parseInt(oldTotalTimeList[2] || '0')
141 | // 数据列表
142 | const dataList = []
143 |
144 | // 初始化
145 | initData(isTmpMode)
146 | // 核心处理
147 | parseFileContent(dataList, text)
148 |
149 | // 是否插入模板
150 | if (isInsertTemplate) text = insertRecordTemplate(dataList, text, insertTitle)
151 | // 根据不同的正则,替换文件中的内容
152 | if (dataList.length) text = matchContentReplace(dataList, text)
153 |
154 | // 将内容写入到『Record』中
155 | // 优化:新总时长对比旧总时长,不一致时进行写入更新
156 | if (oldTotalTime !== fileTotalTime && isSaveFile) saveFile(filePath, text)
157 | // saveFile(filePath, text)
158 |
159 | // 之总时长超过或等于 24h 一律认为已经完成,就不打印了,但是会存在最后一次超过或等于的情况
160 | // 这时候我们还是要打印的,所以两个总时长取一个较小的
161 | if (Math.min(oldTotalTime, fileTotalTime) < 24 * 60) {
162 | // 开始打印!去除 .md 的后缀名
163 | let index = 1
164 | let bracket = ''
165 | let printContent = `${path.parse(filePath).name}`
166 | // 关于睡眠数据特殊处理
167 | for (let item of dataList) {
168 | if (item.title === '睡眠') {
169 | printContent += ` 💤 ${minToTimeStr(item.statsTime, '')}`
170 | break
171 | }
172 | }
173 | // 加上总时长
174 | printContent += ` 🕛 ${isTmpMode ? minToTimeStr(fileTotalTime, '') : minToTime(fileTotalTime)}\n`
175 | // 剩余标题数据
176 | for (let item of dataList) {
177 | const { title, statsTime } = item
178 | // 不包含睡眠和总时长
179 | if (['睡眠', '总时长'].includes(title) || statsTime === 0) continue
180 | printContent += `\n${index++}. ${title} ${minToTimeStr(statsTime, bracket)}`
181 | }
182 | console.log(printContent, '\n')
183 | }
184 | }
185 |
186 | // 解析文件内容,根据匹配正则录入数据
187 | function parseFileContent(dataList, text) {
188 | // 睡眠时长
189 | addSleepTimeData(dataList, text)
190 | // 内容时长
191 | addTitleTimeData(dataList, text)
192 | // 总时长
193 | addTotalTimeData(dataList, fileTotalTime)
194 | }
195 |
196 | // 根据匹配正则添加睡眠时长数据
197 | function addSleepTimeData(dataList, text, match, sleepTitle = '睡眠') {
198 | const sleepTimeRegex = /(\d{2}):(\d{2})-(\d{2}):(\d{2})/g
199 | while ((match = sleepTimeRegex.exec(text)) !== null) {
200 | // 开始与结束时间,默认当前时间
201 | const start = new Date()
202 | const end = new Date()
203 | const matchContent = match[0]
204 | const startHour = parseInt(match[1], 10)
205 | const startMinute = parseInt(match[2], 10)
206 | const endHour = parseInt(match[3], 10)
207 | const endMinute = parseInt(match[4], 10)
208 | start.setHours(startHour, startMinute)
209 | end.setHours(endHour, endMinute)
210 | // 如果结束时间在开始时间之前,表示跨天
211 | if (end < start) {
212 | // 将结束时间调整为第二天
213 | end.setDate(end.getDate() + 1)
214 | }
215 | // 计算时间差
216 | const duration = end.getTime() - start.getTime()
217 | const statsTime = duration / 1000 / 60
218 | // 累加给文件总时长
219 | fileTotalTime += statsTime
220 | // 录入数据
221 | addData(
222 | dataList,
223 | sleepTitle,
224 | `- [x] ${sleepTitle}:${matchContent}`,
225 | matchContent + '.*',
226 | `${matchContent} 💤 ${minToTimeStr(statsTime)}`,
227 | statsTime,
228 | )
229 | }
230 | }
231 |
232 | // 根据匹配正则添加标题为主的内容数据时长
233 | function addTitleTimeData(dataList, text, match) {
234 | const contentRegex = /## (.+?)\n([\s\S]*?)(?=\n## |\n*$)/g
235 | const contentTimeRegex = /- \[x\].*\*\*(.*)\*\*/g
236 | // NOTE: 后面的 \+? 为了兼容旧笔记数据,如 1h+、25min+ 等等
237 | const timeRegex = /\*\*(\d+h)?(\d+min)?\+?\*\*/
238 |
239 | while ((match = contentRegex.exec(text)) !== null) {
240 | const title = match[1]
241 | const matchContent = match[2].trim()
242 | const matchContentList = matchContent.match(contentTimeRegex) || []
243 |
244 | // 该文件中已有插入标题,无需自动插入
245 | if (title === insertTitle) {
246 | isInsertTemplate = false
247 | continue
248 | }
249 | // 过滤不满足 custom 模式内包含的标题
250 | if (matchMode === modeMap['custom'] && !includeTitleList.includes(title)) {
251 | continue
252 | }
253 | // 没有匹配到内容的标题
254 | if (!matchContent) {
255 | // 顺便看看要不要删除
256 | isRemoveTitle && addData(dataList, title, '', `\n## ${title}\n*`, '')
257 | continue
258 | }
259 |
260 | // OK,校验都结束了,那我们下面开始匹配时间数据并计算
261 |
262 | // 插入内容
263 | let insertContent = `- [x] ${title}:`
264 | // 匹配标题
265 | let matchTitle = `${title}:.*`
266 | // 当前标题下的总时长
267 | let statsTime = 0
268 | for (let content of matchContentList) {
269 | // 每个任务的统计时长
270 | let taskMinTime = 0
271 | const matchTimeList = content.match(new RegExp(timeRegex, 'g')) || []
272 | // NOTE: 兼容单个任务内出现多个时长的情况
273 | for (let taskContent of matchTimeList) {
274 | const item = taskContent.match(timeRegex) || []
275 | const hour = parseInt(item[1]) || 0
276 | const minute = parseInt(item[2]) || 0
277 | taskMinTime += hour * 60 + minute
278 | }
279 | // 累加到标题总时长
280 | statsTime += taskMinTime
281 | }
282 | // 标题总时长累加到文件总时长上
283 | fileTotalTime += statsTime
284 | // 添加数据,后续统一处理
285 | addData(dataList, title, insertContent, matchTitle, `${title}:${minToTimeStr(statsTime)}`, statsTime, {
286 | matchContentList,
287 | })
288 | }
289 | }
290 |
291 | // 录入总时长
292 | function addTotalTimeData(dataList, totalTime, title = '总时长') {
293 | // 根据总时长给原有标题时长添加百分比信息
294 | dataList.forEach((item) => {
295 | if (item.statsTime !== 0) {
296 | item.percentage = Math.round((item.statsTime / totalTime) * 100)
297 | // NOTE: 这里百分比是四舍五入的,可能会存在总和不为 100 的情况
298 | item.result += `(${item.percentage}%)`
299 | }
300 | })
301 |
302 | addData(dataList, title, `\n> ${title}:\n`, `${title}:.*`, `${title}:${minToTimeStr(totalTime)}`, totalTime)
303 | }
304 |
305 | // 根据扫描标题动态插入格式模板
306 | function insertRecordTemplate(dataList, text, title) {
307 | let insertTemplate = `## ${title}\n\n`
308 | dataList.forEach(({ insertContent }) => {
309 | // 插入内容为空就不用插入了
310 | if (insertContent) {
311 | insertTemplate += insertContent + '\n'
312 | }
313 | })
314 | return insertTemplate + text
315 | }
316 |
317 | // 根据内容匹配正则替换数据(返回替换后的数据,不影响原数据)
318 | function matchContentReplace(dataList, text) {
319 | dataList.forEach(({ matchContent: match, result }) => {
320 | text = text.replace(new RegExp(match), result)
321 | })
322 | return text
323 | }
324 |
325 | // 保存文件内容
326 | function saveFile(filePath, text) {
327 | fs.writeFileSync(filePath, text, 'utf8')
328 | }
329 |
330 | // salute!
331 | setup()
332 | })()
333 |
--------------------------------------------------------------------------------
/3-js/diary-stats-utools.js:
--------------------------------------------------------------------------------
1 | // 首先感谢你点开了这个文件,其次我劝你别看了,这代码写的跟屎一样 🙏
2 | // 建议移步:https://github.com/fengstats/diary-duration-stats 可能会好点
3 |
4 | import fs from 'fs'
5 | import path from 'path'
6 | import clipboardy from 'clipboardy'
7 | import NP from 'number-precision'
8 |
9 | const year = '2024'
10 | const month = '01'
11 | let inputPath = `/Users/feng/codebase/private/diary/${year}/${month}月`
12 |
13 | const isRemoveTitle = false
14 | const recordTitle = 'Record'
15 | const includeTitleList = ['重要', '生活', '休闲']
16 | const excludeFileList = []
17 | const bracketMap = { '': '', '**': '**', '(': ')', '(': ')' }
18 | const typeMap = {
19 | title: 'title',
20 | quote: 'quote',
21 | money: 'money',
22 | }
23 | // 生活: '',
24 | const colorMap = {
25 | 重要: ['#3eb370', '#44c47b'],
26 | 出行: ['#3eb370', '#44c47b'],
27 | 睡眠: ['#91c5b9', '#91c5b9'],
28 | 生活: ['#4e99de', '#1f99ed'],
29 | // 休闲: ["#f09665", "#FC8D2A"],
30 | 休闲: ['#ff6b81', '#ff4757'],
31 | 其他: ['#a5b1c2', '#a5b1c2'],
32 | }
33 | const modeMap = {
34 | free: 'FREE',
35 | custom: 'CUSTOM',
36 | temp: 'TEMP',
37 | }
38 | const style = {
39 | // fontFamily: 'font-family: Input Mono Freeze',
40 | // fontFamily: 'font-family: Comic Sans MS',
41 | // fontFamily: 'font-family: Maple UI',
42 | fontFamily: '',
43 | fontWeight: 'font-weight: 700',
44 | fontSize: 'font-size: 16px',
45 | autoCenter: 'width: fit-content; margin: 0 auto;',
46 | }
47 |
48 | let matchMode = modeMap['free']
49 | let isSaveFile = true
50 | let isInsertTemplate = true
51 | // 月支出
52 | let monthSpend = 0
53 | // 月收入
54 | let monthEarn = 0
55 | // 单文件总时长
56 | let fileTotalTime = 0
57 |
58 | function generateMoneyHtml(title, money, text, emoji) {
59 | return `
60 |
61 | 这个月${text}
62 | ${money} 元了 ${emoji}
70 |
`
71 | }
72 |
73 | // 生成任务模板
74 | function generateTaskHtml(title, content = '') {
75 | return `
76 |
93 | `
94 | }
95 |
96 | // 生成单个任务 HTML 模板
97 | function generateTaskItemHtml(title, statsTime) {
98 | // ꔷ
99 | const progressHeight = `height: 18px`
100 | const progressRadius = `border-radius: 9px`
101 | const [color1, color2] = colorMap[title] || colorMap['生活']
102 | const percentage = Math.round((100 * statsTime) / fileTotalTime)
103 | // 单独处理百分比小于 10% 的进度小球大小和位置
104 | const circleBoxSize = percentage >= 10 ? 40 : 34
105 | const circleBoxTop = percentage >= 10 ? 0.88 : 0.64 // 大往上,小往下
106 | const circleTextTop = percentage >= 10 ? 0.32 : 0.06 // 大往下,小往上
107 | const titleFlex = matchMode === modeMap['temp'] ? 0.3 : 0.08
108 | const isMinPercentage = percentage >= 2
109 | return `
110 |
118 | ${title}
127 |
138 |
146 | ${
147 | isMinPercentage
148 | ? `
${percentage}%
163 | `
164 | : ''
165 | }
166 |
167 |
168 | ${minToTimeStr(statsTime, '')}
174 | `
175 | }
176 |
177 | function minToTime(time, separator = ':') {
178 | const h = String(Math.floor(time / 60)).padStart(2, '0')
179 | const m = String(Math.floor(time % 60)).padStart(2, '0')
180 | return h + separator + m
181 | }
182 |
183 | function minToTimeStr(t, bracket = '**') {
184 | if (t === 0) return ''
185 | const h = Math.floor(t / 60)
186 | const m = Math.floor(t % 60)
187 | const hStr = h === 0 ? '' : h + 'h'
188 | const mStr = m === 0 ? '' : String(m).padStart(2, '0') + 'min'
189 | return bracket + hStr + mStr + bracketMap[bracket]
190 | }
191 |
192 | function initData() {
193 | fileTotalTime = 0
194 | }
195 |
196 | function addData(dataList, type, data) {
197 | const id = dataList.length + 1
198 | const { title = '', matchRegex = '', result = '' } = data
199 | // 公有参数
200 | const item = { id, type, title, matchRegex, result }
201 | switch (type) {
202 | case typeMap['title']:
203 | const { insert = '', statsTime = 0, matchList = [] } = data
204 | item.insert = insert
205 | item.statsTime = statsTime
206 | item.matchList = matchList
207 | break
208 | case typeMap['quote']:
209 | // ...
210 | break
211 | default:
212 | break
213 | }
214 | dataList.push(item)
215 | }
216 |
217 | function addSleepTimeData(dataList, text, match, title = '睡眠') {
218 | const sleepTimeRegex = /(\d{2}):(\d{2})-(\d{2}):(\d{2})/g
219 | while ((match = sleepTimeRegex.exec(text)) !== null) {
220 | const start = new Date()
221 | const end = new Date()
222 | const matchContent = match[0]
223 | const startHour = parseInt(match[1], 10)
224 | const startMinute = parseInt(match[2], 10)
225 | const endHour = parseInt(match[3], 10)
226 | const endMinute = parseInt(match[4], 10)
227 | start.setHours(startHour, startMinute)
228 | end.setHours(endHour, endMinute)
229 | if (end < start) {
230 | end.setDate(end.getDate() + 1)
231 | }
232 | const duration = end.getTime() - start.getTime()
233 | const statsTime = duration / 1000 / 60
234 | fileTotalTime += statsTime
235 | addData(dataList, typeMap['title'], {
236 | title,
237 | insert: `- [x] ${title}:${matchContent}`,
238 | matchRegex: `${matchContent}.*`,
239 | statsTime,
240 | result: `${matchContent} 💤 ${minToTimeStr(statsTime)}`,
241 | })
242 | }
243 | }
244 |
245 | function addTitleTimeData(dataList, text, match) {
246 | const contentRegex = /## (.+?)\n([\s\S]*?)(?=\n## |\n*$)/g
247 | const contentTimeRegex = /- \[x\].*\*\*(.*)\*\*/g
248 | const timeRegex = /\*\*(\d+h)?(\d+min)?\+?\*\*/
249 |
250 | while ((match = contentRegex.exec(text)) !== null) {
251 | const title = match[1]
252 | const matchContent = match[2].trim()
253 | const matchContentList = matchContent.match(contentTimeRegex) || []
254 |
255 | if (title === recordTitle) {
256 | isInsertTemplate = false
257 | continue
258 | }
259 | if (matchMode === modeMap['custom'] && !includeTitleList.includes(title)) {
260 | continue
261 | }
262 | if (!matchContent) {
263 | isRemoveTitle &&
264 | addData(dataList, typeMap['title'], {
265 | title,
266 | matchRegex: `\n## ${title}\n*`,
267 | result: '',
268 | })
269 | continue
270 | }
271 | // 自动计算
272 | if (title === '生活') {
273 | monthSpend = NP.plus(addMoneyData(dataList, matchContent, '支出小记'), monthSpend)
274 | monthEarn = NP.plus(addMoneyData(dataList, matchContent, '收入小记'), monthEarn)
275 | addMoneyData(dataList, matchContent, '人情世故')
276 | }
277 |
278 | const insert = `- [x] ${title}:`
279 | const matchRegex = `${title}:.*`
280 | let statsTime = 0
281 | for (const content of matchContentList) {
282 | let taskMinTime = 0
283 | const matchTimeList = content.match(new RegExp(timeRegex, 'g')) || []
284 | for (const taskContent of matchTimeList) {
285 | const item = taskContent.match(timeRegex) || []
286 | const hour = parseInt(item[1]) || 0
287 | const minute = parseInt(item[2]) || 0
288 | taskMinTime += hour * 60 + minute
289 | }
290 | statsTime += taskMinTime
291 | }
292 | fileTotalTime += statsTime
293 | addData(dataList, typeMap['title'], {
294 | title,
295 | insert,
296 | matchRegex,
297 | statsTime,
298 | result: `${title}:${minToTimeStr(statsTime)}`,
299 | matchList: matchContentList,
300 | })
301 | }
302 | }
303 |
304 | function addTotalTimeData(dataList, title = '总时长') {
305 | addData(dataList, typeMap['quote'], {
306 | title,
307 | insert: `\n> ${title}:\n`,
308 | matchRegex: `${title}:.*`,
309 | result: `${title}:${minToTimeStr(fileTotalTime)}`,
310 | })
311 | }
312 |
313 | function addMoneyData(dataList, text, title) {
314 | // NOTE: \\s\\S 这里是因为字符串形式需要转移
315 | // /> 支出小记:.*\n([\s\S]*?)(?=\n{2}|$)'
316 | const regex = new RegExp(`> ${title}:.*\n([\\s\\S]*?)(?=\n{2}|$)`)
317 | const moneyRegex = /-.*((.*?) 元.*)/g
318 |
319 | let money = 0
320 | const match = regex.exec(text)
321 | if (match) {
322 | const matchContent = match[1]
323 | const moneyList = []
324 | let matchMoney
325 | while ((matchMoney = moneyRegex.exec(matchContent)) !== null) {
326 | moneyList.push(matchMoney[1])
327 | }
328 | let result = `${title}:`
329 | if (moneyList.length) {
330 | const spend = NP.plus(...moneyList)
331 | money = NP.plus(spend, money)
332 | result += `${moneyList.join('+')}(${spend} 元)`
333 | } else {
334 | result += '0 元'
335 | }
336 | addData(dataList, typeMap['money'], {
337 | title,
338 | matchRegex: `${title}:.*`,
339 | result,
340 | moneyList,
341 | })
342 | }
343 | return money
344 | }
345 |
346 | function insertRecordTemplate(dataList, text, title) {
347 | let insertTemplate = `## ${title}\n\n`
348 | for (const { insert } of dataList) {
349 | if (insert) insertTemplate += insert + '\n'
350 | }
351 | return insertTemplate + text
352 | }
353 |
354 | function matchContentReplace(dataList, text) {
355 | for (const { matchRegex, result } of dataList) {
356 | if (matchRegex === '') continue
357 | const regex = new RegExp(matchRegex)
358 | text = text.replace(regex, result)
359 | }
360 | return text
361 | }
362 |
363 | function parseFileContent(dataList, text) {
364 | addSleepTimeData(dataList, text)
365 | addTitleTimeData(dataList, text)
366 | addTotalTimeData(dataList)
367 | }
368 |
369 | function saveFile(filePath, data) {
370 | fs.writeFile(filePath, data, (err) => {
371 | if (err) {
372 | console.error('❌ 文件更新失败', err)
373 | } else {
374 | // console.log('✅ 文件更新成功')
375 | }
376 | })
377 | }
378 |
379 | function run(filePath) {
380 | let text = fs.readFileSync(filePath, 'utf8')
381 | if (!text) {
382 | generateTaskHtml('这是一个空文件嗷~')
383 | return
384 | }
385 |
386 | const oldTotalTimeList = text.match(/\n> 总时长:\*\*(\d+h)?(\d+min)?.*\*\*/) ?? []
387 | const oldTotalTime = parseInt(oldTotalTimeList[1] || '0') * 60 + parseInt(oldTotalTimeList[2] || '0')
388 | const dataList = []
389 | initData()
390 | parseFileContent(dataList, text)
391 |
392 | if (isInsertTemplate) text = insertRecordTemplate(dataList, text, recordTitle)
393 | if (dataList.length) text = matchContentReplace(dataList, text)
394 | if (oldTotalTime !== fileTotalTime && isSaveFile) saveFile(filePath, text)
395 | // 手动更新
396 | // saveFile(filePath, text)
397 |
398 | if (Math.min(oldTotalTime, fileTotalTime) < 24 * 60) {
399 | let title = path.parse(filePath).name
400 | let content = ''
401 | if (fileTotalTime === 0) {
402 | // printTip(`${title}:`)
403 | console.log(generateTaskHtml(title, '暂无时长可统计,可先添加二级标题 → 任务列表 → 尾部追加时间'))
404 | return
405 | }
406 |
407 | title += `🕛
`
408 | title += `${minToTime(fileTotalTime)}`
409 |
410 | // 临时模式将标题替换为总时长,将总时长写入到系统剪贴板中
411 | if (matchMode === modeMap['temp']) {
412 | title = `总时长:${minToTimeStr(fileTotalTime, '')}`
413 | clipboardy.write(minToTimeStr(fileTotalTime, ''))
414 | } else {
415 | clipboardy.write(minToTime(fileTotalTime))
416 | }
417 | for (const { type, title, statsTime } of dataList) {
418 | // 过滤
419 | if (type !== typeMap['title'] || title === '睡眠' || statsTime === 0) continue
420 | // 加入输出模板中
421 | content += generateTaskItemHtml(title, statsTime)
422 | }
423 |
424 | // 添加睡眠时间,注意可能有多个睡眠数据
425 | let sleepTime = 0
426 | for (const { title, statsTime } of dataList) {
427 | if (title === '睡眠') sleepTime += statsTime
428 | }
429 | if (sleepTime) {
430 | // title += ` 💤 ${minToTimeStr(sleepTime, '')}`
431 | content += generateTaskItemHtml('睡眠', sleepTime)
432 | }
433 |
434 | // 输出
435 | console.log(generateTaskHtml(title, content))
436 | }
437 | }
438 |
439 | function setup(inputPath) {
440 | // 如果有值就按照临时模式匹配
441 | const forceInputPath = process.argv.slice(2)[0]
442 | if (forceInputPath) {
443 | matchMode = modeMap['temp']
444 | inputPath = forceInputPath
445 | // 不需要插入标题和保存
446 | isInsertTemplate = false
447 | isSaveFile = false
448 | }
449 | if (!inputPath) {
450 | generateTaskHtml('请先传入一个文件/文件夹')
451 | return
452 | }
453 | if (!fs.existsSync(inputPath)) {
454 | generateTaskHtml('没有找到这个文件/文件夹~')
455 | return
456 | }
457 | if (fs.statSync(inputPath).isFile()) {
458 | run(inputPath)
459 | return
460 | }
461 |
462 | // 执行
463 | const files = fs.readdirSync(inputPath)
464 | for (const file of files) {
465 | if (path.extname(file) !== '.md' || excludeFileList.includes(file)) continue
466 | const filePath = path.join(inputPath, file)
467 | if (fs.statSync(filePath).isFile()) {
468 | run(filePath)
469 | }
470 | }
471 |
472 | console.log(generateMoneyHtml('重要', monthEarn, '赚了', '🎉'))
473 | console.log(generateMoneyHtml('生活', monthSpend, '花了', '💢'))
474 | }
475 |
476 | setup(inputPath)
477 |
--------------------------------------------------------------------------------
/2-vscode/keybindings.json:
--------------------------------------------------------------------------------
1 | [
2 | // Vim or NeoVim
3 | // 增量范围选中扩大、缩小
4 | {
5 | "key": "enter",
6 | "command": "expand_region",
7 | "when": "editorTextFocus && (vim.mode == 'Normal' || vim.mode == 'Visual') && !suggestWidgetVisible"
8 | },
9 | {
10 | "key": "backspace",
11 | "command": "undo_expand_region",
12 | "when": "editorTextFocus && editorHasSelection && vim.mode == 'Visual'"
13 | },
14 | // 在 Vim INSERT 模式下的 Ctrl+d/u 滚动半屏
15 | {
16 | "key": "ctrl+d",
17 | "command": "cursorMove",
18 | "when": "editorTextFocus && vim.mode == 'Insert'",
19 | "args": {
20 | "to": "down",
21 | "by": "line",
22 | "value": 22,
23 | "revealCursor": true
24 | }
25 | },
26 | {
27 | "key": "ctrl+u",
28 | "command": "cursorMove",
29 | "when": "editorTextFocus && vim.mode == 'Insert'",
30 | "args": {
31 | "to": "up",
32 | "by": "line",
33 | "value": 22,
34 | "revealCursor": true
35 | }
36 | },
37 | // Copilot 编辑器内联聊天
38 | {
39 | "key": "cmd+l",
40 | "command": "inlineChat.startWithCurrentLine",
41 | "when": "editorFocus && github.copilot.chat.editor.enableLineTrigger && inlineChatHasProvider && !editorReadonly && !inlineChatVisible"
42 | },
43 | // 与上面的指令效果差不多,不过是由另外的参数控制的:
44 | // editorScroll 和 halfPage
45 | // {
46 | // "key": "ctrl+d",
47 | // "when": "editorTextFocus && vim.mode == 'Insert'",
48 | // "command": "editorScroll",
49 | // "args": {
50 | // "to": "down",
51 | // "value": 1,
52 | // "by": "halfPage",
53 | // "revealCursor": true
54 | // }
55 | // },
56 |
57 | // Basic
58 | // {
59 | // "key": "cmd+l",
60 | // "command": "markdown.extension.checkTaskList",
61 | // "when": "editorTextFocus && editorLangId =~ /^markdown$|^rmd$|^quarto$/"
62 | // },
63 | // 选择最近的文件工作区
64 | {
65 | "key": "cmd+r",
66 | "command": "workbench.action.openRecent"
67 | // 只能在聚焦文件管理、编辑器、Panel 时使用
68 | // "when": "filesExplorerFocus || editorFocus || panelFocus"
69 | },
70 | // 搜索面板刷新搜索结果,需要聚焦侧边栏以及搜索面板可见
71 | {
72 | "key": "cmd+r",
73 | "command": "search.action.refreshSearchResults",
74 | "when": "sideBarFocus && searchViewletVisible"
75 | },
76 | // 清空扩展输入信息(就当我没事给自己找点事干好了,这个配置挺鸡肋的,直接 cmd+a 然后 del 就行哈哈哈哈)
77 | {
78 | "key": "cmd+k",
79 | "command": "workbench.extensions.action.clearExtensionsSearchResults",
80 | "when": "sideBarFocus"
81 | },
82 | // 搜索面板调出替换输入框的快捷键
83 | {
84 | "key": "cmd+g",
85 | "command": "workbench.action.replaceInFiles",
86 | "when": "sideBarFocus"
87 | },
88 | // 替换单个文件内的某处匹配(在搜索面板中使用,需聚焦具体匹配项)
89 | {
90 | "key": "enter",
91 | "command": "search.action.replace",
92 | "when": "matchFocus && replaceActive && searchViewletVisible"
93 | },
94 | // 切换左右 panel
95 | {
96 | "key": "cmd+[",
97 | "command": "workbench.action.previousPanelView",
98 | "when": "panelFocus"
99 | },
100 | {
101 | "key": "cmd+]",
102 | "command": "workbench.action.nextPanelView",
103 | "when": "panelFocus"
104 | },
105 | // 打开一个新窗口
106 | {
107 | "key": "cmd+ctrl+n",
108 | "command": "workbench.action.newWindow"
109 | },
110 | // 打开当前文件所在访达位置
111 | {
112 | "key": "cmd+shift+r",
113 | "command": "revealFileInOS"
114 | // "when": "!editorFocus"
115 | },
116 | // 在不同的面板(组件)之间进行聚焦
117 | {
118 | "key": "cmd+shift+h",
119 | "command": "workbench.action.navigateLeft"
120 | },
121 | {
122 | "key": "cmd+shift+l",
123 | "command": "workbench.action.navigateRight"
124 | },
125 | {
126 | "key": "cmd+shift+k",
127 | "command": "workbench.action.navigateUp"
128 | },
129 | {
130 | "key": "cmd+shift+j",
131 | "command": "workbench.action.navigateDown"
132 | },
133 | // 聚焦文件管理面板
134 | {
135 | "key": "cmd+shift+;",
136 | "command": "workbench.view.explorer",
137 | "when": "viewContainer.workbench.view.explorer.enabled"
138 | },
139 | // 聚焦全局搜索面板
140 | {
141 | "key": "cmd+shift+f",
142 | "command": "workbench.action.findInFiles"
143 | },
144 | // 聚焦 gitlens
145 | {
146 | "key": "cmd+shift+g",
147 | "command": "workbench.view.scm",
148 | "when": "workbench.scm.active"
149 | },
150 | // 断点调试
151 | {
152 | "key": "cmd+5",
153 | "command": "workbench.action.debug.start",
154 | "when": "debuggersAvailable && debugState == 'inactive'"
155 | },
156 | {
157 | "key": "cmd+5",
158 | "command": "workbench.action.debug.continue",
159 | "when": "debugState == 'stopped'"
160 | },
161 | // Run Code
162 | // {
163 | // "key": "cmd+alt+n",
164 | // "command": "code-runner.run"
165 | // },
166 | // 切换随机背景图(暂时不用了,影响写代码速度)
167 | // {
168 | // "key": "shift+cmd+7",
169 | // "command": "extension.backgroundCover.refresh"
170 | // },
171 | // 让你的 Esc 优先执行取消提示建议的操作,然后才会识别进入 normal 模式
172 | // {
173 | // "key": "escape",
174 | // "command": "hideSuggestWidget",
175 | // "when": "suggestWidgetVisible && textInputFocus"
176 | // },
177 | // VSC 调用 Vim 指令
178 | // {
179 | // "key": "cmd+shift+h",
180 | // "command": "vim.remap",
181 | // "when": "vim.mode == 'Normal'",
182 | // "args": {
183 | // "after": ["", "h"]
184 | // }
185 | // },
186 |
187 | // File
188 | // NOTE: 没什么问题(去掉了 !explorerResourceIsRoot 达到了聚焦资源管理器根目录中新建的功能,但不知道可能会有什么隐患,先观望一下)
189 | {
190 | "key": "cmd+n",
191 | "command": "explorer.newFile"
192 | },
193 | // 新建未命名文件
194 | {
195 | "key": "cmd+t",
196 | "command": "workbench.action.files.newUntitledFile"
197 | },
198 | // 在文件管理器中搜索
199 | {
200 | "key": "f",
201 | "command": "list.find",
202 | "when": "listFocus && listSupportsFind && !inputFocus"
203 | },
204 | {
205 | "key": "/",
206 | "command": "list.find",
207 | "when": "listFocus && listSupportsFind && !inputFocus"
208 | },
209 | // 新建文件/文件夹
210 | {
211 | "key": "a",
212 | "command": "explorer.newFile",
213 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceReadonly && !inputFocus"
214 | },
215 | {
216 | "key": "shift+a",
217 | "command": "explorer.newFolder",
218 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceReadonly && !inputFocus"
219 | },
220 | // 复制/剪切/粘贴
221 | {
222 | "key": "y",
223 | "command": "filesExplorer.copy",
224 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
225 | },
226 | {
227 | "key": "x",
228 | "command": "filesExplorer.cut",
229 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
230 | },
231 | {
232 | "key": "p",
233 | "command": "filesExplorer.paste",
234 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
235 | },
236 | // 重命名/删除
237 | {
238 | "key": "r",
239 | "command": "renameFile",
240 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
241 | },
242 | {
243 | "key": "d",
244 | "command": "deleteFile",
245 | "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceReadonly && !inputFocus"
246 | },
247 |
248 | // Tabs
249 | // 在当前编辑组内切换左右文件(将当前文件与左右文件换位置)
250 | {
251 | "key": "cmd+[",
252 | "command": "workbench.action.moveEditorLeftInGroup",
253 | // 解决和 panel 切换快捷键冲突的问题
254 | "when": "!panelFocus"
255 | },
256 | {
257 | "key": "cmd+]",
258 | "command": "workbench.action.moveEditorRightInGroup",
259 | "when": "!panelFocus"
260 | },
261 | // 在当前编辑组内左右聚焦文件
262 | {
263 | "key": "cmd+shift+[",
264 | "command": "workbench.action.previousEditorInGroup"
265 | },
266 | {
267 | "key": "cmd+shift+]",
268 | "command": "workbench.action.nextEditorInGroup"
269 | },
270 | // 将当前编辑组的文件移动到上一个/下一个编辑组中 | << and >>
271 | {
272 | "key": "cmd+shift+, cmd+shift+,",
273 | "command": "workbench.action.moveEditorToPreviousGroup"
274 | },
275 | {
276 | "key": "cmd+shift+. cmd+shift+.",
277 | "command": "workbench.action.moveEditorToNextGroup"
278 | },
279 |
280 | // Editor
281 | // Codeium 的 Command 面板
282 | // TODO: 找了一圈没看到怎么用键盘快捷方式 cancel 掉这个 command,ESC 直接切 Vim 的 normal 模式了
283 | // 先鼠标点掉吧……
284 | {
285 | "key": "alt+i",
286 | "command": "codeium.openCodeiumCommand",
287 | "when": "codeium.commandEnabled && editorTextFocus && !inlineSuggestionsVisible"
288 | },
289 | // 替换当前行和上/下行
290 | {
291 | "key": "alt+k",
292 | "command": "editor.action.moveLinesUpAction",
293 | "when": "editorTextFocus && !editorReadonly"
294 | },
295 | {
296 | "key": "alt+j",
297 | "command": "editor.action.moveLinesDownAction",
298 | "when": "editorTextFocus && !editorReadonly"
299 | },
300 | // 查找替换
301 | {
302 | "key": "cmd+g",
303 | "command": "editor.action.startFindReplaceAction",
304 | "when": "editorFocus"
305 | },
306 | // 向下/上寻找当前文件出现的提示提示/警告/错误
307 | {
308 | "key": "cmd+8",
309 | "command": "editor.action.marker.next",
310 | "when": "editorFocus"
311 | },
312 | {
313 | "key": "cmd+shift+8",
314 | "command": "editor.action.marker.prev",
315 | "when": "editorFocus"
316 | },
317 | // 调整编辑组区域宽度大小(缩小、放大、恢复)
318 | {
319 | "key": "cmd+shift+-",
320 | "command": "workbench.action.decreaseViewWidth"
321 | // "when": "editorTextFocus && !editorReadonly"
322 | },
323 | {
324 | "key": "cmd+shift+=",
325 | "command": "workbench.action.increaseViewWidth"
326 | },
327 | {
328 | "key": "cmd+shift+0",
329 | "command": "workbench.action.evenEditorWidths"
330 | },
331 | // 垂直分屏
332 | {
333 | "key": "cmd+shift+\\",
334 | "command": "workbench.action.splitEditorToBelowGroup"
335 | },
336 | // {
337 | // "key": "ctrl+o",
338 | // "command": "workbench.action.navigateBack"
339 | // },
340 | // {
341 | // "key": "ctrl+i",
342 | // "command": "workbench.action.navigateForward"
343 | // },
344 |
345 | // Terminal
346 | {
347 | "key": "cmd+w",
348 | "command": "workbench.action.terminal.kill",
349 | // "args": ["workbench.action.terminal.kill", "workbench.action.terminal.focus"],
350 | "when": "terminalFocus"
351 | },
352 | // 创建终端(根据当前编辑区聚焦文件的位置)
353 | {
354 | "key": "ctrl+`",
355 | "command": "openInIntegratedTerminal"
356 | // 打开外部终端:具体看 settings.json 中 osxExec 设置的
357 | // "command": "openInTerminal"
358 | },
359 | // 创建终端(水平方向)
360 | {
361 | "key": "cmd+d",
362 | "command": "workbench.action.terminal.split",
363 | "when": "terminalFocus && terminalProcessSupported || terminalFocus && terminalWebExtensionContributedProfile"
364 | },
365 | // 创建终端(垂直方向)
366 | {
367 | "key": "cmd+shift+d",
368 | "command": "workbench.action.terminal.new",
369 | "when": "terminalFocus && terminalProcessSupported || terminalWebExtensionContributedProfile"
370 | },
371 | {
372 | "key": "cmd+shift+n",
373 | "command": "workbench.action.terminal.new",
374 | "when": "terminalProcessSupported || terminalWebExtensionContributedProfile"
375 | },
376 | // 从任意地方聚焦到终端,i = iTerm
377 | {
378 | "key": "cmd+shift+i",
379 | "command": "workbench.action.terminal.focus"
380 | },
381 | // 最大化终端
382 | {
383 | "key": "cmd+shift+enter",
384 | "command": "workbench.action.toggleMaximizedPanel",
385 | "when": "terminalFocus"
386 | },
387 | // 上下拉伸终端(快捷键原本是编辑器整体放大缩小, 被我禁用了)
388 | {
389 | "key": "cmd+shift+-",
390 | "command": "workbench.action.terminal.resizePaneDown",
391 | "when": "panelFocus"
392 | // "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
393 | },
394 | {
395 | "key": "cmd+shift+=",
396 | "command": "workbench.action.terminal.resizePaneUp",
397 | "when": "panelFocus"
398 | // "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
399 | },
400 | // 左右终端聚焦
401 | {
402 | "key": "cmd+shift+h",
403 | "command": "workbench.action.terminal.focusPreviousPane",
404 | "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
405 | },
406 | {
407 | "key": "cmd+shift+l",
408 | "command": "workbench.action.terminal.focusNextPane",
409 | "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
410 | },
411 | // 可以从终端返回编辑区中而不关闭终端
412 | {
413 | "key": "cmd+shift+k",
414 | "command": "workbench.action.navigateUp",
415 | "when": "terminal.active && terminalFocus"
416 | },
417 | // TODO: 上下终端聚焦,用来覆盖 Tabs 中设置左右聚焦 tab 功能,后续再看看能不能优化
418 | {
419 | "key": "cmd+shift+[",
420 | "command": "workbench.action.terminal.focusPrevious",
421 | "when": "terminalFocus && terminalHasBeenCreated && !terminalEditorFocus || terminalFocus && terminalProcessSupported && !terminalEditorFocus"
422 | },
423 | {
424 | "key": "cmd+shift+]",
425 | "command": "workbench.action.terminal.focusNext",
426 | "when": "terminalFocus && terminalHasBeenCreated && !terminalEditorFocus || terminalFocus && terminalProcessSupported && !terminalEditorFocus"
427 | },
428 |
429 | // Setting Default
430 | {
431 | "key": "ctrl+shift+`",
432 | "command": "-workbench.action.terminal.new",
433 | "when": "terminalProcessSupported || terminalWebExtensionContributedProfile"
434 | },
435 | {
436 | "key": "alt+cmd+h",
437 | "command": "-rest-client.history"
438 | },
439 | {
440 | "key": "ctrl+f",
441 | "command": "-cursorRight",
442 | "when": "textInputFocus"
443 | },
444 | {
445 | "key": "ctrl+f",
446 | "command": "-extension.vim_ctrl+f",
447 | "when": "editorTextFocus && vim.active && vim.use && !inDebugRepl && vim.mode != 'Insert'"
448 | },
449 | {
450 | "key": "ctrl+cmd+f",
451 | "command": "-workbench.action.toggleFullScreen",
452 | "when": "!isIOS"
453 | },
454 | {
455 | "key": "ctrl+f",
456 | "command": "workbench.view.search",
457 | "when": "workbench.view.search.active && neverMatch =~ /doesNotMatch/"
458 | },
459 | {
460 | "key": "ctrl+f",
461 | "command": "workbench.action.terminal.searchWorkspace",
462 | "when": "terminalFocus && terminalProcessSupported && terminalTextSelected"
463 | },
464 |
465 | // Setting Disabled
466 | {
467 | "key": "shift+cmd+f",
468 | "command": "-workbench.view.search",
469 | "when": "workbench.view.search.active && neverMatch =~ /doesNotMatch/"
470 | },
471 | {
472 | "key": "shift+cmd+f",
473 | "command": "-workbench.action.terminal.searchWorkspace",
474 | "when": "terminalFocus && terminalProcessSupported && terminalTextSelected"
475 | },
476 | {
477 | "key": "shift+cmd+f",
478 | "command": "-workbench.action.findInFiles"
479 | },
480 | {
481 | "key": "shift+cmd+h",
482 | "command": "-workbench.action.replaceInFiles"
483 | },
484 | {
485 | "key": "ctrl+`",
486 | "command": "-workbench.action.terminal.toggleTerminal",
487 | "when": "terminal.active"
488 | },
489 | {
490 | "key": "ctrl+k",
491 | "command": "-deleteAllRight",
492 | "when": "textInputFocus && !editorReadonly"
493 | },
494 | {
495 | "key": "shift+cmd+=",
496 | "command": "-workbench.action.zoomIn"
497 | },
498 | {
499 | "key": "shift+cmd+-",
500 | "command": "-workbench.action.zoomOut"
501 | },
502 | {
503 | "key": "cmd+-",
504 | "command": "-workbench.action.zoomOut"
505 | },
506 | {
507 | "key": "cmd+=",
508 | "command": "-workbench.action.zoomIn"
509 | },
510 | {
511 | "key": "ctrl+r",
512 | "command": "-shell.runCommand"
513 | },
514 | {
515 | "key": "ctrl+o",
516 | "command": "-lineBreakInsert",
517 | "when": "textInputFocus && !editorReadonly"
518 | },
519 | {
520 | "key": "alt+cmd+f",
521 | "command": "-editor.action.startFindReplaceAction",
522 | "when": "editorFocus || editorIsOpen"
523 | },
524 | {
525 | "key": "alt+cmd+up",
526 | "command": "-extension.vim_cmd+alt+up",
527 | "when": "editorTextFocus && vim.active && !inDebugRepl"
528 | },
529 | {
530 | "key": "alt+cmd+down",
531 | "command": "-extension.vim_cmd+alt+down",
532 | "when": "editorTextFocus && vim.active && !inDebugRepl"
533 | },
534 | {
535 | "key": "cmd+n",
536 | "command": "-workbench.action.files.newUntitledFile"
537 | },
538 | {
539 | "key": "cmd+t",
540 | "command": "-workbench.action.showAllSymbols"
541 | },
542 | {
543 | "key": "ctrl+alt+n",
544 | "command": "-code-runner.run"
545 | },
546 | {
547 | "key": "ctrl+shift+f7",
548 | "command": "-extension.backgroundCover.refresh"
549 | },
550 | {
551 | "key": "cmd+l cmd+o",
552 | "command": "-fiveServer.start",
553 | "when": "editorTextFocus"
554 | },
555 | {
556 | "key": "cmd+l cmd+c",
557 | "command": "-fiveServer.close",
558 | "when": "editorTextFocus"
559 | },
560 | {
561 | "key": "cmd+5",
562 | "command": "-workbench.action.focusFifthEditorGroup"
563 | },
564 | {
565 | "key": "cmd+i",
566 | "command": "-codeium.openCodeiumCommand",
567 | "when": "codeium.commandEnabled && editorTextFocus && !inlineSuggestionsVisible"
568 | },
569 | {
570 | "key": "alt+escape",
571 | "command": "-editor.action.triggerSuggest",
572 | "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly && !suggestWidgetVisible"
573 | },
574 | {
575 | "key": "cmd+e",
576 | "command": "-editor.action.toggleScreenReaderAccessibilityMode",
577 | "when": "accessibilityHelpIsShown"
578 | },
579 | {
580 | "key": "cmd+i",
581 | "command": "-inlineChat.startWithCurrentLine",
582 | "when": "editorFocus && github.copilot.chat.editor.enableLineTrigger && inlineChatHasProvider && !editorReadonly && !inlineChatVisible"
583 | },
584 | {
585 | "key": "cmd+l",
586 | "command": "inlineChat.start",
587 | "when": "editorFocus && inlineChatHasProvider && inlineChatPossible && !editorReadonly"
588 | },
589 | {
590 | "key": "cmd+i",
591 | "command": "-inlineChat.start",
592 | "when": "editorFocus && inlineChatHasProvider && inlineChatPossible && !editorReadonly"
593 | }
594 | ]
--------------------------------------------------------------------------------
/2-vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Basic
3 | "update.mode": "default",
4 | "breadcrumbs.icons": false,
5 | "database-client.autoSync": true,
6 | "explorer.confirmDragAndDrop": false,
7 | "explorer.confirmPasteNative": false,
8 | "explorer.openEditors.visible": 20,
9 | "explorer.confirmDelete": false,
10 | "security.workspace.trust.untrustedFiles": "open",
11 | "files.eol": "\n",
12 | "files.autoSave": "off",
13 | // 是否在尾部插入一个新行
14 | "files.insertFinalNewline": true,
15 | "files.simpleDialog.enable": false,
16 | "files.associations": {
17 | ".zimrc": "shellscript",
18 | // "*.json": "jsonc",
19 | "*.conf": "plaintext"
20 | },
21 |
22 | // Search
23 | "search.smartCase": true,
24 | "search.collapseResults": "auto",
25 | "search.seedOnFocus": true,
26 | "search.showLineNumbers": true,
27 | "search.useGlobalIgnoreFiles": true,
28 | "search.useParentIgnoreFiles": true,
29 | "search.quickAccess.preserveInput": true,
30 | "search.searchEditor.defaultNumberOfContextLines": null,
31 | "search.searchEditor.singleClickBehaviour": "peekDefinition",
32 | "search.exclude": {
33 | "**/.git": true,
34 | "**/.github": true,
35 | "**/.nuxt": true,
36 | "**/.output": true,
37 | "**/.pnpm": true,
38 | "**/.vscode": true,
39 | "**/.yarn": true,
40 | "**/bower_components": true,
41 | "**/dist/**": true,
42 | "**/logs": true,
43 | "**/node_modules": true,
44 | "**/out/**": true,
45 | "**/package-lock.json": true,
46 | "**/pnpm-lock.yaml": true,
47 | "**/tmp": true,
48 | "**/yarn.lock": true
49 | },
50 |
51 | // Sundial
52 | "workbench.preferredLightColorTheme": "Default Light Modern",
53 | "workbench.preferredDarkColorTheme": "Default Dark+",
54 | "workbench.colorTheme": "Default Dark+",
55 | "sundial.sunrise": "07:00",
56 | "sundial.sunset": "17:00",
57 | "sundial.interval": 20,
58 | // "Color": "#d484818f"
59 | // "sundial.daySettings": {
60 | // "animations.CursorAnimationOptions": {
61 | // "Color": "#0000006f"
62 | // }
63 | // },
64 | // "sundial.nightSettings": {
65 | // "animations.CursorAnimationOptions": {
66 | // "Color": "#ffffff4f"
67 | // }
68 | // },
69 |
70 | // Window
71 | "window.nativeTabs": false,
72 | "window.dialogStyle": "custom",
73 | "window.newWindowDimensions": "offset",
74 | "window.zoomLevel": 1,
75 | "window.commandCenter": false,
76 | "workbench.activityBar.location": "top",
77 | "workbench.tree.indent": 10,
78 | "workbench.tree.enableStickyScroll": true,
79 | "workbench.tree.renderIndentGuides": "always",
80 | "workbench.iconTheme": "material-icon-theme",
81 | "workbench.startupEditor": "none",
82 | "workbench.productIconTheme": "icons-carbon",
83 | "workbench.list.smoothScrolling": true,
84 | "workbench.editor.pinnedTabsOnSeparateRow": true,
85 | "workbench.editor.focusRecentEditorAfterClose": false,
86 | "workbench.editor.highlightModifiedTabs": true,
87 | "workbench.editor.limit.value": 12,
88 | "workbench.editor.limit.perEditorGroup": true,
89 | "workbench.editor.limit.enabled": true,
90 | "workbench.commandPalette.experimental.suggestCommands": true,
91 | // 自动恢复上次使用过的命令
92 | // "workbench.commandPalette.preserveInput": true,
93 | // 字体像素级和次像素级平滑
94 | // "workbench.fontAliasing": "antialiased",
95 | "workbench.colorCustomizations": {
96 | // 终端提示命令
97 | "terminal.ansiBrightBlack": "#0000008f",
98 | // "editor.lineHighlightBackground": "#ffffff00",
99 | // 底部控制栏
100 | // "statusBar.background": "#0000002f",
101 | "[Maple Dark]": {
102 | "editorCursor.background": "#ffffff",
103 | "editor.selectionHighlightBackground": "#8adcf14f"
104 | },
105 | "[Default Dark+][GitHub Dark Classic]": {
106 | "terminal.ansiBlue": "#8adcf1",
107 | "terminal.ansiRed": "#ff6b81",
108 | "terminal.ansiBrightRed": "#ff7675"
109 | }
110 | },
111 |
112 | // Editor
113 | "fonted.font": "Arial",
114 | "editor.fontSize": 13,
115 | "editor.lineNumbers": "interval",
116 | "editor.lineHeight": 1.45,
117 | "editor.gotoLocation.multipleDefinitions": "goto",
118 | "editor.fontFamily": "Input Mono, monospace",
119 | // "editor.fontFamily": "Maple Mono SC NF, monospace",
120 | // "editor.fontFamily": "JetBrains Mono, monospace",
121 | // "editor.fontFamily": "Monaco, monospace",
122 | // "editor.fontFamily": "Liga SFMono Nerd Font, monospace",
123 | "editor.fontLigatures": "'ss01', 'ss02', 'ss03', 'ss06', 'ss12', 'ss13'",
124 | "editor.cursorSurroundingLines": 5,
125 | "editor.accessibilitySupport": "auto",
126 | "editor.renderLineHighlight": "all",
127 | "editor.cursorBlinking": "expand",
128 | "editor.cursorSmoothCaretAnimation": "on",
129 | // 配置选中文本时的截断分隔符
130 | // "editor.wordSeparators": "`~!@%^&*()=+[{]}\\|;:'\",.<>/?(),。;:_-",
131 | // 不好用,输入比较快的时候就抽风了
132 | "editor.linkedEditing": false,
133 | // TODO: 关闭缩进猜测
134 | "editor.detectIndentation": false,
135 | "editor.tabSize": 2,
136 | // auto close brackets
137 | "editor.autoClosingBrackets": "beforeWhitespace",
138 | "editor.autoClosingDelete": "always",
139 | "editor.autoClosingOvertype": "always",
140 | "editor.autoClosingQuotes": "beforeWhitespace",
141 | // smart suggest
142 | "editor.suggest.snippetsPreventQuickSuggestions": true,
143 | "editor.acceptSuggestionOnEnter": "smart",
144 | "editor.inlineSuggest.showToolbar": "always",
145 | "editor.hover.above": false,
146 | "editor.hover.delay": 220,
147 | "editor.hover.hidingDelay": 0,
148 | "editor.padding.top": 2,
149 | "editor.smoothScrolling": true,
150 | // TODO: 父级代码吸附置顶,显示嵌套作用域
151 | "editor.stickyScroll.enabled": false,
152 | "editor.stickyScroll.scrollWithEditor": false,
153 | "editor.scrollbar.ignoreHorizontalScrollbarInContentHeight": true,
154 | "editor.scrollbar.horizontalScrollbarSize": 6,
155 | "editor.scrollbar.verticalScrollbarSize": 24,
156 | "editor.scrollBeyondLastLine": true,
157 | "editor.find.addExtraSpaceOnTop": false,
158 | "editor.minimap.renderCharacters": false,
159 | "editor.minimap.showSlider": "always",
160 | "editor.minimap.size": "fit",
161 | "editor.minimap.maxColumn": 60,
162 | // bracket pair color
163 | "editor.guides.bracketPairs": true,
164 | "editor.bracketPairColorization.enabled": true,
165 | "editor.bracketPairColorization.independentColorPoolPerBracketType": true,
166 | "editor.quickSuggestions": {
167 | "strings": "on"
168 | },
169 | "editor.unicodeHighlight.allowedLocales": {
170 | "zh-hant": true
171 | },
172 | "editor.semanticTokenColorCustomizations": {
173 | "enabled": true
174 | },
175 | "editor.codeActionsOnSave": {
176 | "source.fixAll": "never",
177 | "source.fixAll.eslint": "explicit"
178 | },
179 | "editor.tokenColorCustomizations": {
180 | // "[Default Light Modern][Moegi Light Vitesse]": { "comments": "#95a5a6" },
181 | "[Fleet Dark Modern][Fleet Dark][Fleet Ocean][Maple Dark]": {
182 | "comments": "#a1a7a1df"
183 | },
184 | "[Default Light Modern][Moegi Light]": {
185 | "comments": "#218c74"
186 | },
187 | "[Evondev Dracula Darker Contrast]": {
188 | "comments": "#95a5a6"
189 | },
190 | "[GitHub Dark Classic][Atom One Dark]": {
191 | "comments": "#95a5a6"
192 | },
193 | "[Default Dark+]": {
194 | "comments": "#adb5ad"
195 | },
196 | "[Moegi Dark Vitesse]": {
197 | "comments": "#a1a7a1"
198 | },
199 | "[Maple Dark]": {
200 | "textMateRules": [
201 | // 重置斜体关键字
202 | {
203 | "scope": [
204 | // import/export/for/if/for/while/continue/break/switch/return
205 | "keyword.control",
206 | // function/let/const
207 | "storage.type",
208 | // async/await
209 | "storage.modifier",
210 | // this
211 | "variable.language.this"
212 | // 下面这个 scope 选择器貌似没起作用
213 | // "keyword.function"
214 | ],
215 | "settings": {
216 | "fontStyle": ""
217 | }
218 | },
219 | // 去除无效值的删除线
220 | {
221 | "scope": "invalid",
222 | "settings": {
223 | "fontStyle": ""
224 | }
225 | }
226 | ]
227 | },
228 | // 一般的斜体矫正
229 | "textMateRules": [
230 | {
231 | "name": "Comment Italics",
232 | "scope": ["comment.line.double-slash", "comment.block.documentation"],
233 | "settings": {
234 | "fontStyle": ""
235 | }
236 | }
237 | ]
238 | },
239 |
240 | // Terminal
241 | "terminal.external.osxExec": "iTerm",
242 | "terminal.integrated.gpuAcceleration": "on",
243 | "terminal.integrated.fontSize": 13,
244 | "terminal.integrated.lineHeight": 1.1,
245 | "terminal.integrated.confirmOnKill": "never",
246 | "terminal.integrated.copyOnSelection": true,
247 | "terminal.integrated.cursorBlinking": true,
248 | "terminal.integrated.fontFamily": "Maple Mono SC NF, Hack Nerd Font Mono, monospace",
249 | "terminal.integrated.tabs.defaultColor": "terminal.ansiGreen",
250 | "terminal.integrated.tabs.defaultIcon": "terminal-bash",
251 | "terminal.integrated.smoothScrolling": true,
252 | "terminal.integrated.env.osx": {
253 | "FIG_NEW_SESSION": "1",
254 | "NO_COLOR": null
255 | },
256 | // "terminal.integrated.fontFamily": "Maple Mono SC NF Freeze, JetBrains Mono, Monaco, Input Mono Freeze, Hack Nerd Font Mono, monospace",
257 |
258 | // Formatter
259 | "editor.formatOnSave": true,
260 | "prettier.semi": false,
261 | "prettier.singleQuote": true,
262 | "prettier.trailingComma": "all",
263 | "prettier.proseWrap": "preserve",
264 | "prettier.printWidth": 100,
265 | "[json]": {
266 | "editor.defaultFormatter": "vscode.json-language-features"
267 | },
268 | "[markdown][jsonc][javascript][typescript][vue][html][css][less]": {
269 | "editor.defaultFormatter": "esbenp.prettier-vscode"
270 | },
271 | "[javascriptreact][typescriptreact]": {
272 | "editor.defaultFormatter": "esbenp.prettier-vscode"
273 | },
274 | "[handlebars]": {
275 | "editor.defaultFormatter": "esbenp.prettier-vscode"
276 | },
277 | "[dotenv]": {
278 | "editor.defaultFormatter": "foxundermoon.shell-format"
279 | },
280 |
281 | // Vue
282 | "vue.inlayHints.missingProps": true,
283 | "vue.autoInsert.dotValue": true,
284 |
285 | // JS/TS 关闭验证,用 quick-lint-js 看看
286 | "typescript.validate.enable": true,
287 | "javascript.validate.enable": true,
288 |
289 | // DEBUG
290 | "debug.javascript.autoAttachFilter": "onlyWithFlag",
291 |
292 | // CSS
293 | "css.lint.duplicateProperties": "warning",
294 | "less.lint.duplicateProperties": "warning",
295 | "scss.lint.duplicateProperties": "warning",
296 | "css.lint.unknownAtRules": "ignore",
297 | "scss.lint.unknownAtRules": "ignore",
298 | "tailwindMagic.variantGroup": true,
299 |
300 | // Vim
301 | "vim.leader": "",
302 | "vim.useSystemClipboard": true,
303 | "vim.hlsearch": true,
304 | "vim.foldfix": true,
305 | "vim.easymotion": false,
306 | "vim.highlightedyank.enable": true,
307 | "vim.highlightedyank.duration": 100,
308 | "vim.highlightedyank.color": "#00000000",
309 | "vim.highlightedyank.textColor": "white",
310 | "vim.flash.enable": true,
311 | // Vimium-C
312 | // "vim.flash.labels": "sadjklewcmpgho",
313 | // mini.jump2d
314 | // "vim.flash.labels": "abcdefghijklmnopqrstuvwxyz",
315 | // hop.nvim
316 | "vim.flash.labels": "etovxqpdygfblzhckisuran",
317 | "vim.flash.marker.nextMatchBackgroundColor": "#fdff6c",
318 | "vim.flash.marker.backgroundColor": "#3eb370",
319 | "vim.operatorPendingModeKeyBindings": [
320 | { "before": ["H"], "after": ["^"] },
321 | { "before": ["L"], "after": ["g", "_"] }
322 | ],
323 | "vim.visualModeKeyBindingsNonRecursive": [
324 | // 还原原生的 f 命令
325 | // 设置 fash.nvim 查找键
326 | { "before": ["f"], "after": ["\\"] },
327 | { "before": ["s"], "after": ["f"] },
328 | { "before": ["`"], "after": ["S", "`", "e"] },
329 | { "before": ["\""], "after": ["S", "\"", "e"] },
330 | { "before": ["'"], "after": ["S", "'", "e"] },
331 | { "before": ["("], "after": ["S", ")", "e"] },
332 | { "before": ["p"], "after": ["p", "g", "v", "y"] },
333 | { "before": ["j"], "after": ["g", "j"] },
334 | { "before": ["k"], "after": ["g", "k"] },
335 | { "before": ["J"], "after": ["4", "j"] },
336 | { "before": ["K"], "after": ["4", "k"] },
337 | { "before": ["H"], "after": ["^"] },
338 | { "before": ["L"], "after": ["g", "_"] },
339 | { "before": ["g", "h"], "commands": ["editor.action.showHover"] },
340 | { "before": ["leader", "i", "w"], "after": ["V", "$", "%", "o"] },
341 | { "before": ["leader", "d", "f"], "after": ["V", "$", "%", "d"] }
342 | ],
343 | "vim.normalModeKeyBindingsNonRecursive": [
344 | // NOTE: 会覆盖原生的 Ctrl+D 命令,修复 Ctrl+D/U 在顶部代码折叠后失效 + 遇到折叠代码自动展开的问题
345 | { "before": [""], "after": ["2", "2", "g", "j", "z", "z"] },
346 | { "before": [""], "after": ["2", "2", "g", "k", "z", "z"] },
347 | // 通过 matchit 插件代替原生 % 功能,匹配范围更精确且支持匹配 html 标签
348 | { "before": ["s"], "commands": ["extension.matchitJumpItems"] },
349 | { "before": ["f"], "after": ["\\"] },
350 | { "before": [";"], "after": ["f"] },
351 | { "before": ["="], "after": [""] },
352 | { "before": ["-"], "after": [""] },
353 | { "before": ["j"], "after": ["g", "j"] },
354 | { "before": ["k"], "after": ["g", "k"] },
355 | { "before": ["J"], "after": ["4", "g", "j"] },
356 | { "before": ["K"], "after": ["4", "g", "k"] },
357 | { "before": ["H"], "after": ["^"] },
358 | { "before": ["L"], "after": ["g", "_"] },
359 | { "before": ["U"], "after": [""] },
360 | { "before": ["n"], "after": ["n", "z", "z"] },
361 | { "before": ["N"], "after": ["N", "z", "z"] },
362 | { "before": ["["], "after": ["{"] },
363 | { "before": ["]"], "after": ["}"] },
364 | // 解决按快了没
365 | { "before": ["v", "w", "i"], "after": ["v", "i", "w"] },
366 | { "before": [",", ","], "after": ["A", ",", "esc"] },
367 | { "before": ["`", "`"], "after": ["v", "i", "w", "S", "`", "e", "l"] },
368 | { "before": ["'", "'"], "after": ["v", "i", "w", "S", "'", "e", "l"] },
369 | { "before": ["\"", "\""], "after": ["v", "i", "w", "S", "\"", "e", "l"] },
370 | { "before": ["g", "r"], "commands": ["editor.action.goToReferences"] },
371 | { "before": ["z", "C"], "commands": ["editor.foldAll"] },
372 | { "before": ["z", "O"], "commands": ["editor.unfoldAll"] },
373 | { "before": ["leader", ";"], "commands": [":noh"] },
374 | { "before": ["leader", "o"], "commands": ["extension.toggleBool"] },
375 | { "before": ["leader", "l"], "commands": ["workbench.action.toggleAuxiliaryBar"] },
376 | { "before": ["leader", "e"], "commands": ["workbench.action.toggleSidebarVisibility"] },
377 | { "before": ["leader", "q"], "commands": ["workbench.action.closeActiveEditor"] },
378 | { "before": ["leader", "w"], "commands": ["workbench.action.files.saveWithoutFormatting"] },
379 | { "before": ["leader", "["], "after": ["[", "{"] },
380 | { "before": ["leader", "]"], "after": ["]", "}"] },
381 | { "before": ["leader", "r", "n"], "commands": ["editor.action.rename"] },
382 | { "before": ["leader", "i", "w"], "after": ["V", "$", "%", "o"] },
383 | { "before": ["leader", "i", "y"], "after": ["V", "$", "%", "o", "y"] },
384 | { "before": ["leader", "d", "f"], "after": ["V", "$", "%", "o", "d"] }
385 | ],
386 |
387 | // Git
388 | "git.autofetch": true,
389 | "git.confirmSync": false,
390 | "git.enableSmartCommit": true,
391 | "git.openRepositoryInParentFolders": "never",
392 | "git.ignoreRebaseWarning": true,
393 | "git.autoStash": true,
394 | "diffEditor.ignoreTrimWhitespace": false,
395 | "diffEditor.hideUnchangedRegions.enabled": true,
396 | "scm.showActionButton": false,
397 | "scm.showInputActionButton": false,
398 | "scm.diffDecorationsGutterPattern": {
399 | "modified": false
400 | },
401 |
402 | // GitLens
403 | "gitlens.plusFeatures.enabled": false,
404 | "gitlens.graph.minimap.enabled": false,
405 | "githubPullRequests.pullBranch": "never",
406 |
407 | // Markdown
408 | "markdown-preview-github-styles.colorTheme": "light",
409 | "markdown-preview-github-styles.lightTheme": "light_tritanopia",
410 | "markdown-preview-github-styles.darkTheme": "dark_dimmed",
411 |
412 | // ErrorLens
413 | "errorLens.enabledDiagnosticLevels": ["error", "warning", "info"],
414 | "errorLens.excludeBySource": ["cSpell", "Grammarly"],
415 |
416 | // LeetCode
417 | "leetcode.endpoint": "leetcode-cn",
418 | "leetcode.defaultLanguage": "typescript",
419 | "leetcode.workspaceFolder": "/Users/feng/codebase/public/leetcode",
420 | "leetcode.hint.commandShortcut": false,
421 | "leetcode.hint.commentDescription": false,
422 | "leetcode.hint.configWebviewMarkdown": false,
423 |
424 | // Comment Anchors
425 | "commentAnchors.tags.anchors": {
426 | "BUG": {
427 | "isBold": false,
428 | "iconColor": "red",
429 | "highlightColor": "#F44336",
430 | "scope": "workspace"
431 | },
432 | "TODO": {
433 | "isBold": false,
434 | "iconColor": "red",
435 | "highlightColor": "#3ea8ff",
436 | "scope": "workspace"
437 | },
438 | "FIXME": {
439 | "isBold": false,
440 | "iconColor": "red",
441 | "highlightColor": "#F44336",
442 | "scope": "workspace"
443 | },
444 | "REVIEW": {
445 | "isBold": false,
446 | "iconColor": "orange",
447 | "highlightColor": "#FFB300",
448 | "scope": "workspace"
449 | },
450 | "NOTE": {
451 | "isBold": false,
452 | "iconColor": "green",
453 | "highlightColor": "#2ecc71",
454 | "scope": "file"
455 | },
456 | "DONE": {
457 | "isBold": false,
458 | "iconColor": "green",
459 | "highlightColor": "#2ecc71",
460 | "scope": "file"
461 | }
462 | },
463 |
464 | // Code Spell Checker
465 | "cSpell.enableFiletypes": ["vimrc"],
466 | "cSpell.userWords": [
467 | "antfu",
468 | "astro",
469 | "asvetliakov",
470 | "autofetch",
471 | "axios",
472 | "Behaviour",
473 | "bilibili",
474 | "Callout",
475 | "catppuccin",
476 | "clipboardy",
477 | "Codegeex",
478 | "codeium",
479 | "cofounder",
480 | "colour",
481 | "composables",
482 | "concat",
483 | "daisyui",
484 | "douyin",
485 | "Downie",
486 | "easymotion",
487 | "esno",
488 | "Evondev",
489 | "excalidraw",
490 | "feng",
491 | "fengstats",
492 | "filesize",
493 | "Fira",
494 | "fittencode",
495 | "flvjs",
496 | "foldfix",
497 | "fonted",
498 | "fullscreen",
499 | "Gitee",
500 | "Grammarly",
501 | "highlightedyank",
502 | "hlsearch",
503 | "iconfont",
504 | "IINA",
505 | "incsearch",
506 | "Innei",
507 | "juejin",
508 | "karabiner",
509 | "Keka",
510 | "Kirbyson",
511 | "lcpr",
512 | "leetcode",
513 | "Liga",
514 | "Logi",
515 | "logto",
516 | "macwk",
517 | "matchit",
518 | "MBTI",
519 | "Moegi",
520 | "mysqld",
521 | "naiveui",
522 | "Navicat",
523 | "neovim",
524 | "nestjs",
525 | "nums",
526 | "nuxt",
527 | "nuxtjs",
528 | "nvim",
529 | "peachpuff",
530 | "picgo",
531 | "pinia",
532 | "powermode",
533 | "PTSD",
534 | "Raycast",
535 | "rgba",
536 | "Rubick",
537 | "Shanns",
538 | "Shikiji",
539 | "Snipaste",
540 | "Sonoma",
541 | "soundmark",
542 | "streamurl",
543 | "strs",
544 | "SVIP",
545 | "tabao",
546 | "tailwindcss",
547 | "Taze",
548 | "tencent",
549 | "timi",
550 | "unocss",
551 | "unplugin",
552 | "utools",
553 | "Vimium",
554 | "vimrc",
555 | "Vite",
556 | "Vitesse",
557 | "vscodevim",
558 | "vueuse",
559 | "webrtc",
560 | "wechat",
561 | "weibo",
562 | "Windi",
563 | "xattr",
564 | "yuque",
565 | "zhihu",
566 | "zimfw",
567 | "zimrc",
568 | "zmodule",
569 | "Zolplay"
570 | ],
571 |
572 | // File Nesting
573 | "explorer.fileNesting.enabled": true,
574 | "explorer.fileNesting.expand": false,
575 | "explorer.fileNesting.patterns": {
576 | "//": "Last update at 2024/12/5 19:35:26",
577 | ".clang-tidy": ".clang-format, .clangd, compile_commands.json",
578 | ".env": "*.env, .env.*, .envrc, env.d.ts",
579 | ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*",
580 | ".project": ".classpath",
581 | "+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql",
582 | "+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql",
583 | "ansible.cfg": "ansible.cfg, .ansible-lint, requirements.yml",
584 | "app.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
585 | "artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, webpack.mix.js, windi.config.*",
586 | "astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
587 | "build-wrapper.log": "build-wrapper*.log, build-wrapper-dump*.json, build-wrapper-win*.exe, build-wrapper-linux*, build-wrapper-macosx*",
588 | "BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE",
589 | "Cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml",
590 | "CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json, CMakeCache.txt",
591 | "composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml",
592 | "default.nix": "shell.nix",
593 | "deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*",
594 | "Dockerfile": "*.dockerfile, .devcontainer.*, .dockerignore, captain-definition, compose.*, docker-compose.*, dockerfile*",
595 | "flake.nix": "flake.lock",
596 | "gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
597 | "gemfile": ".ruby-version, gemfile.lock",
598 | "go.mod": ".air*, go.sum",
599 | "go.work": "go.work.sum",
600 | "hatch.toml": ".editorconfig, .flake8, .isort.cfg, .python-version, hatch.toml, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
601 | "I*.cs": "$(capture).cs",
602 | "Makefile": "*.mk",
603 | "mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock",
604 | "next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, next-i18next.config.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
605 | "nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .nuxtignore, .nuxtrc, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
606 | "package.json": "*.code-workspace, .browserslist*, .circleci*, .commitlint*, .cursorrules, .cz-config.js, .czrc, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitmojirc.json, .gitpod*, .huskyrc*, .jslint*, .knip.*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .pylintrc, .release-please*.json, .releaserc*, .ruff.toml, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, biome.json*, bower.json, build.config.*, bun.lockb, bunfig.toml, colada.options.ts, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json*, electron-builder.*, eslint*, firebase.json, grunt*, gulp*, jenkins*, knip.*, lerna*, lint-staged*, nest-cli.*, netlify*, nixpacks*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-please*.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, ruff.toml, sentry.*.config.ts, simple-git-hooks*, sonar-project.properties, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, wrangler.toml, xo.config.*, yarn*",
607 | "Pipfile": ".editorconfig, .flake8, .isort.cfg, .python-version, Pipfile, Pipfile.lock, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
608 | "pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml",
609 | "pyproject.toml": ".commitlint*, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .flake8, .flowconfig, .isort.cfg, .jslint*, .lintstagedrc*, .markdownlint*, .pdm-python, .pdm.toml, .prettier*, .pylintrc, .python-version, .ruff.toml, .stylelint*, .textlint*, .xo-config*, .yamllint*, MANIFEST.in, Pipfile, Pipfile.lock, biome.json*, commitlint*, dangerfile*, dlint.json, dprint.json*, eslint*, hatch.toml, lint-staged*, pdm.lock, phpcs.xml, poetry.lock, poetry.toml, prettier*, pyproject.toml, pyrightconfig.json, requirements*.in, requirements*.pip, requirements*.txt, ruff.toml, setup.cfg, setup.py, stylelint*, tox.ini, tslint*, uv.lock, uv.toml, xo.config.*",
610 | "quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
611 | "readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
612 | "Readme*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
613 | "README*": "AUTHORS, Authors, BACKERS*, Backers*, CHANGELOG*, CITATION*, CODEOWNERS, CODE_OF_CONDUCT*, CONTRIBUTING*, CONTRIBUTORS, COPYING*, CREDITS, Changelog*, Citation*, Code_Of_Conduct*, Codeowners, Contributing*, Contributors, Copying*, Credits, GOVERNANCE.MD, Governance.md, HISTORY.MD, History.md, LICENSE*, License*, MAINTAINERS, Maintainers, README-*, README_*, RELEASE_NOTES*, ROADMAP.MD, Readme-*, Readme_*, Release_Notes*, Roadmap.md, SECURITY.MD, SPONSORS*, Security.md, Sponsors*, authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying*, credits, governance.md, history.md, license*, maintainers, readme-*, readme_*, release_notes*, roadmap.md, security.md, sponsors*",
614 | "remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
615 | "requirements.txt": ".editorconfig, .flake8, .isort.cfg, .python-version, requirements*.in, requirements*.pip, requirements*.txt, tox.ini",
616 | "rush.json": "*.code-workspace, .browserslist*, .circleci*, .commitlint*, .cursorrules, .cz-config.js, .czrc, .dlint.json, .dprint.json*, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitmojirc.json, .gitpod*, .huskyrc*, .jslint*, .knip.*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .pylintrc, .release-please*.json, .releaserc*, .ruff.toml, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, biome.json*, bower.json, build.config.*, bun.lockb, bunfig.toml, colada.options.ts, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json*, electron-builder.*, eslint*, firebase.json, grunt*, gulp*, jenkins*, knip.*, lerna*, lint-staged*, nest-cli.*, netlify*, nixpacks*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-please*.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, ruff.toml, sentry.*.config.ts, simple-git-hooks*, sonar-project.properties, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, wrangler.toml, xo.config.*, yarn*",
617 | "sanity.config.*": "sanity.cli.*, sanity.types.ts, schema.json",
618 | "setup.cfg": ".editorconfig, .flake8, .isort.cfg, .python-version, MANIFEST.in, requirements*.in, requirements*.pip, requirements*.txt, setup.cfg, tox.ini",
619 | "setup.py": ".editorconfig, .flake8, .isort.cfg, .python-version, MANIFEST.in, requirements*.in, requirements*.pip, requirements*.txt, setup.cfg, setup.py, tox.ini",
620 | "shims.d.ts": "*.d.ts",
621 | "svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
622 | "vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
623 | "vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, capacitor.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, i18n.config.*, ionic.config.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, panda.config.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, sst.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, vuetify.config.*, webpack.config.*, windi.config.*",
624 | "*.asax": "$(capture).*.cs, $(capture).*.vb",
625 | "*.ascx": "$(capture).*.cs, $(capture).*.vb",
626 | "*.ashx": "$(capture).*.cs, $(capture).*.vb",
627 | "*.aspx": "$(capture).*.cs, $(capture).*.vb",
628 | "*.axaml": "$(capture).axaml.cs",
629 | "*.bloc.dart": "$(capture).event.dart, $(capture).state.dart",
630 | "*.c": "$(capture).h",
631 | "*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
632 | "*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs",
633 | "*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less",
634 | "*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
635 | "*.cs": "$(capture).*.cs",
636 | "*.cshtml": "$(capture).cshtml.cs",
637 | "*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
638 | "*.css": "$(capture).css.map, $(capture).*.css",
639 | "*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx, $(capture).hh",
640 | "*.dart": "$(capture).freezed.dart, $(capture).g.dart",
641 | "*.db": "*.db-shm, *.db-wal",
642 | "*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex",
643 | "*.fs": "$(capture).fs.js, $(capture).fs.js.map, $(capture).fs.jsx, $(capture).fs.ts, $(capture).fs.tsx, $(capture).fs.rs, $(capture).fs.php, $(capture).fs.dart",
644 | "*.go": "$(capture)_test.go",
645 | "*.java": "$(capture).class",
646 | "*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js, $(capture).d.ts, $(capture).js.flow",
647 | "*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx, $(capture).module.css, $(capture).less, $(capture).module.less, $(capture).module.less.d.ts, $(capture).scss, $(capture).module.scss, $(capture).module.scss.d.ts",
648 | "*.master": "$(capture).*.cs, $(capture).*.vb",
649 | "*.md": "$(capture).*",
650 | "*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs",
651 | "*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts",
652 | "*.mts": "$(capture).mts.map, $(capture).*.mts, $(capture)_*.mts",
653 | "*.pubxml": "$(capture).pubxml.user",
654 | "*.py": "$(capture).pyi",
655 | "*.razor": "$(capture).razor.cs, $(capture).razor.css, $(capture).razor.scss",
656 | "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb",
657 | "*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).bbl-SAVE-ERROR, $(capture).bcf, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).nav, $(capture).out, $(capture).run.xml, $(capture).snm, $(capture).synctex.gz, $(capture).toc, $(capture).xdv",
658 | "*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts",
659 | "*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx, $(capture).module.css, $(capture).less, $(capture).module.less, $(capture).module.less.d.ts, $(capture).scss, $(capture).module.scss, $(capture).module.scss.d.ts, $(capture).css.ts",
660 | "*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json",
661 | "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue",
662 | "*.w": "$(capture).*.w, I$(capture).w",
663 | "*.wat": "$(capture).wasm",
664 | "*.xaml": "$(capture).xaml.cs"
665 | },
666 |
667 | // Translate
668 | "commentTranslate.hover.string": true,
669 | "commentTranslate.hover.enabled": true,
670 | "commentTranslate.hover.variable": true,
671 | "commentTranslate.multiLineMerge": true,
672 | "commentTranslate.hover.content": false,
673 | "commentTranslate.maxTranslationLength": 1000,
674 | "commentTranslate.targetLanguage": "zh-CN",
675 | "commentTranslate.source": "Kaiqun.tencent-cloud-translate-tencentCloud",
676 |
677 | // Extensions
678 | "gotoAlias.closeDts": true,
679 | "fnMap.registrationCode": "flm7F9uEfVXhX8rtQpZ3kGRm9UE/Bb5Nj2t/q5msz4tQqR7WrbFDnhdtuCOUQ7DFYLSKCqh7oNqylVWdoXsiNpZo112c1KWI7U8Y+hehQmYpQbdaylIdyBbVb+gvhJ3x774vaJ7327UzyoqBlC54x+HQREYOJsdUbWKSdQ67/0sFtZL+6aumQEDJObPqQDuxQHQbT1pAjz15FnsEGADsThjgAg+toQ8TJtFx0f5cU4E+twFRpIS1O4td8OpwJDxm0OcEMfFRHsw3JzmrxxNITTRPv3lHiWr9CBMYYm0HBL61je7veCMrwDoRv9jgoTJYy1Ds7JKkqVEKK8pKe8Ez9Q==",
680 | "timeline.pageOnScroll": true,
681 | "extensions.ignoreRecommendations": true,
682 | "extensions.experimental.affinity": {
683 | "cuixiaorui.cvim": 1,
684 | "be5invis.vscode-custom-css": 2
685 | // "BrandonKirbyson.vscode-animations": 2,
686 | // "drcika.apc-extension": 2,
687 | // "vscodevim.vim": 1,
688 | // "asvetliakov.vscode-neovim": 2
689 | }
690 | }
691 |
--------------------------------------------------------------------------------