vault backup: 2025-04-10 14:02:57
This commit is contained in:
13
.obsidian/plugins/obsidian-enhancing-export-main/.editorconfig
vendored
Normal file
13
.obsidian/plugins/obsidian-enhancing-export-main/.editorconfig
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = false
|
||||
insert_final_newline = false
|
||||
max_line_length = 140
|
3
.obsidian/plugins/obsidian-enhancing-export-main/.env
vendored
Normal file
3
.obsidian/plugins/obsidian-enhancing-export-main/.env
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
# export to obsidian plugin directory directly?
|
||||
OUT_DIR="./dist"
|
1
.obsidian/plugins/obsidian-enhancing-export-main/.env.development
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/.env.development
vendored
Normal file
@ -0,0 +1 @@
|
||||
NODE_ENV=development
|
52
.obsidian/plugins/obsidian-enhancing-export-main/.eslintrc.json
vendored
Normal file
52
.obsidian/plugins/obsidian-enhancing-export-main/.eslintrc.json
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-prototype-builtins": "off",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"dist/*"
|
||||
]
|
||||
}
|
1
.obsidian/plugins/obsidian-enhancing-export-main/.gitattributes
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
20
.obsidian/plugins/obsidian-enhancing-export-main/.github/dependabot.yml
vendored
Normal file
20
.obsidian/plugins/obsidian-enhancing-export-main/.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
time: "13:00"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
time: "13:00"
|
||||
open-pull-requests-limit: 10
|
119
.obsidian/plugins/obsidian-enhancing-export-main/.github/workflows/release.yml
vendored
Normal file
119
.obsidian/plugins/obsidian-enhancing-export-main/.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,119 @@
|
||||
name: Release Obsidian plugin
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'version'
|
||||
required: true
|
||||
|
||||
env:
|
||||
PLUGIN_NAME: obsidian-enhancing-export
|
||||
|
||||
jobs:
|
||||
bump:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
- name: Create local changes
|
||||
run: |
|
||||
npm run version ${{ github.event.inputs.version }}
|
||||
- name: Commit files
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git commit -a -m "🔖 Bump version number to ${{ github.event.inputs.version }}"
|
||||
git tag -a ${{ github.event.inputs.version }} -m ""
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
tags: true
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ "bump"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version }}
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- name: Build
|
||||
id: build
|
||||
run: |
|
||||
pnpm install
|
||||
npm run build
|
||||
mkdir ${{ env.PLUGIN_NAME }}
|
||||
cp dist/* ${{ env.PLUGIN_NAME }}
|
||||
zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
|
||||
ls
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ github.event.inputs.version }}
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.version }}
|
||||
release_name: ${{ github.event.inputs.version }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Upload zip file
|
||||
id: upload-zip
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./${{ env.PLUGIN_NAME }}.zip
|
||||
asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip
|
||||
asset_content_type: application/zip
|
||||
|
||||
- name: Upload main.js
|
||||
id: upload-main
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./dist/main.js
|
||||
asset_name: main.js
|
||||
asset_content_type: text/javascript
|
||||
|
||||
- name: Upload manifest.json
|
||||
id: upload-manifest
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./dist/manifest.json
|
||||
asset_name: manifest.json
|
||||
asset_content_type: application/json
|
||||
|
||||
- name: Upload styles.css
|
||||
id: upload-css
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./dist/styles.css
|
||||
asset_name: styles.css
|
||||
asset_content_type: text/css
|
34
.obsidian/plugins/obsidian-enhancing-export-main/.github/workflows/test.yml
vendored
Normal file
34
.obsidian/plugins/obsidian-enhancing-export-main/.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- name: Install Pandoc
|
||||
run: |
|
||||
wget https://github.com/jgm/pandoc/releases/download/3.1.11.1/pandoc-3.1.11.1-1-amd64.deb
|
||||
sudo dpkg -i pandoc-3.1.11.1-1-amd64.deb
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
- name: Test
|
||||
run: npm test
|
6
.obsidian/plugins/obsidian-enhancing-export-main/.gitignore
vendored
Normal file
6
.obsidian/plugins/obsidian-enhancing-export-main/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/dist
|
||||
/node_modules
|
||||
/coverage
|
||||
/lua/main.lua
|
||||
/.env.local
|
||||
/.idea
|
1
.obsidian/plugins/obsidian-enhancing-export-main/.npmrc
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/.npmrc
vendored
Normal file
@ -0,0 +1 @@
|
||||
tag-version-prefix=""
|
8
.obsidian/plugins/obsidian-enhancing-export-main/.prettierrc
vendored
Normal file
8
.obsidian/plugins/obsidian-enhancing-export-main/.prettierrc
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
tabWidth: 2
|
||||
useTabs: false
|
||||
semi: true
|
||||
singleQuote: true
|
||||
quoteProps: preserve
|
||||
trailingComma: es5
|
||||
arrowParens: avoid
|
||||
|
2
.obsidian/plugins/obsidian-enhancing-export-main/.vscode/settings.json
vendored
Normal file
2
.obsidian/plugins/obsidian-enhancing-export-main/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
63
.obsidian/plugins/obsidian-enhancing-export-main/CONTRIBUTING.md
vendored
Normal file
63
.obsidian/plugins/obsidian-enhancing-export-main/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
# Contributing to Obsidian Enhancing Export
|
||||
|
||||
First, thank you for your willingness to contribute to this project.
|
||||
|
||||
## Simple guide
|
||||
|
||||
1. Environment Preparing
|
||||
|
||||
- Install the `nodejs`
|
||||
|
||||
[https://nodejs.org/en/download](https://nodejs.org/en/download)
|
||||
|
||||
- Install the `pnpm`
|
||||
|
||||
```shell
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
- Clone the repository
|
||||
|
||||
```shell'
|
||||
git clone https://github.com/mokeyish/obsidian-enhancing-export.git
|
||||
```
|
||||
|
||||
- Install the dependencies
|
||||
|
||||
```shell
|
||||
cd obsidian-enhancing-export
|
||||
pnpm install
|
||||
```
|
||||
|
||||
2. Development & debugging (Recommend [VsCode](https://code.visualstudio.com/))
|
||||
|
||||
- Add `.env.local` to project root with following content
|
||||
|
||||
```shell
|
||||
# export to obsidian plugin directory directly
|
||||
OUT_DIR="path/to/.obsidian/plugins/obsidian-enhancing-export"
|
||||
```
|
||||
|
||||
- Enable `dev-mode `
|
||||
|
||||
To enable dev-mode in the obsidian, use the shortcut `Ctrl+Shift+I` or the `<F12>` key to open DevTools. and run following commands in the Console Tab of DevTools.
|
||||
|
||||
```shell
|
||||
localStorage.setItem('debug-plugin', '1')
|
||||
```
|
||||
|
||||
- Build the code for debugging
|
||||
|
||||
```shell
|
||||
npm run dev
|
||||
```
|
||||
|
||||
More debug tips please see: [How to debug TypeScript in Chrome](https://blog.logrocket.com/how-to-debug-typescript-chrome/)
|
||||
|
||||
3. Building for Production
|
||||
|
||||
```shell
|
||||
npm run build
|
||||
```
|
||||
|
||||
4. Other commands please see `sciprts` of `package.json` in the project root.
|
21
.obsidian/plugins/obsidian-enhancing-export-main/LICENSE
vendored
Normal file
21
.obsidian/plugins/obsidian-enhancing-export-main/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 YISH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
67
.obsidian/plugins/obsidian-enhancing-export-main/README.md
vendored
Normal file
67
.obsidian/plugins/obsidian-enhancing-export-main/README.md
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
# Obsidian Enhancing Export Plugin
|
||||
|
||||

|
||||

|
||||
|
||||
English | [中文](https://github.com/mokeyish/obsidian-enhancing-export/blob/master/README_zh-CN.md)
|
||||
|
||||
This is an enhancing export plugin base on `Pandoc` for Obsidian ([https://obsidian.md/](https://obsidian.md/)). It's allow you to export to formats like `Markdown`,`Markdown (Hugo)`,`HTML`,`docx`,`Latex` etc.
|
||||
|
||||
Where `Markdown`,`Markdown (Hugo)`,`HTML` will export and its media resource together.
|
||||
|
||||
**Note:** `Markdown`,`Markdown (Hugo)`,`HTML` are tested in Mac OS, Windows, and Linux as I used it for myself, others are not tested well.
|
||||
|
||||
|
||||
**Ads**: You might like my other plugins 🤪
|
||||
- [Obsidian Code Emitter](https://github.com/mokeyish/obsidian-code-emitter)
|
||||
|
||||
|
||||
## Screen shot
|
||||
|
||||
- Export view,click on `Export to...` on file menu.
|
||||
|
||||

|
||||
- Setting view
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
1. First install the latest `pandoc` (3.1.9+), and then add `pandoc` path to environment variable `PATH` or set absolute path of `pandoc` in the plugin setting view.
|
||||
|
||||
See more details in [https://pandoc.org/installing.html](https://pandoc.org/installing.html)。
|
||||
|
||||
2. Search `obsidian-enhancing-export` in the community plugins of obsidian, and install it.
|
||||
|
||||
## Customize export commands
|
||||
|
||||
You can customize your export command by yourself, click `add` in the plugin setting view and then choose template `custom` to add new custom configuration.
|
||||
|
||||
## Variables
|
||||
|
||||
You can use `${variables}` in custom export command, their values are:
|
||||
|
||||
| Key | Value |
|
||||
| ------------------------- | ------------------------------------------------------------ |
|
||||
| `${outputPath}` | Output file path after export. For example, if your export to location `/User/aaa/Documents/test.pdf`, then `${outputDir}` will be replace that path. |
|
||||
| `${outputDir}` | Output directory of saved exported file,It will be `/User/aaa/Documents` in above case. |
|
||||
| `${outputFileName}` | File name (without extension) of the saved exported file. It will be `test` in above case. |
|
||||
| `${outputFileFullName}` | File name (with extension) of the saved exported file. It will be `test.pdf` in above case. |
|
||||
| `${currentPath}` | Path of currently edited file. For example, if your are editing `/User/aaa/Documents/readme.md`, the the value will be `/User/aaa/Documents/readme.md`. |
|
||||
| `${currentDir}` | Current directory of currently edited file, It will be`/User/aaa/Documents` in above case. |
|
||||
| `${currentFileName}` | Filename without extension of currently edited file, It will be `readme` in above case. |
|
||||
| `${currentFileFullName}` | Filename with extension of currently edited file. It will be `readme.md` in above case. |
|
||||
| `${vaultDir}` | The obsidian current vaultDir. |
|
||||
| `${attachmentFolderPath}` | The `attachmentFolderPath` of Obsidian. |
|
||||
| Others variables | You can use `keyword: value` in [YAML Front Matter](https://jekyllrb.com/docs/front-matter/), then use `${metadata.keyword}` |
|
||||
|
||||
## Related resources
|
||||
|
||||
- **Tutorial**: [Obsidian Tutorial for Academic Writing](https://betterhumans.pub/obsidian-tutorial-for-academic-writing-87b038060522) - tutorial on how to setup this plugin and use it for academic writing (export to `.docx`, `.pdf`, `.tex`, `.bib`)
|
||||
- **A collection of lua filters for pandoc**: [https://github.com/pandoc-ext](https://github.com/pandoc-ext) - Filters and other goodies to get the most out of pandoc, the universal document converter.
|
||||
- **Math latex editor**: [https://math.yish.org/](https://math.yish.org/)
|
||||
|
||||
## Finally
|
||||
|
||||
- Welcome to provide more command templates to [here](src/export_templates.ts).
|
||||
- Feel free to file an issue for any questions.
|
52
.obsidian/plugins/obsidian-enhancing-export-main/README_zh-CN.md
vendored
Normal file
52
.obsidian/plugins/obsidian-enhancing-export-main/README_zh-CN.md
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
# Obsidian Enhancing Export Plugin
|
||||
|
||||
[English](https://github.com/mokeyish/obsidian-enhancing-export/blob/master/README.md) | 中文
|
||||
|
||||
这是一个基于 Pandoc 的 Obsidian 加强版导出插件。提供了基本的导出格式:Markdown 、Markdown(Hugo [https://gohugo.io/](https://gohugo.io/))、Html、docx、Latex等。
|
||||
其中 Markdown 、Markdown(Hugo)、Html 会把媒体资源一并导出。
|
||||
|
||||
**注意:** 目前自用的就是 Markdown 、Markdown(Hugo)、Html,在 Mac OS、Windows、Linux 可正常使用,其他未经严格测试。
|
||||
|
||||
## 界面截图
|
||||
- 导出界面,在文件菜单上点击 `导出为......`
|
||||
|
||||

|
||||
- 设置界面
|
||||
|
||||

|
||||
|
||||
## 安装
|
||||
1. 需要先安装最新的 `pandoc`(3.1.9+),最好配置到 PATH 环境变量,或者设置界面指定路径。
|
||||
参考地址:[https://pandoc.org/installing.html](https://pandoc.org/installing.html)
|
||||
2. 在 Obsidian 插件市场,搜索 `obsidian-enhancing-export` 进行安装。
|
||||
|
||||
## 自定义命令
|
||||
|
||||
本插件是支持自定义导出命令的,在设置界面,点击添加按钮,选择 `Custom` 作为模板,即可新增一个自定义导出的配置了。
|
||||
|
||||
### 变量
|
||||
你可以使用 `${variable}` 在自定义导出的命令中。它们的值是:
|
||||
|
||||
| 变量名 | 值 |
|
||||
| -- | -- |
|
||||
| `${outputPath}` |导出路径,例如,你的导出位置是:`/User/aaa/Documents/test.pdf` ,则 `${outputDir}` 会替换为那个路径。|
|
||||
| `${outputDir}` | 导出目录,按上面的例子,它会被替换为 `/User/aaa/Documents`。 |
|
||||
| `${outputFileName}` | 没有扩展名的文件名,按上面的例子,它会被替换为 `test`。 |
|
||||
| `${outputFileFullName}` | 文件的全名,按上面的例子,它会被替换为 `test.pdf`。 |
|
||||
| `${currentPath}` | 当前文件路径,例如当前的文件位置是 `/User/aaa/Documents/readme.md`,那么它会被替换为这个文件的位置。 |
|
||||
| `${currentDir}` | 当前文件所在目录,按上面的例子,值为 `/User/aaa/Documents`。 |
|
||||
| `${currentFileName}` | 当前文件不带扩展名的名字,值是 `readme` |
|
||||
| `${currentFileFullName}` | 当前文件全名,值是 `readme.md`。 |
|
||||
| `${vaultDir}` | Obsidian 当前的 vaultDir. |
|
||||
| `${attachmentFolderPath}`| Obsidian 的附件目录 |
|
||||
| 其他变量 | 你可以在 [YAML Front Matter](https://jekyllrb.com/docs/front-matter/) 中定义 `keyword: value` 变量,然后以 `${metadata.keyword}`引用它。 |
|
||||
|
||||
## Related resources
|
||||
|
||||
- **Pandoc 的 lua filters 集合**: [https://github.com/pandoc-ext](https://github.com/pandoc-ext)
|
||||
- **Latex 数学公式编辑器**: [https://math.yish.org/](https://math.yish.org/)
|
||||
|
||||
## 最后
|
||||
|
||||
- 欢迎提供更多命令模板到[这里](src/export_templates.ts).。
|
||||
- 有问题可以提交 Issue 给我。
|
5
.obsidian/plugins/obsidian-enhancing-export-main/jest.config.cjs
vendored
Normal file
5
.obsidian/plugins/obsidian-enhancing-export-main/jest.config.cjs
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node'
|
||||
};
|
6
.obsidian/plugins/obsidian-enhancing-export-main/lua/citefilter.lua
vendored
Normal file
6
.obsidian/plugins/obsidian-enhancing-export-main/lua/citefilter.lua
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
-- credits to tarleb — StackExchange: https://tex.stackexchange.com/questions/392070/pandoc-markdown-create-self-contained-bib-file-from-cited-references
|
||||
function Pandoc(d)
|
||||
d.meta.references = pandoc.utils.references(d)
|
||||
d.meta.bibliography = nil
|
||||
return d
|
||||
end
|
5
.obsidian/plugins/obsidian-enhancing-export-main/lua/markdown+hugo.lua
vendored
Normal file
5
.obsidian/plugins/obsidian-enhancing-export-main/lua/markdown+hugo.lua
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package.path=package.path..";" ..debug.getinfo(1).source:match("(.*[/\\])"):sub(2) .. "?.lua"
|
||||
|
||||
Mode='hugo'
|
||||
|
||||
require('markdown')
|
237
.obsidian/plugins/obsidian-enhancing-export-main/lua/markdown.lua
vendored
Normal file
237
.obsidian/plugins/obsidian-enhancing-export-main/lua/markdown.lua
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
package.path=debug.getinfo(1).source:gsub('@',''):sub(0):match('(.*[/\\])'):sub(0) .. '?.lua' .. ';' .. package.path
|
||||
|
||||
require("polyfill")
|
||||
local url = require('url')
|
||||
|
||||
local pandoc=pandoc
|
||||
local PANDOC_STATE=PANDOC_STATE
|
||||
|
||||
PANDOC_VERSION:must_be_at_least '3.1.7'
|
||||
|
||||
os.text = pandoc.text
|
||||
|
||||
local PATH = pandoc.path
|
||||
local doc_dir = nil
|
||||
local media_dir = nil
|
||||
|
||||
if Mode == nil then
|
||||
Mode = 'default'
|
||||
end
|
||||
|
||||
-- print("Mode: "..Mode)
|
||||
|
||||
if PANDOC_STATE.output_file then
|
||||
local output_file = PANDOC_STATE.output_file
|
||||
doc_dir = PATH.directory(output_file)
|
||||
if PANDOC_WRITER_OPTIONS.variables["media_dir"] then
|
||||
media_dir = tostring(PANDOC_WRITER_OPTIONS.variables["media_dir"])
|
||||
else
|
||||
media_dir = PATH.split_extension(output_file)
|
||||
if Mode ~= 'hugo' then
|
||||
media_dir = media_dir .. '-media'
|
||||
end
|
||||
end
|
||||
end
|
||||
assert(doc_dir, "doc_dir is nil")
|
||||
assert(media_dir, "media_dir is nil")
|
||||
|
||||
|
||||
local function get_absolute_path(file_path)
|
||||
if PATH.is_absolute(file_path) then
|
||||
return file_path
|
||||
end
|
||||
for _, dir in pairs(PANDOC_STATE.resource_path) do
|
||||
local full_path = PATH.join({dir, file_path})
|
||||
if os.exists(full_path) then
|
||||
return full_path
|
||||
end
|
||||
end
|
||||
for _, file in pairs(PANDOC_STATE.input_files) do
|
||||
if not PATH.is_absolute(file) then
|
||||
file = PATH.join({pandoc.system.get_working_directory(), file_path})
|
||||
end
|
||||
local dir = PATH.directory(file)
|
||||
local full_path = PATH.join({dir, file_path})
|
||||
if os.exists(full_path) then
|
||||
return full_path
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_output_file(file_path)
|
||||
if media_dir then
|
||||
local new_file_name = pandoc.utils.sha1(file_path)
|
||||
local _, new_file_ext = PATH.split_extension(file_path)
|
||||
file_path = new_file_name .. new_file_ext
|
||||
local full_path = PATH.join({media_dir, file_path})
|
||||
return full_path
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function extract_media(file_path)
|
||||
os.mkdir(media_dir)
|
||||
file_path = url.decode(file_path)
|
||||
local abs_path = get_absolute_path(file_path)
|
||||
local file = get_output_file(file_path)
|
||||
if abs_path and file then
|
||||
if not os.exists(file) then
|
||||
os.copy(abs_path, file)
|
||||
end
|
||||
local rel_path = PATH.make_relative(file, doc_dir, false)
|
||||
local parts = PATH.split(rel_path)
|
||||
for i,v in ipairs(parts) do
|
||||
parts[i] = url.encode(v)
|
||||
end
|
||||
local encoded_rel_path = table.concat(parts, "/")
|
||||
if Mode == 'hugo' then
|
||||
encoded_rel_path = '../' .. encoded_rel_path
|
||||
end
|
||||
return encoded_rel_path
|
||||
end
|
||||
end
|
||||
|
||||
local function raw(s)
|
||||
return pandoc.RawInline('markdown', s)
|
||||
end
|
||||
|
||||
function Image(el)
|
||||
local src = extract_media(el.src)
|
||||
if src then
|
||||
el.src = src
|
||||
end
|
||||
return el
|
||||
end
|
||||
|
||||
function Space()
|
||||
return raw(' ')
|
||||
end
|
||||
|
||||
function SoftBreak()
|
||||
return raw('\n')
|
||||
end
|
||||
|
||||
function RawInline(el)
|
||||
if el.format == "html" then
|
||||
el.format = 'markdown'
|
||||
el.text = string.gsub(el.text, '<img[^>]+>', function(img)
|
||||
return string.gsub(img, 'src="([^"]+)"', function(url)
|
||||
if string.find(url, '^[Hh][Tt][Tt][Pp][Ss]?://') == nil then
|
||||
local extract_media_url = extract_media(url)
|
||||
if extract_media_url then
|
||||
return 'src="' .. extract_media_url .. '"'
|
||||
end
|
||||
return '123'
|
||||
end
|
||||
return 'src="' .. url .. '"'
|
||||
end)
|
||||
end)
|
||||
end
|
||||
return el
|
||||
end
|
||||
|
||||
function RawBlock(el)
|
||||
if el.format == "html" then
|
||||
el.format = 'markdown'
|
||||
end
|
||||
return el
|
||||
end
|
||||
|
||||
function Math(el)
|
||||
if Mode == 'hugo' then
|
||||
if el.mathtype == 'DisplayMath' then
|
||||
return raw('{{< mathjax >}}\n$$' .. el.text .. '$$\n{{</mathjax >}}')
|
||||
else
|
||||
el.text = string.gsub(el.text, '\\[\\{\\}]', function (v)
|
||||
return '\\' .. v
|
||||
end)
|
||||
el.text = string.gsub(el.text, '_', function (v)
|
||||
return '\\' .. v
|
||||
end)
|
||||
end
|
||||
end
|
||||
return el
|
||||
end
|
||||
|
||||
local function headerLink(input)
|
||||
-- github style section link
|
||||
return "#"..input:gsub(' ', '-')
|
||||
end
|
||||
|
||||
|
||||
local function insertLink(content, linkDescription)
|
||||
local descriptionText = table.concat(linkDescription, "")
|
||||
|
||||
if string.find(descriptionText, '|') then
|
||||
local target, desc = descriptionText:match("(.*)|(.*)")
|
||||
table.insert(content, pandoc.Link(desc, headerLink(target)))
|
||||
else
|
||||
table.insert(content, pandoc.Link(descriptionText, headerLink(descriptionText)))
|
||||
end
|
||||
end
|
||||
|
||||
function Para(el)
|
||||
local content = el.content
|
||||
content = ProcessMath(content)
|
||||
content = ProcessInternalLinks(content)
|
||||
el.content = content
|
||||
return el
|
||||
end
|
||||
|
||||
function ProcessMath(elements)
|
||||
local content = {}
|
||||
local in_display_math = false
|
||||
for _, item in pairs(elements) do
|
||||
if item.t == 'Str'and item.text == "$$" then
|
||||
in_display_math = not in_display_math
|
||||
else
|
||||
if in_display_math then
|
||||
if item.t == 'RawInline' and item.format == 'tex' then
|
||||
local n = pandoc.Math('DisplayMath', '\n' .. item.text .. '\n')
|
||||
table.insert(content, Math(n))
|
||||
else
|
||||
table.insert(content, item)
|
||||
end
|
||||
else
|
||||
table.insert(content, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
return content
|
||||
end
|
||||
|
||||
function ProcessInternalLinks(elements)
|
||||
local content = {}
|
||||
local in_section_link = false
|
||||
local linkDescription = {}
|
||||
|
||||
for _, item in pairs(elements) do
|
||||
if item.t == 'Str' and string.starts_with(item.text, '[[#') then
|
||||
in_section_link = true
|
||||
table.insert(linkDescription, string.sub(item.text, 4))
|
||||
elseif in_section_link then
|
||||
if string.ends_with(item.text, ']]') then
|
||||
table.insert(linkDescription, string.sub(item.text, 1, -3))
|
||||
insertLink(content, linkDescription)
|
||||
in_section_link = false
|
||||
linkDescription = {}
|
||||
else
|
||||
table.insert(linkDescription, item.text)
|
||||
end
|
||||
else
|
||||
table.insert(content, item)
|
||||
end
|
||||
end
|
||||
return content
|
||||
end
|
||||
|
||||
function Plain(el)
|
||||
el.content = ProcessInternalLinks(el.content)
|
||||
return el
|
||||
end
|
||||
|
||||
function Pandoc(el)
|
||||
return el
|
||||
end
|
68
.obsidian/plugins/obsidian-enhancing-export-main/lua/math_block.lua
vendored
Normal file
68
.obsidian/plugins/obsidian-enhancing-export-main/lua/math_block.lua
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
traverse = 'topdown'
|
||||
|
||||
math_block_text = nil
|
||||
function process(el)
|
||||
|
||||
-- MathBlock start or end
|
||||
if el.t == 'Str' and el.text == '$$' then
|
||||
if math_block_text == nil then -- start
|
||||
math_block_text = ''
|
||||
else -- end
|
||||
local math_block = pandoc.Math('DisplayMath', '\n' .. math_block_text .. '\n')
|
||||
math_block_text = nil
|
||||
return math_block
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
if math_block_text then
|
||||
if (el.t == 'RawInline' or el.t == 'RawBlock') and el.format == 'tex' then
|
||||
math_block_text = math_block_text .. el.text
|
||||
return {}
|
||||
elseif el.t == 'Str' then
|
||||
math_block_text = math_block_text .. el.text
|
||||
return {}
|
||||
elseif el.t == 'SoftBreak' or el.t == 'BulletList' then
|
||||
return {}
|
||||
end
|
||||
end
|
||||
return el
|
||||
end
|
||||
|
||||
function RawInline(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function RawBlock(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function Str(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function SoftBreak(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function Header(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function Para(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function Plain(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
function BulletList(el)
|
||||
return process(el)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
12
.obsidian/plugins/obsidian-enhancing-export-main/lua/pdf.lua
vendored
Normal file
12
.obsidian/plugins/obsidian-enhancing-export-main/lua/pdf.lua
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
return {
|
||||
{
|
||||
Math = function (elem)
|
||||
if elem.text:find("^%s*\\begin{") ~= nil then
|
||||
return pandoc.RawInline('tex', elem.text)
|
||||
else
|
||||
return elem
|
||||
end
|
||||
end,
|
||||
}
|
||||
}
|
61
.obsidian/plugins/obsidian-enhancing-export-main/lua/polyfill.lua
vendored
Normal file
61
.obsidian/plugins/obsidian-enhancing-export-main/lua/polyfill.lua
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
os.platform = nil
|
||||
if os.platform == nil then
|
||||
local libExt = package.cpath:match("%p[\\|/]?\\.%p(%a+)")
|
||||
if libExt == 'dll' then
|
||||
os.platform = "Windows"
|
||||
elseif libExt == 'so' then
|
||||
os.platform = "Linux"
|
||||
elseif libExt == 'dylib' then
|
||||
os.platform = "MacOS"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
os.copy = function(src, dest)
|
||||
if os.platform == "Windows" then
|
||||
src = string.gsub(src, "/", "\\")
|
||||
src = os.text.toencoding(src)
|
||||
dest = os.text.toencoding(dest)
|
||||
os.execute('copy "' .. src .. '" "' .. dest .. '" >NUL')
|
||||
else
|
||||
os.execute('cp "' .. src .. '" "' .. dest .. '"')
|
||||
end
|
||||
end
|
||||
|
||||
os.mkdir = function(dir)
|
||||
if os.exists(dir) then
|
||||
return
|
||||
end
|
||||
if os.platform == "Windows" then
|
||||
dir = os.text.toencoding(dir)
|
||||
os.execute('mkdir "' .. dir .. '"')
|
||||
else
|
||||
os.execute('mkdir -p "' .. dir .. '"')
|
||||
end
|
||||
end
|
||||
|
||||
os.exists = function(path)
|
||||
if os.platform == "Windows" then
|
||||
path = string.gsub(path, "/", "\\")
|
||||
path = os.text.toencoding(path)
|
||||
local _, _, code = os.execute('if exist "' .. path .. '" (exit 0) else (exit 1)')
|
||||
return code == 0
|
||||
else
|
||||
local _, _, code = os.execute('test -e "' .. path .. '"')
|
||||
return code == 0
|
||||
end
|
||||
end
|
||||
|
||||
string.starts_with = function(str, start)
|
||||
return str:sub(1, #start) == start
|
||||
end
|
||||
|
||||
string.ends_with = function(str, ending)
|
||||
return ending == "" or str:sub(-#ending) == ending
|
||||
end
|
||||
|
||||
|
||||
return {
|
||||
os = os,
|
||||
string = string
|
||||
}
|
18
.obsidian/plugins/obsidian-enhancing-export-main/lua/url.lua
vendored
Normal file
18
.obsidian/plugins/obsidian-enhancing-export-main/lua/url.lua
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
local function encode (str)
|
||||
str = string.gsub (str, "([^0-9a-zA-Z !'()*._~-])", -- locale independent
|
||||
function (c) return string.format ("%%%02X", string.byte(c)) end)
|
||||
str = string.gsub (str, " ", "%%20")
|
||||
return str
|
||||
end
|
||||
|
||||
|
||||
local function decode (str)
|
||||
str = string.gsub (str, "%%20", " ")
|
||||
str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end)
|
||||
return str
|
||||
end
|
||||
|
||||
return {
|
||||
encode = encode,
|
||||
decode = decode
|
||||
}
|
1278
.obsidian/plugins/obsidian-enhancing-export-main/lua/utf8_filenames.lua.bak
vendored
Normal file
1278
.obsidian/plugins/obsidian-enhancing-export-main/lua/utf8_filenames.lua.bak
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
.obsidian/plugins/obsidian-enhancing-export-main/manifest.json
vendored
Normal file
10
.obsidian/plugins/obsidian-enhancing-export-main/manifest.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "obsidian-enhancing-export",
|
||||
"name": "Enhancing Export",
|
||||
"version": "1.10.7",
|
||||
"minAppVersion": "1.6.3",
|
||||
"description": "This is a enhancing export plugin for Obsidian. It allows to export to formats like Html, DOCX, ePub and PDF or Markdown(Hugo) etc.",
|
||||
"author": "YISH",
|
||||
"authorUrl": "https://github.com/mokeyish",
|
||||
"isDesktopOnly": true
|
||||
}
|
46
.obsidian/plugins/obsidian-enhancing-export-main/package.json
vendored
Normal file
46
.obsidian/plugins/obsidian-enhancing-export-main/package.json
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "obsidian-enhancing-export",
|
||||
"version": "1.10.7",
|
||||
"description": "This is a enhancing export plugin for Obsidian. It allows to export to formats like Html, DOCX, ePub and PDF or Markdown(Hugo) etc.",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"dev": "vite build -w -m development",
|
||||
"build": "vite build",
|
||||
"version": "node version-bump.mjs",
|
||||
"lint": "eslint --ext .ts,.js src",
|
||||
"lint-fix": "eslint --fix --ext .ts,.js src",
|
||||
"format-check": "prettier --check \"src/**/*.ts\"",
|
||||
"format-fix": "prettier --write \"src/**/*.ts\"",
|
||||
"test": "jest"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "YISH",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/mokeyish/obsidian-enhancing-export",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/node": "^20.14.8",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@types/yargs-parser": "^21.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.7",
|
||||
"@typescript-eslint/parser": "^5.59.7",
|
||||
"builtin-modules": "^3.3.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.41.0",
|
||||
"jest": "^29.5.0",
|
||||
"obsidian": "latest",
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
"tslib": "2.6.3",
|
||||
"typescript": "5.0.4",
|
||||
"vite": "^5.2.13",
|
||||
"vite-plugin-solid": "^2.10.2",
|
||||
"vite-plugin-static-copy": "^1.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": "^7.5.1",
|
||||
"solid-js": "^1.8.20",
|
||||
"yargs-parser": "^21.1.1"
|
||||
}
|
||||
}
|
4201
.obsidian/plugins/obsidian-enhancing-export-main/pnpm-lock.yaml
generated
vendored
Normal file
4201
.obsidian/plugins/obsidian-enhancing-export-main/pnpm-lock.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/exportview_en-US.png
vendored
Normal file
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/exportview_en-US.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/exportview_zh-CN.png
vendored
Normal file
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/exportview_zh-CN.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/settingview_en-US.png
vendored
Normal file
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/settingview_en-US.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/settingview_zh-CN.png
vendored
Normal file
BIN
.obsidian/plugins/obsidian-enhancing-export-main/screenshot/settingview_zh-CN.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
141
.obsidian/plugins/obsidian-enhancing-export-main/src/export_templates.ts
vendored
Normal file
141
.obsidian/plugins/obsidian-enhancing-export-main/src/export_templates.ts
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
import type { ExportSetting } from './settings';
|
||||
|
||||
/*
|
||||
* Variables
|
||||
* - ${attachmentFolderPath} --> obsidian' settings.
|
||||
*
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${outputDir} --> /User/aaa/Documents/
|
||||
* - ${outputPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${outputFileName} --> test
|
||||
* - ${outputFileFullName} --> test.pdf
|
||||
*
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${currentDir} --> /User/aaa/Documents/
|
||||
* - ${currentPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${currentFileName} --> test
|
||||
* - ${CurrentFileFullName} --> test.pdf
|
||||
*/
|
||||
|
||||
export default {
|
||||
'Markdown': {
|
||||
name: 'Markdown',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/markdown.lua" -s -o "${outputPath}" -t commonmark_x-attributes',
|
||||
extension: '.md',
|
||||
},
|
||||
'Markdown (Hugo)': {
|
||||
name: 'Markdown (Hugo)',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/markdown+hugo.lua" -s -o "${outputPath}" -t commonmark_x-attributes',
|
||||
extension: '.md',
|
||||
},
|
||||
'Html': {
|
||||
name: 'Html',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/math_block.lua" --embed-resources --standalone --metadata title="${currentFileName}" -s -o "${outputPath}" -t html',
|
||||
customArguments: '--mathjax="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg-full.js"',
|
||||
extension: '.html',
|
||||
},
|
||||
'TextBundle': {
|
||||
name: 'TextBundle',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/markdown.lua" -V media_dir="${outputDir}/${outputFileName}.textbundle/assets" -s -o "${outputDir}/${outputFileName}.textbundle/text.md" -t commonmark_x-attributes',
|
||||
extension: '.md',
|
||||
},
|
||||
'Typst': {
|
||||
name: 'Typst',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/markdown.lua" -s -o "${outputPath}" -t typst',
|
||||
extension: '.typ',
|
||||
},
|
||||
'PDF': {
|
||||
name: 'PDF',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/pdf.lua" ${ options.textemplate ? `--resource-path="${pluginDir}/textemplate" --template="${options.textemplate}"` : ` ` } -o "${outputPath}" -t pdf',
|
||||
customArguments: '--pdf-engine=pdflatex',
|
||||
optionsMeta: {
|
||||
'textemplate': 'preset:textemplate', // reference from `PresetOptionsMeta` in `src/settings.ts`
|
||||
},
|
||||
extension: '.pdf',
|
||||
},
|
||||
'Word (.docx)': {
|
||||
name: 'Word (.docx)',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -o "${outputPath}" -t docx',
|
||||
extension: '.docx',
|
||||
},
|
||||
'OpenOffice': {
|
||||
name: 'OpenOffice',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -o "${outputPath}" -t odt',
|
||||
extension: '.odt',
|
||||
},
|
||||
'RTF': {
|
||||
name: 'RTF',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -s -o "${outputPath}" -t rtf',
|
||||
extension: '.rtf',
|
||||
},
|
||||
'Epub': {
|
||||
name: 'Epub',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -o "${outputPath}" -t epub',
|
||||
extension: '.epub',
|
||||
},
|
||||
'Latex': {
|
||||
name: 'Latex',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" ${ options.textemplate ? `--resource-path="${pluginDir}/textemplate" --template="${options.textemplate}"` : ` ` } --extract-media="${outputDir}" -s -o "${outputPath}" -t latex',
|
||||
optionsMeta: {
|
||||
'textemplate': 'preset:textemplate', // reference from `PresetOptionsMeta` in `src/settings.ts`
|
||||
},
|
||||
extension: '.tex',
|
||||
},
|
||||
'Media Wiki': {
|
||||
name: 'Media Wiki',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -s -o "${outputPath}" -t mediawiki',
|
||||
extension: '.mediawiki',
|
||||
},
|
||||
'reStructuredText': {
|
||||
name: 'reStructuredText',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -s -o "${outputPath}" -t rst',
|
||||
extension: '.rst',
|
||||
},
|
||||
'Textile': {
|
||||
name: 'Textile',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -s -o "${outputPath}" -t textile',
|
||||
extension: '.textile',
|
||||
},
|
||||
'OPML': {
|
||||
name: 'OPML',
|
||||
type: 'pandoc',
|
||||
arguments: '-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" -s -o "${outputPath}" -t opml',
|
||||
extension: '.opml',
|
||||
},
|
||||
'Bibliography (.bib)': {
|
||||
name: 'Bibliography',
|
||||
type: 'pandoc',
|
||||
arguments:
|
||||
'-f ${fromFormat} --resource-path="${currentDir}" --resource-path="${attachmentFolderPath}" --lua-filter="${luaDir}/citefilter.lua" -o "${outputPath}" --to=bibtex "${currentPath}"',
|
||||
extension: '.bib',
|
||||
},
|
||||
'Custom': {
|
||||
name: 'Custom',
|
||||
type: 'custom',
|
||||
command: 'your command',
|
||||
targetFileExtensions: '.ext',
|
||||
},
|
||||
} satisfies Record<string, ExportSetting> as Record<string, ExportSetting>;
|
234
.obsidian/plugins/obsidian-enhancing-export-main/src/exporto0o.ts
vendored
Normal file
234
.obsidian/plugins/obsidian-enhancing-export-main/src/exporto0o.ts
vendored
Normal file
@ -0,0 +1,234 @@
|
||||
import * as ct from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import process from 'process';
|
||||
import path from 'path';
|
||||
import argsParser from 'yargs-parser';
|
||||
import { Variables, ExportSetting, extractDefaultExtension as extractExtension, createEnv } from './settings';
|
||||
import { MessageBox } from './ui/message_box';
|
||||
import { Notice, TFile } from 'obsidian';
|
||||
import { exec, renderTemplate, getPlatformValue, trimQuotes } from './utils';
|
||||
import ProgressBar from './ui/components/ProgressBar';
|
||||
import type ExportPlugin from './main';
|
||||
import pandoc from './pandoc';
|
||||
|
||||
export async function exportToOo(
|
||||
plugin: ExportPlugin,
|
||||
currentFile: TFile,
|
||||
candidateOutputDirectory: string,
|
||||
candidateOutputFileName: string | undefined,
|
||||
setting: ExportSetting,
|
||||
showOverwriteConfirmation?: boolean,
|
||||
options?: unknown,
|
||||
onSuccess?: () => void,
|
||||
onFailure?: () => void,
|
||||
beforeExport?: () => void
|
||||
) {
|
||||
const {
|
||||
settings: globalSetting,
|
||||
lang,
|
||||
manifest,
|
||||
app: {
|
||||
vault: { adapter, config: obsidianConfig },
|
||||
metadataCache,
|
||||
},
|
||||
} = plugin;
|
||||
|
||||
if (!candidateOutputFileName) {
|
||||
const extension = extractExtension(setting);
|
||||
candidateOutputFileName = `${currentFile.basename}${extension}`;
|
||||
}
|
||||
if (showOverwriteConfirmation == undefined) {
|
||||
showOverwriteConfirmation = globalSetting.showOverwriteConfirmation;
|
||||
}
|
||||
|
||||
const showExportProgressBar = globalSetting.showExportProgressBar;
|
||||
|
||||
/* Variables
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${outputDir} --> /User/aaa/Documents/
|
||||
* - ${outputPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${outputFileName} --> test
|
||||
* - ${outputFileFullName} --> test.pdf
|
||||
*
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${currentDir} --> /User/aaa/Documents/
|
||||
* - ${currentPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${CurrentFileName} --> test
|
||||
* - ${CurrentFileFullName} --> test.pdf
|
||||
*/
|
||||
const vaultDir = adapter.getBasePath();
|
||||
const pluginDir = `${vaultDir}/${manifest.dir}`;
|
||||
const luaDir = `${pluginDir}/lua`;
|
||||
const outputDir = candidateOutputDirectory;
|
||||
const outputPath = `${outputDir}/${candidateOutputFileName}`;
|
||||
const outputFileName = candidateOutputFileName.substring(0, candidateOutputFileName.lastIndexOf('.'));
|
||||
const outputFileFullName = candidateOutputFileName;
|
||||
|
||||
const currentPath = adapter.getFullPath(currentFile.path);
|
||||
const currentDir = path.dirname(currentPath);
|
||||
const currentFileName = currentFile.basename;
|
||||
const currentFileFullName = currentFile.name;
|
||||
|
||||
let attachmentFolderPath = obsidianConfig.attachmentFolderPath ?? '/';
|
||||
if (attachmentFolderPath === '/') {
|
||||
attachmentFolderPath = vaultDir;
|
||||
} else if (attachmentFolderPath.startsWith('.')) {
|
||||
attachmentFolderPath = path.join(currentDir, attachmentFolderPath.substring(1));
|
||||
} else {
|
||||
attachmentFolderPath = path.join(vaultDir, attachmentFolderPath);
|
||||
}
|
||||
|
||||
let frontMatter: unknown = null;
|
||||
try {
|
||||
frontMatter = metadataCache.getCache(currentFile.path).frontmatter;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
const variables: Variables = {
|
||||
pluginDir,
|
||||
luaDir,
|
||||
outputDir,
|
||||
outputPath,
|
||||
outputFileName,
|
||||
outputFileFullName,
|
||||
currentDir,
|
||||
currentPath,
|
||||
currentFileName,
|
||||
currentFileFullName,
|
||||
attachmentFolderPath,
|
||||
vaultDir,
|
||||
// date: new Date(currentFile.stat.ctime),
|
||||
// lastMod: new Date(currentFile.stat.mtime),
|
||||
// now: new Date()
|
||||
metadata: frontMatter,
|
||||
options,
|
||||
fromFormat: app.vault.config.useMarkdownLinks ? 'markdown' : 'markdown+wikilinks_title_after_pipe',
|
||||
};
|
||||
|
||||
const showCommandLineOutput = setting.type === 'custom' && setting.showCommandOutput;
|
||||
const openExportedFileLocation = setting.openExportedFileLocation ?? globalSetting.openExportedFileLocation;
|
||||
const openExportedFile = setting.openExportedFile ?? globalSetting.openExportedFile;
|
||||
|
||||
if (showOverwriteConfirmation && fs.existsSync(outputPath)) {
|
||||
// const msgBox = new MessageBox(this.app, {
|
||||
// message: lang.overwriteConfirmationDialog.message(outputDir),
|
||||
// title: lang.overwriteConfirmationDialog.title(outputFileFullName),
|
||||
// buttons: 'OkCancel',
|
||||
// buttonsLabel: {
|
||||
// ok: lang.overwriteConfirmationDialog.replace,
|
||||
// },
|
||||
// buttonsClass: {
|
||||
// ok: 'mod-warning'
|
||||
// },
|
||||
// callback: {
|
||||
// ok: () => doExport()
|
||||
// }
|
||||
// });
|
||||
// msgBox.open();
|
||||
|
||||
const result = await ct.remote.dialog.showSaveDialog({
|
||||
title: lang.overwriteConfirmationDialog.title(outputFileFullName),
|
||||
defaultPath: outputPath,
|
||||
properties: ['showOverwriteConfirmation', 'createDirectory'],
|
||||
});
|
||||
|
||||
if (result.canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
variables.outputPath = result.filePath;
|
||||
variables.outputDir = path.dirname(variables.outputPath);
|
||||
variables.outputFileFullName = path.basename(variables.outputPath);
|
||||
variables.outputFileName = path.basename(variables.outputFileFullName, path.extname(variables.outputFileFullName));
|
||||
}
|
||||
|
||||
// show progress
|
||||
let progressBarHide: (() => void) | undefined = undefined;
|
||||
if (showExportProgressBar) {
|
||||
beforeExport?.();
|
||||
progressBarHide = ProgressBar.show(lang.preparing(variables.outputFileFullName));
|
||||
}
|
||||
|
||||
// process Environment variables..
|
||||
const env = (variables.env = createEnv(getPlatformValue(globalSetting.env) ?? {}, variables));
|
||||
|
||||
let pandocPath = pandoc.normalizePath(getPlatformValue(globalSetting.pandocPath));
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// https://github.com/mokeyish/obsidian-enhancing-export/issues/153
|
||||
pandocPath = pandocPath.replaceAll('\\', '/');
|
||||
const pathKeys: Array<keyof Variables> = [
|
||||
'pluginDir',
|
||||
'luaDir',
|
||||
'outputDir',
|
||||
'outputPath',
|
||||
'currentDir',
|
||||
'currentPath',
|
||||
'attachmentFolderPath',
|
||||
'vaultDir',
|
||||
];
|
||||
|
||||
for (const pathKey of pathKeys) {
|
||||
const path = variables[pathKey] as string;
|
||||
variables[pathKey] = path.replaceAll('\\', '/');
|
||||
}
|
||||
}
|
||||
|
||||
const cmdTpl =
|
||||
setting.type === 'pandoc'
|
||||
? `${pandocPath} "\${currentPath}" ${setting.arguments ?? ''} ${setting.customArguments ?? ''}`
|
||||
: setting.command;
|
||||
|
||||
const cmd = renderTemplate(cmdTpl, variables);
|
||||
const args = argsParser(cmd.match(/(?:[^\s"]+|"[^"]*")+/g), {
|
||||
alias: {
|
||||
output: ['o'],
|
||||
},
|
||||
});
|
||||
const actualOutputPath = path.normalize(trimQuotes(args.output));
|
||||
|
||||
const actualOutputDir = path.dirname(actualOutputPath);
|
||||
if (!fs.existsSync(actualOutputDir)) {
|
||||
fs.mkdirSync(actualOutputDir);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`[${plugin.manifest.name}]: export command and options:`, {
|
||||
cmd,
|
||||
options: { cwd: variables.currentDir, env },
|
||||
});
|
||||
await exec(cmd, { cwd: variables.currentDir, env });
|
||||
progressBarHide?.();
|
||||
|
||||
const next = async () => {
|
||||
if (openExportedFileLocation) {
|
||||
setTimeout(() => {
|
||||
ct.remote.shell.showItemInFolder(actualOutputPath);
|
||||
}, 1000);
|
||||
}
|
||||
if (openExportedFile) {
|
||||
await ct.remote.shell.openPath(actualOutputPath);
|
||||
}
|
||||
if (setting.type === 'pandoc' && setting.runCommand === true && setting.command) {
|
||||
const extCmd = renderTemplate(setting.command, variables);
|
||||
await exec(extCmd, { cwd: variables.currentDir, env });
|
||||
}
|
||||
// success
|
||||
onSuccess && onSuccess();
|
||||
};
|
||||
|
||||
if (showCommandLineOutput) {
|
||||
const box = new MessageBox(app, lang.exportCommandOutputMessage(cmd));
|
||||
box.onClose = next;
|
||||
box.open();
|
||||
} else {
|
||||
new Notice(lang.exportSuccessNotice(variables.outputFileFullName), 1500);
|
||||
await next();
|
||||
}
|
||||
} catch (err) {
|
||||
progressBarHide?.();
|
||||
new MessageBox(app, lang.exportErrorOutputMessage(cmd, err)).open();
|
||||
onFailure && onFailure();
|
||||
}
|
||||
}
|
79
.obsidian/plugins/obsidian-enhancing-export-main/src/hmr.ts
vendored
Normal file
79
.obsidian/plugins/obsidian-enhancing-export-main/src/hmr.ts
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
import type { Plugin } from 'obsidian';
|
||||
import { debounce, Platform } from 'obsidian';
|
||||
import { normalize, join } from 'path';
|
||||
|
||||
declare global {
|
||||
interface HmrOptions {
|
||||
watchFiles?: Array<'main.js' | 'manifest.json' | 'styles.css'> | string[];
|
||||
}
|
||||
interface Window {
|
||||
hmr(plugin: Plugin, options?: HmrOptions): void;
|
||||
}
|
||||
}
|
||||
|
||||
Window.prototype.hmr = function (plugin: Plugin, options?: HmrOptions): void {
|
||||
if (Platform.isMobile) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[hmr: ${plugin.manifest.name}]`, new Date());
|
||||
|
||||
options ??= {};
|
||||
options.watchFiles ??= ['main.js', 'manifest.json', 'styles.css'];
|
||||
const { watchFiles } = options;
|
||||
|
||||
const {
|
||||
app: {
|
||||
vault: { adapter },
|
||||
plugins,
|
||||
},
|
||||
manifest: { dir: pluginDir, id },
|
||||
} = plugin;
|
||||
const {
|
||||
app: { vault },
|
||||
} = plugin;
|
||||
|
||||
const restartPlugin = async () => {
|
||||
const dbgKey = 'debug-plugin';
|
||||
const oldDebug = localStorage.getItem(dbgKey);
|
||||
try {
|
||||
localStorage.setItem(dbgKey, '1');
|
||||
await plugins.disablePlugin(id);
|
||||
await plugins.enablePlugin(id);
|
||||
} finally {
|
||||
if (oldDebug) {
|
||||
localStorage.setItem(dbgKey, oldDebug);
|
||||
} else {
|
||||
localStorage.removeItem(dbgKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const entry = normalize(join(pluginDir, 'main.js'));
|
||||
const onChange = debounce(
|
||||
async (file: string) => {
|
||||
if (file.startsWith(pluginDir)) {
|
||||
if (!(await adapter.exists(entry))) {
|
||||
return;
|
||||
}
|
||||
if (file === pluginDir) {
|
||||
// reload
|
||||
} else if (watchFiles?.length > 0) {
|
||||
if (!watchFiles.some(o => file.endsWith(o))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
await restartPlugin();
|
||||
}
|
||||
},
|
||||
500,
|
||||
true
|
||||
);
|
||||
|
||||
plugin.registerEvent(vault.on('raw', onChange));
|
||||
|
||||
plugin.register(() => adapter.stopWatchPath(pluginDir));
|
||||
adapter.startWatchPath(pluginDir);
|
||||
};
|
||||
|
||||
export {};
|
71
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/de-DE.ts
vendored
Normal file
71
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/de-DE.ts
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
import { strTpl } from '../utils';
|
||||
import type { Lang } from '.';
|
||||
|
||||
export default {
|
||||
exportToOo: 'Export to...',
|
||||
exportSuccessNotice: strTpl`Export der Datei ${0} erfolgreich!`,
|
||||
exportCommandOutputMessage: strTpl`Command: ${0}`,
|
||||
exportErrorOutputMessage: strTpl`Command: ${0},Fehler:${1}`,
|
||||
exportWithPrevious: 'Exportiere mit Vorherigem',
|
||||
pleaseOpenFile: 'Bitte öffne zunächst eine Datei.',
|
||||
preparing: strTpl`generating "${0}"...`,
|
||||
exportDialog: {
|
||||
exportTo: 'Exportiere nach',
|
||||
fileName: 'Dateiname',
|
||||
title: strTpl`Export to ${0}`,
|
||||
export: 'Export',
|
||||
selectExportFolder: 'Zielordner auswählen',
|
||||
overwriteConfirmation: 'Überschreibe den Zielordner',
|
||||
type: 'Typ',
|
||||
},
|
||||
messageBox: {
|
||||
yes: 'Ja',
|
||||
no: 'Nein',
|
||||
ok: 'Ok',
|
||||
cancel: 'Abbrechen',
|
||||
},
|
||||
overwriteConfirmationDialog: {
|
||||
replace: 'Ersetze',
|
||||
title: strTpl`"${0}" existiert bereits. Soll er ersetzt werden?`,
|
||||
message: strTpl`Eine Datei oder ein Ordner mit dem gleichen Namen existiert bereits im Ordner "${0}". Das Ersetzen wird die jetzigen Inhalte überschreiben.`,
|
||||
},
|
||||
settingTab: {
|
||||
general: 'Allgemein',
|
||||
name: 'Name',
|
||||
title: 'Export-Einstellungen',
|
||||
pandocVersion: strTpl`Version: ${0}`,
|
||||
pandocVersionWithWarning: strTpl`Version: ${0}, please upgrade version to ${1}`,
|
||||
pandocNotFound:
|
||||
'Pandoc.exe wurde nicht gefunden. Bitte geben Sie den Pfad zur Pandoc.exe ein oder fügen Sie ihn den Window Systemumgebungsvariablen hinzu.',
|
||||
defaultFolderForExportedFile: 'Standardordner für exportierte Dateien',
|
||||
openExportedFileLocation: 'Speicherort der exportierten Datei öffnen',
|
||||
openExportedFile: 'Exportierte Datei öffnen',
|
||||
pandocPath: 'Pfad zur Datei Pandoc.exe',
|
||||
pandocPathPlaceholder: '(Automatische Erkennung)',
|
||||
editCommandTemplate: '‘Befehlsvorlage bearbeiten',
|
||||
chooseCommandTemplate: 'Vorlage auswählen',
|
||||
customLocation: 'Benutzerdefinierter Speicherort',
|
||||
template: 'Vorlage',
|
||||
command: 'Befehl',
|
||||
reset: 'Zurücksetzen',
|
||||
auto: 'Auto',
|
||||
add: 'Hinzufügen',
|
||||
remove: 'Entfernen',
|
||||
rename: 'Umbenennen',
|
||||
sameFolderWithCurrentFile: 'Der gleiche Ordner mit der aktuellen Datei',
|
||||
afterExport: 'Nach dem Export',
|
||||
targetFileExtensions: 'Dateinamenserweiterung der Zieldatei',
|
||||
targetFileExtensionsTip: '(Mit Leerzeichen getrennt)',
|
||||
showCommandOutput: 'Zeige die Ausgabe des Befehls',
|
||||
runCommand: 'Starte den Befehl',
|
||||
extraArguments: 'Zusätzliche Parameter',
|
||||
save: 'Speichern',
|
||||
new: 'Neu',
|
||||
arguments: 'Parameter',
|
||||
|
||||
advanced: 'Advanced',
|
||||
environmentVariables: 'Environment Variables',
|
||||
environmentVariablesDesc: 'Define the Environment Variables for exporting.',
|
||||
ShowExportProgressBar: 'Show export progressBar',
|
||||
},
|
||||
} satisfies Lang;
|
69
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/en-US.ts
vendored
Normal file
69
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/en-US.ts
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
import { strTpl } from '../utils';
|
||||
|
||||
export default {
|
||||
exportToOo: 'Export to...',
|
||||
exportSuccessNotice: strTpl`Export file ${0} success!`,
|
||||
exportCommandOutputMessage: strTpl`Command: ${0}`,
|
||||
exportErrorOutputMessage: strTpl`Command: ${0},Error:${1}`,
|
||||
exportWithPrevious: 'Export with Previous',
|
||||
pleaseOpenFile: 'Please open a file first.',
|
||||
preparing: strTpl`generating "${0}"...`,
|
||||
exportDialog: {
|
||||
exportTo: 'Export to',
|
||||
fileName: 'File Name',
|
||||
title: strTpl`Export to ${0}`,
|
||||
export: 'Export',
|
||||
selectExportFolder: 'Please select an export folder.',
|
||||
overwriteConfirmation: 'Overwrite confirmation',
|
||||
type: 'Type',
|
||||
},
|
||||
messageBox: {
|
||||
yes: 'Yes',
|
||||
no: 'No',
|
||||
ok: 'Ok',
|
||||
cancel: 'Cancel',
|
||||
},
|
||||
overwriteConfirmationDialog: {
|
||||
replace: 'Replace',
|
||||
title: strTpl`"${0}" already exists. Do you want to replace it?`,
|
||||
message: strTpl`A file or folder with the same name already exists in the folder "${0}". Replacing it will overwrite its current contents.`,
|
||||
},
|
||||
settingTab: {
|
||||
general: 'General',
|
||||
name: 'Name',
|
||||
title: 'Export Settings',
|
||||
pandocVersion: strTpl`Version: ${0}`,
|
||||
pandocVersionWithWarning: strTpl`Version: ${0}, please upgrade version to ${1}`,
|
||||
pandocNotFound: 'Pandoc not found, please fill in the Pandoc file path, or add it to the system environment variables.',
|
||||
defaultFolderForExportedFile: 'Default Folder for Exported File',
|
||||
openExportedFileLocation: 'Open exported file location',
|
||||
ShowExportProgressBar: 'Show export progress bar',
|
||||
openExportedFile: 'Open exported file',
|
||||
pandocPath: 'Pandoc path',
|
||||
pandocPathPlaceholder: '(Auto Detect)',
|
||||
editCommandTemplate: 'Edit Command Template',
|
||||
chooseCommandTemplate: 'Choose template',
|
||||
customLocation: 'Custom location',
|
||||
template: 'Template',
|
||||
command: 'Command',
|
||||
reset: 'Reset',
|
||||
auto: 'Auto',
|
||||
add: 'Add',
|
||||
remove: 'Remove',
|
||||
rename: 'Rename',
|
||||
sameFolderWithCurrentFile: 'Same folder with current file',
|
||||
afterExport: 'After Export',
|
||||
targetFileExtensions: 'Target file extensions',
|
||||
targetFileExtensionsTip: '(Separated by whitespace)',
|
||||
showCommandOutput: 'Show command output',
|
||||
runCommand: 'Run command',
|
||||
extraArguments: 'Extra arguments',
|
||||
save: 'Save',
|
||||
new: 'New',
|
||||
arguments: 'Arguments',
|
||||
|
||||
advanced: 'Advanced',
|
||||
environmentVariables: 'Environment Variables',
|
||||
environmentVariablesDesc: 'Define the Environment Variables for exporting.',
|
||||
},
|
||||
};
|
27
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/index.ts
vendored
Normal file
27
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/index.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
import zhCN from './zh-CN';
|
||||
import enUS from './en-US';
|
||||
import deDE from './de-DE';
|
||||
import { moment } from 'obsidian';
|
||||
|
||||
export type Lang = typeof enUS;
|
||||
|
||||
export default {
|
||||
'de-DE': deDE,
|
||||
'en-US': enUS,
|
||||
'zh-CN': zhCN,
|
||||
get current() {
|
||||
const langIds = Object.keys(this);
|
||||
const locale = moment.locale().toLowerCase();
|
||||
let langId = langIds.find(id => id.toLowerCase() === locale.toLowerCase());
|
||||
if (langId) {
|
||||
return this[langId];
|
||||
}
|
||||
|
||||
const localePrefix = locale.split('-')[0];
|
||||
langId = langIds.find(id => id.toLowerCase().startsWith(localePrefix));
|
||||
if (langId) {
|
||||
return this[langId];
|
||||
}
|
||||
return this['en-US'];
|
||||
},
|
||||
};
|
70
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/zh-CN.ts
vendored
Normal file
70
.obsidian/plugins/obsidian-enhancing-export-main/src/lang/zh-CN.ts
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
import { strTpl } from '../utils';
|
||||
import type { Lang } from '.';
|
||||
|
||||
export default {
|
||||
exportToOo: '导出为......',
|
||||
exportWithPrevious: '使用上一次设置导出',
|
||||
exportSuccessNotice: strTpl`导出文件 ${0} 成功!`,
|
||||
exportCommandOutputMessage: strTpl`命令:${0}`,
|
||||
exportErrorOutputMessage: strTpl`命令 ${0},错误:${1}`,
|
||||
pleaseOpenFile: '请打开一个文件先。',
|
||||
preparing: strTpl`正在生成 "${0}" ......`,
|
||||
exportDialog: {
|
||||
fileName: '文件名',
|
||||
type: '类型',
|
||||
exportTo: '导出到',
|
||||
title: strTpl`导出为 ${0}`,
|
||||
export: '导出',
|
||||
selectExportFolder: '请选择导出文件夹',
|
||||
overwriteConfirmation: '覆盖提示',
|
||||
},
|
||||
messageBox: {
|
||||
yes: '是',
|
||||
no: '否',
|
||||
ok: '确认',
|
||||
cancel: '取消',
|
||||
},
|
||||
overwriteConfirmationDialog: {
|
||||
replace: '替换',
|
||||
title: strTpl`"${0}" 已经存在。您要替换它吗?`,
|
||||
message: strTpl`"${0}" 文件夹中已有相同的文件或文件夹,若替换,则会覆盖其当前内容。`,
|
||||
},
|
||||
settingTab: {
|
||||
title: '导出设置',
|
||||
general: '通用',
|
||||
name: '名称',
|
||||
customLocation: '自定义',
|
||||
pandocVersion: strTpl`版本: ${0}`,
|
||||
pandocVersionWithWarning: strTpl`Version: ${0}, 请升级版本到 ${1}`,
|
||||
pandocNotFound: '找不到 Pandoc,请填写 Pandoc 文件路径,或者将其添加到系统环境变量中。',
|
||||
pandocPath: 'Pandoc 路径',
|
||||
defaultFolderForExportedFile: '默认的导出文件夹',
|
||||
openExportedFileLocation: '打开导出文件所在目录',
|
||||
sameFolderWithCurrentFile: '与原文件同一目录下',
|
||||
openExportedFile: '打开导出文件',
|
||||
pandocPathPlaceholder: '(自动检测)',
|
||||
editCommandTemplate: '编辑命令模板',
|
||||
chooseCommandTemplate: '选择模板',
|
||||
afterExport: '导出后',
|
||||
command: '命令',
|
||||
arguments: '参数',
|
||||
auto: '自动',
|
||||
reset: '重置',
|
||||
add: '添加',
|
||||
remove: '移除',
|
||||
rename: '重命名',
|
||||
targetFileExtensions: '目标文件扩展名',
|
||||
targetFileExtensionsTip: '(用空格分开)',
|
||||
showCommandOutput: '显示命令行输出',
|
||||
runCommand: '运行自定义命令',
|
||||
extraArguments: '自定义参数',
|
||||
save: '保存',
|
||||
new: '新建',
|
||||
template: '模板',
|
||||
|
||||
advanced: '高级',
|
||||
environmentVariables: '环境变量',
|
||||
environmentVariablesDesc: '定义导出的环境变量.',
|
||||
ShowExportProgressBar: '显示导出进度条',
|
||||
},
|
||||
} satisfies Lang;
|
153
.obsidian/plugins/obsidian-enhancing-export-main/src/main.ts
vendored
Normal file
153
.obsidian/plugins/obsidian-enhancing-export-main/src/main.ts
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
import { App, Menu, Plugin, PluginManifest, TFile, Notice, debounce } from 'obsidian';
|
||||
import { UniversalExportPluginSettings, ExportSetting, DEFAULT_SETTINGS, DEFAULT_ENV } from './settings';
|
||||
// import { ExportSettingTab, ExportDialog } from './ui/legacy';
|
||||
import { ExportSettingTab, ExportDialog } from './ui';
|
||||
import { exportToOo } from './exporto0o';
|
||||
import { getPlatformValue, PlatformKey } from './utils';
|
||||
import lang, { Lang } from './lang';
|
||||
import path from 'path';
|
||||
import resources from './resources';
|
||||
import './styles.css';
|
||||
|
||||
export default class UniversalExportPlugin extends Plugin {
|
||||
settings: UniversalExportPluginSettings;
|
||||
lang: Lang;
|
||||
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
super(app, manifest);
|
||||
this.lang = lang.current;
|
||||
this.saveSettings = debounce(this.saveSettings.bind(this), 1000, true) as unknown as typeof this.saveSettings;
|
||||
}
|
||||
|
||||
async onload() {
|
||||
await this.releaseResources();
|
||||
|
||||
await this.loadSettings();
|
||||
const { lang } = this;
|
||||
|
||||
this.addSettingTab(new ExportSettingTab(this));
|
||||
|
||||
this.addCommand({
|
||||
id: 'obsidian-enhancing-export:export',
|
||||
name: lang.exportToOo,
|
||||
icon: 'document',
|
||||
callback: () => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (file) {
|
||||
ExportDialog.show(this, file);
|
||||
} else {
|
||||
new Notice(lang.pleaseOpenFile, 2000);
|
||||
}
|
||||
},
|
||||
});
|
||||
this.addCommand({
|
||||
id: 'obsidian-enhancing-export:export-with-previous',
|
||||
name: lang.exportWithPrevious,
|
||||
icon: 'document',
|
||||
callback: async () => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
if (file) {
|
||||
if (this.settings.lastExportType && this.settings.lastExportDirectory) {
|
||||
const setting = this.settings.items.find(s => s.name === this.settings.lastExportType);
|
||||
if (setting) {
|
||||
await exportToOo(this, file, getPlatformValue(this.settings.lastExportDirectory), undefined, setting);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ExportDialog.show(this, file);
|
||||
} else {
|
||||
new Notice(lang.pleaseOpenFile, 2000);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.registerEvent(
|
||||
this.app.workspace.on('file-menu', (menu: Menu, file) => {
|
||||
if (file instanceof TFile) {
|
||||
menu
|
||||
.addItem(item => {
|
||||
item
|
||||
.setTitle(lang.exportToOo)
|
||||
.setIcon('document')
|
||||
.onClick((): void => {
|
||||
ExportDialog.show(this, file);
|
||||
});
|
||||
})
|
||||
.addSeparator();
|
||||
}
|
||||
})
|
||||
);
|
||||
// this.downloadLuaScripts().then();
|
||||
if (import.meta.env.DEV) {
|
||||
window.hmr && window.hmr(this);
|
||||
}
|
||||
}
|
||||
|
||||
public async resetSettings(): Promise<void> {
|
||||
this.settings = {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_SETTINGS)),
|
||||
lastExportDirectory: this.settings.lastExportDirectory,
|
||||
};
|
||||
await this.saveSettings();
|
||||
}
|
||||
|
||||
public async loadSettings(): Promise<void> {
|
||||
const settings: UniversalExportPluginSettings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
settings.items.forEach(v => {
|
||||
Object.assign(v, Object.assign({}, DEFAULT_SETTINGS.items.find(o => o.name === v.name) ?? {}, v));
|
||||
});
|
||||
for (const item of DEFAULT_SETTINGS.items) {
|
||||
if (settings.items.every(o => o.name !== item.name)) {
|
||||
settings.items.push(item);
|
||||
}
|
||||
}
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public async saveSettings(): Promise<void> {
|
||||
console.log('[obsidian-enhancing-export] saveSettings', this.settings);
|
||||
const settings: UniversalExportPluginSettings = JSON.parse(JSON.stringify(this.settings));
|
||||
settings.items.forEach(v => {
|
||||
const def = DEFAULT_SETTINGS.items.find(o => o.name === v.name);
|
||||
if (def) {
|
||||
Object.keys(v).forEach((k: keyof ExportSetting) => {
|
||||
if (k !== 'name' && JSON.stringify(v[k]) === JSON.stringify(def[k])) {
|
||||
delete v[k];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (settings.env) {
|
||||
for (const platform of Object.keys(settings.env) as PlatformKey[]) {
|
||||
const env = settings.env[platform];
|
||||
if (JSON.stringify(env) === JSON.stringify(DEFAULT_ENV[platform])) {
|
||||
delete settings.env[platform];
|
||||
continue;
|
||||
}
|
||||
const refEnv = getPlatformValue(DEFAULT_ENV, platform);
|
||||
for (const [name, value] of Object.entries(env)) {
|
||||
if (value === refEnv[name]) {
|
||||
delete env[name];
|
||||
}
|
||||
}
|
||||
if (Object.keys(env).length === 0) {
|
||||
delete settings.env[platform];
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.saveData(settings);
|
||||
}
|
||||
|
||||
async releaseResources(): Promise<void> {
|
||||
const { adapter } = this.app.vault;
|
||||
for (const [dir, res] of resources) {
|
||||
const resDir = path.join(this.manifest.dir, dir);
|
||||
await adapter.mkdir(resDir);
|
||||
for (const [fileName, bytes] of res) {
|
||||
const filePath = path.join(resDir, fileName);
|
||||
await adapter.writeBinary(filePath, bytes);
|
||||
}
|
||||
}
|
||||
resources.length = 0;
|
||||
}
|
||||
}
|
28
.obsidian/plugins/obsidian-enhancing-export-main/src/pandoc.ts
vendored
Normal file
28
.obsidian/plugins/obsidian-enhancing-export-main/src/pandoc.ts
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
import { exec } from './utils';
|
||||
import semver from 'semver/preload';
|
||||
|
||||
export const normalizePandocPath = (path?: string) => (path?.includes(' ') ? `"${path}"` : `${path ?? 'pandoc'}`);
|
||||
|
||||
export async function getPandocVersion(path?: string, env?: Record<string, string>) {
|
||||
path = normalizePandocPath(path);
|
||||
let version = await exec(`${path} --version`, { env });
|
||||
version = version.substring(0, version.indexOf('\n')).replace('pandoc.exe', '').replace('pandoc', '').trim();
|
||||
let dotCount = [...version].filter(c => c === '.').length;
|
||||
if (dotCount === 1) {
|
||||
version = `${version}.0`;
|
||||
} else {
|
||||
while (dotCount > 2) {
|
||||
version = version.substring(0, version.lastIndexOf('.'));
|
||||
dotCount -= 1;
|
||||
}
|
||||
}
|
||||
return semver.parse(version, true);
|
||||
}
|
||||
|
||||
export const PANDOC_REQUIRED_VERSION = '3.1.7';
|
||||
|
||||
export default {
|
||||
normalizePath: normalizePandocPath,
|
||||
getVersion: getPandocVersion,
|
||||
requiredVersion: PANDOC_REQUIRED_VERSION,
|
||||
};
|
9
.obsidian/plugins/obsidian-enhancing-export-main/src/resources.ts
vendored
Normal file
9
.obsidian/plugins/obsidian-enhancing-export-main/src/resources.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
const embed = (dir: string, res: Record<string, { default: Uint8Array }>) =>
|
||||
[dir, Object.entries(res).map(([k, m]) => [k.substring(dir.length + 3), m.default] as const)] as const;
|
||||
|
||||
// The embedded resource
|
||||
export default [
|
||||
// For other file types, the Loader must be configured in the <root>/vite.config.ts.
|
||||
embed('lua', import.meta.glob<{ default: Uint8Array }>('../lua/*.lua', { eager: true })),
|
||||
embed('textemplate', import.meta.glob<{ default: Uint8Array }>('../textemplate/*.{tex,sty}', { eager: true })),
|
||||
];
|
172
.obsidian/plugins/obsidian-enhancing-export-main/src/settings.ts
vendored
Normal file
172
.obsidian/plugins/obsidian-enhancing-export-main/src/settings.ts
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
import export_templates from './export_templates';
|
||||
import { setPlatformValue, PlatformValue, renderTemplate, getPlatformValue } from './utils';
|
||||
import type { PropertyGridMeta } from './ui/components/PropertyGrid';
|
||||
|
||||
/*
|
||||
* Variables
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${outputDir} --> /User/aaa/Documents/
|
||||
* - ${outputPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${outputFileName} --> test
|
||||
* - ${outputFileFullName} --> test.pdf
|
||||
*
|
||||
* /User/aaa/Documents/test.pdf
|
||||
* - ${currentDir} --> /User/aaa/Documents/
|
||||
* - ${currentPath} --> /User/aaa/Documents/test.pdf
|
||||
* - ${CurrentFileName} --> test
|
||||
* - ${CurrentFileFullName} --> test.pdf
|
||||
*/
|
||||
export interface Variables extends Record<string, unknown> {
|
||||
attachmentFolderPath: string;
|
||||
pluginDir: string;
|
||||
luaDir: string;
|
||||
outputDir: string;
|
||||
outputPath: string;
|
||||
outputFileName: string;
|
||||
outputFileFullName: string;
|
||||
currentDir: string;
|
||||
currentPath: string;
|
||||
currentFileName: string;
|
||||
currentFileFullName: string;
|
||||
vaultDir: string;
|
||||
// date: new Date(currentFile.stat.ctime),
|
||||
// lastMod: new Date(currentFile.stat.mtime),
|
||||
// now: new Date()
|
||||
metadata?: unknown;
|
||||
options?: unknown;
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface UniversalExportPluginSettings {
|
||||
version?: string;
|
||||
pandocPath?: PlatformValue<string>;
|
||||
showOverwriteConfirmation?: boolean;
|
||||
defaultExportDirectoryMode: 'Auto' | 'Same' | 'Custom';
|
||||
customDefaultExportDirectory?: PlatformValue<string>;
|
||||
env: PlatformValue<Record<string, string>>;
|
||||
items: ExportSetting[];
|
||||
|
||||
openExportedFile?: boolean; // open exported file after export
|
||||
openExportedFileLocation?: boolean; // open exported file location after export
|
||||
|
||||
lastEditName?: string;
|
||||
|
||||
lastExportDirectory?: PlatformValue<string>;
|
||||
lastExportType?: string;
|
||||
|
||||
showExportProgressBar?: boolean;
|
||||
}
|
||||
|
||||
export type OptionsMeta = {
|
||||
[optionsName: string]: PropertyGridMeta[string] | `preset:${keyof typeof PRESET_OPTIONS_META}`;
|
||||
};
|
||||
|
||||
interface CommonExportSetting {
|
||||
name: string;
|
||||
|
||||
openExportedFileLocation?: boolean; // open exported file location after export
|
||||
openExportedFile?: boolean; // open exported file after export
|
||||
optionsMeta?: OptionsMeta;
|
||||
}
|
||||
|
||||
export interface PandocExportSetting extends CommonExportSetting {
|
||||
type: 'pandoc';
|
||||
arguments: string;
|
||||
customArguments?: string;
|
||||
extension: string;
|
||||
|
||||
runCommand?: boolean; // run command after export
|
||||
command?: string; // command to run after export
|
||||
}
|
||||
|
||||
export interface CustomExportSetting extends CommonExportSetting {
|
||||
type: 'custom';
|
||||
command: string;
|
||||
targetFileExtensions?: string;
|
||||
|
||||
showCommandOutput?: boolean; // show command output in console after export
|
||||
}
|
||||
|
||||
export type ExportSetting = PandocExportSetting | CustomExportSetting;
|
||||
|
||||
export const PRESET_OPTIONS_META: PropertyGridMeta = {
|
||||
'textemplate': {
|
||||
title: 'Latex Template',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ name: 'None', value: null },
|
||||
{ name: 'Dissertation', value: 'dissertation.tex' },
|
||||
{ name: 'Academic Paper', value: 'neurips.tex' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_ENV = (() => {
|
||||
let env: PlatformValue<Record<string, string>> = {};
|
||||
env = setPlatformValue(
|
||||
env,
|
||||
{
|
||||
'HOME': '${HOME}',
|
||||
'PATH': '${PATH}',
|
||||
'TEXINPUTS': '${pluginDir}/textemplate/:', // It is necessary to **append** to the current TEXINPUTS wtih ":" - NOT REPLACE. TEXINPUTS contains the basic latex classes.
|
||||
},
|
||||
'*' // available for all platforms.
|
||||
);
|
||||
|
||||
env = setPlatformValue(
|
||||
env,
|
||||
{
|
||||
'TEXINPUTS': '${pluginDir}/textemplate/;', // Windows uses ; rather than : for appending
|
||||
'PATH': '${HOME}\\AppData\\Local\\Pandoc;${PATH}',
|
||||
},
|
||||
'win32' // available for windows only.
|
||||
);
|
||||
|
||||
env = setPlatformValue(
|
||||
env,
|
||||
{
|
||||
'PATH': '/opt/homebrew/bin:/usr/local/bin:/Library/TeX/texbin:${PATH}', // Add HomebrewBin and TexBin. see: https://docs.brew.sh/Installation
|
||||
},
|
||||
'darwin' // for MacOS only.
|
||||
);
|
||||
|
||||
return env;
|
||||
})();
|
||||
|
||||
export const DEFAULT_SETTINGS: UniversalExportPluginSettings = {
|
||||
items: Object.values(export_templates).filter(o => o.type !== 'custom'),
|
||||
pandocPath: undefined,
|
||||
defaultExportDirectoryMode: 'Auto',
|
||||
openExportedFile: true,
|
||||
env: DEFAULT_ENV,
|
||||
showExportProgressBar: true,
|
||||
};
|
||||
|
||||
export function extractDefaultExtension(s: ExportSetting): string {
|
||||
if (s.type === 'pandoc') {
|
||||
return s.extension;
|
||||
} else if (s.type === 'custom') {
|
||||
return s.targetFileExtensions?.split(',')[0];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function createEnv(env: Record<string, string>, envVars?: Record<string, unknown>) {
|
||||
env = Object.assign({}, getPlatformValue(DEFAULT_ENV), env);
|
||||
envVars = Object.assign({ HOME: process.env['HOME'] ?? process.env['USERPROFILE'] }, process.env, envVars ?? {});
|
||||
return Object.fromEntries(Object.entries(env).map(([n, v]) => [n, renderTemplate(v, envVars)]));
|
||||
}
|
||||
|
||||
export function finalizeOptionsMeta(meta?: OptionsMeta): PropertyGridMeta {
|
||||
if (meta) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(meta).map(([optionsName, optionsMetaOrPresetName]) => [
|
||||
optionsName,
|
||||
typeof optionsMetaOrPresetName === 'string'
|
||||
? PRESET_OPTIONS_META[optionsMetaOrPresetName.startsWith('preset:') ? optionsMetaOrPresetName.substring(7) : '']
|
||||
: optionsMetaOrPresetName,
|
||||
])
|
||||
);
|
||||
}
|
||||
return {};
|
||||
}
|
8
.obsidian/plugins/obsidian-enhancing-export-main/src/styles.css
vendored
Normal file
8
.obsidian/plugins/obsidian-enhancing-export-main/src/styles.css
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.setting-item.ex-setting-item {
|
||||
border-top: unset;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
*[hidden] {
|
||||
display: none;
|
||||
}
|
141
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/ExportDialog.tsx
vendored
Normal file
141
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/ExportDialog.tsx
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
import * as ct from 'electron';
|
||||
import { TFile } from 'obsidian';
|
||||
import { createSignal, createRoot, onCleanup, createMemo, untrack, createEffect, Show } from 'solid-js';
|
||||
import { insert } from 'solid-js/web';
|
||||
import type UniversalExportPlugin from '../main';
|
||||
import { extractDefaultExtension as extractExtension, finalizeOptionsMeta } from '../settings';
|
||||
import { setPlatformValue, getPlatformValue, } from '../utils';
|
||||
import { exportToOo } from '../exporto0o';
|
||||
import Modal from './components/Modal';
|
||||
import Button from './components/Button';
|
||||
import PropertyGrid, { createDefaultObject } from './components/PropertyGrid';
|
||||
import Setting, {Text, DropDown, ExtraButton, Toggle} from './components/Setting';
|
||||
|
||||
|
||||
const Dialog = (props: { plugin: UniversalExportPlugin, currentFile: TFile, onClose?: () => void }) => {
|
||||
const { plugin: { app, settings: globalSetting, lang }, currentFile } = props;
|
||||
|
||||
const [hidden, setHidden] = createSignal(false);
|
||||
const [showOverwriteConfirmation, setShowOverwriteConfirmation] = createSignal(globalSetting.showOverwriteConfirmation);
|
||||
const [exportType, setExportType] = createSignal(globalSetting.lastExportType ?? globalSetting.items.first()?.name);
|
||||
const [options, setOptions] = createSignal({});
|
||||
const setting = createMemo(() => globalSetting.items.find(o => o.name === exportType()));
|
||||
const extension = createMemo(() => extractExtension(setting()));
|
||||
const title = createMemo(() => lang.exportDialog.title(setting().name));
|
||||
const optionsMeta = createMemo(() => finalizeOptionsMeta(setting().optionsMeta));
|
||||
|
||||
const [candidateOutputDirectory, setCandidateOutputDirectory] = createSignal(`${getPlatformValue(globalSetting.lastExportDirectory) ?? ct.remote.app.getPath('documents')}`);
|
||||
const [candidateOutputFileName, setCandidateOutputFileName] = createSignal(`${currentFile.basename}${extension()}`);
|
||||
|
||||
createEffect(() => {
|
||||
const meta = optionsMeta();
|
||||
setOptions(meta ? createDefaultObject(meta) : {});
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
let fileName = untrack(candidateOutputFileName);
|
||||
fileName = fileName.includes('.') ? fileName.substring(0, fileName.lastIndexOf('.')) : fileName;
|
||||
setCandidateOutputFileName(`${fileName}${extension()}`);
|
||||
});
|
||||
|
||||
const exportTypes = globalSetting.items.map(o => ({ name: o.name, value: o.name }));
|
||||
|
||||
if (globalSetting.defaultExportDirectoryMode === 'Same') {
|
||||
const path = currentFile.vault.adapter.getBasePath() + '/' + currentFile.parent.path;
|
||||
setCandidateOutputDirectory(path);
|
||||
} else if (globalSetting.defaultExportDirectoryMode === 'Custom') {
|
||||
setCandidateOutputDirectory(getPlatformValue(globalSetting.customDefaultExportDirectory));
|
||||
}
|
||||
|
||||
const chooseFolder = async () => {
|
||||
const retval = await ct.remote.dialog.showOpenDialog({
|
||||
title: lang.exportDialog.selectExportFolder,
|
||||
defaultPath: candidateOutputDirectory(),
|
||||
properties: ['createDirectory', 'openDirectory'],
|
||||
});
|
||||
if (!retval.canceled && retval.filePaths?.length > 0) {
|
||||
setCandidateOutputDirectory(retval.filePaths[0]);
|
||||
}
|
||||
};
|
||||
|
||||
const doExport = async () => {
|
||||
const plugin = props.plugin;
|
||||
setHidden(true);
|
||||
await exportToOo(
|
||||
plugin,
|
||||
currentFile,
|
||||
untrack(candidateOutputDirectory),
|
||||
untrack(candidateOutputFileName),
|
||||
untrack(setting),
|
||||
untrack(showOverwriteConfirmation),
|
||||
options(),
|
||||
async () => {
|
||||
globalSetting.showOverwriteConfirmation = untrack(showOverwriteConfirmation);
|
||||
globalSetting.lastExportDirectory = setPlatformValue(globalSetting.lastExportDirectory, untrack(candidateOutputDirectory));
|
||||
|
||||
globalSetting.lastExportType = untrack(setting).name;
|
||||
await plugin.saveSettings();
|
||||
props.onClose && props.onClose();
|
||||
},
|
||||
() => {
|
||||
setHidden(false);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return <>
|
||||
<Modal app={app} title={title()} hidden={hidden()} onClose={props.onClose} >
|
||||
<Setting name={lang.exportDialog.type}>
|
||||
<DropDown options={exportTypes} onChange={(typ) => setExportType(typ)} selected={exportType()}/>
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.exportDialog.fileName}>
|
||||
<Text
|
||||
title={candidateOutputFileName()}
|
||||
value={candidateOutputFileName()}
|
||||
onChange={(value) => setCandidateOutputFileName(value)}
|
||||
/>
|
||||
</Setting>
|
||||
|
||||
<Show when={optionsMeta()}>
|
||||
<PropertyGrid meta={optionsMeta()} value={options()} onChange={ (o) => setOptions(o)}/>
|
||||
</Show>
|
||||
|
||||
<Setting name={lang.exportDialog.exportTo}>
|
||||
<Text title={candidateOutputDirectory()} value={candidateOutputDirectory()} disabled />
|
||||
<ExtraButton icon='folder' onClick={chooseFolder} />
|
||||
</Setting>
|
||||
|
||||
|
||||
<Setting name={lang.exportDialog.overwriteConfirmation} class="mod-toggle">
|
||||
<Toggle checked={showOverwriteConfirmation()} onChange={setShowOverwriteConfirmation} />
|
||||
</Setting>
|
||||
|
||||
<div class="modal-button-container">
|
||||
<Button cta={true} onClick={doExport}>{lang.exportDialog.export}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</>;
|
||||
};
|
||||
|
||||
|
||||
const show = (plugin: UniversalExportPlugin, currentFile: TFile) => createRoot(dispose => {
|
||||
let disposed = false;
|
||||
const cleanup = () => {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
dispose();
|
||||
};
|
||||
const el = insert(document.body, () => <Dialog onClose={cleanup} plugin={plugin} currentFile={currentFile} />);
|
||||
onCleanup(() => {
|
||||
el instanceof Node && document.body.contains(el) && document.body.removeChild(el);
|
||||
});
|
||||
return cleanup;
|
||||
});
|
||||
|
||||
|
||||
export default {
|
||||
show
|
||||
};
|
362
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/SettingTab.tsx
vendored
Normal file
362
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/SettingTab.tsx
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
import * as ct from 'electron';
|
||||
import process from 'process';
|
||||
import { PluginSettingTab } from 'obsidian';
|
||||
import type { SemVer } from 'semver'
|
||||
import type UniversalExportPlugin from '../main';
|
||||
import {
|
||||
CustomExportSetting,
|
||||
ExportSetting,
|
||||
PandocExportSetting,
|
||||
createEnv,
|
||||
DEFAULT_ENV
|
||||
} from '../settings';
|
||||
import { setPlatformValue, getPlatformValue } from '../utils';
|
||||
|
||||
import { createSignal, createRoot, onCleanup, createMemo, createEffect, Show, batch, Match, Switch, JSX } from 'solid-js';
|
||||
import { createStore, produce } from 'solid-js/store';
|
||||
import { insert, Dynamic } from 'solid-js/web';
|
||||
import type { Lang } from '../lang';
|
||||
|
||||
import pandoc from '../pandoc';
|
||||
import Modal from './components/Modal';
|
||||
import Button from './components/Button';
|
||||
import Setting, { Text, Toggle, ExtraButton, DropDown, TextArea } from './components/Setting';
|
||||
import export_templates from '../export_templates';
|
||||
|
||||
|
||||
const SettingTab = (props: { lang: Lang, plugin: UniversalExportPlugin }) => {
|
||||
const { plugin, lang } = props;
|
||||
const [settings, setSettings0] = createStore(plugin.settings);
|
||||
const [pandocVersion, setPandocVersion] = createSignal<SemVer>();
|
||||
const envVars = createMemo(() => Object.entries(Object.assign({}, getPlatformValue(DEFAULT_ENV), getPlatformValue(settings.env) ?? {})).map(([n, v]) => `${n}="${v}"`).join('\n'));
|
||||
const setSettings: typeof setSettings0 = (...args: unknown[]) => {
|
||||
(setSettings0 as ((...args: unknown[]) => void))(...args);
|
||||
plugin.saveSettings();
|
||||
};
|
||||
const setEnvVars = (envItems: string) => {
|
||||
try {
|
||||
const env: Record<string, string> = {};
|
||||
for (let line of envItems.split('\n')) {
|
||||
line = line.trim();
|
||||
const sepIdx = line.indexOf('=');
|
||||
if (sepIdx > 0) {
|
||||
const name = line.substring(0, sepIdx);
|
||||
let value = line.substring(sepIdx + 1).trim();
|
||||
if (value.startsWith('"') && value.endsWith('"')) {
|
||||
value = value.substring(1, value.length - 1);
|
||||
}
|
||||
env[name] = value;
|
||||
}
|
||||
}
|
||||
setSettings('env', setPlatformValue(settings.env ?? {}, env));
|
||||
} catch (e) {
|
||||
alert(e);
|
||||
}
|
||||
};
|
||||
|
||||
const currentCommandTemplate = createMemo(() => settings.items.find(v => v.name === settings.lastEditName) ?? settings.items.first());
|
||||
const currentEditCommandTemplate = <T extends 'custom' | 'pandoc'>(type?: T) => {
|
||||
const template = currentCommandTemplate();
|
||||
return (type === undefined || type === template.type ? template : undefined) as T extends 'custom' ? CustomExportSetting : T extends 'pandoc' ? PandocExportSetting : ExportSetting;
|
||||
};
|
||||
const customDefaultExportDirectory = createMemo(() => getPlatformValue(settings.customDefaultExportDirectory));
|
||||
|
||||
const updateCurrentEditCommandTemplate = (update: (prev: Partial<ExportSetting>) => void) => {
|
||||
const idx = settings.items.findIndex(v => v.name === settings.lastEditName);
|
||||
setSettings('items', idx === -1 ? 0 : idx, produce(item => {
|
||||
update(item);
|
||||
return item;
|
||||
}));
|
||||
};
|
||||
|
||||
const pandocDescription = createMemo(() => {
|
||||
const version = pandocVersion();
|
||||
if (version) {
|
||||
if (app.vault.config.useMarkdownLinks && version.compare(pandoc.requiredVersion) === -1) {
|
||||
return lang.settingTab.pandocVersionWithWarning(pandoc.requiredVersion)
|
||||
}
|
||||
return lang.settingTab.pandocVersion(version)
|
||||
}
|
||||
return lang.settingTab.pandocNotFound;
|
||||
});
|
||||
|
||||
const [modal, setModal] = createSignal<() => JSX.Element>();
|
||||
|
||||
const AddCommandTemplateModal = () => {
|
||||
type TemplateKey = keyof typeof export_templates;
|
||||
const [templateName, setTemplateName] = createSignal(Object.keys(export_templates)[0] as TemplateKey);
|
||||
const [name, setName] = createSignal<string>();
|
||||
const doAdd = () => {
|
||||
const template = JSON.parse(JSON.stringify(export_templates[templateName()]));
|
||||
template.name = name();
|
||||
batch(() => {
|
||||
setSettings('items', items => [...items, template]);
|
||||
setSettings('lastEditName', template.name);
|
||||
});
|
||||
setModal(undefined);
|
||||
};
|
||||
return <>
|
||||
<Modal app={app} title={lang.settingTab.new} onClose={() => setModal(undefined)}>
|
||||
<Setting name={lang.settingTab.template}>
|
||||
<DropDown
|
||||
options={Object.entries(export_templates).map(([k, v]) => ({ name: v.name, value: k }))}
|
||||
selected={name() ?? templateName()}
|
||||
onChange={(v: TemplateKey) => setTemplateName(v)}
|
||||
/>
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.name}>
|
||||
<Text value={name() ?? ''} onChange={(value) => setName(value)} />
|
||||
</Setting>
|
||||
<div class="modal-button-container">
|
||||
<Button cta={true} onClick={doAdd}>{lang.settingTab.save}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</>;
|
||||
};
|
||||
|
||||
const RenameCommandTemplateModal = () => {
|
||||
const [name, setName] = createSignal(currentEditCommandTemplate().name);
|
||||
const doRename = () => {
|
||||
batch(() => {
|
||||
updateCurrentEditCommandTemplate((v) => v.name = name());
|
||||
setSettings('lastEditName', name());
|
||||
});
|
||||
setModal(undefined);
|
||||
};
|
||||
return <>
|
||||
<Modal app={app} title={lang.settingTab.rename} onClose={() => setModal(undefined)}>
|
||||
<Setting name={lang.settingTab.name}>
|
||||
<Text value={name() ?? ''} onChange={(value) => setName(value)} />
|
||||
</Setting>
|
||||
<div class="modal-button-container">
|
||||
<Button cta={true} onClick={doRename}>{lang.settingTab.add}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</>;
|
||||
};
|
||||
|
||||
const PandocCommandTempateEditBlock = () => {
|
||||
const template = () => currentEditCommandTemplate('pandoc');
|
||||
const updateTemplate = (update: (prev: Partial<PandocExportSetting>) => void) => {
|
||||
updateCurrentEditCommandTemplate(prev => prev.type === 'pandoc' ? update(prev) : undefined);
|
||||
};
|
||||
return <>
|
||||
<Setting name={lang.settingTab.arguments}>
|
||||
<Text style="width: 100%" value={template().arguments ?? ''} onChange={(value) => updateTemplate(v => v.arguments = value)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.extraArguments}>
|
||||
<Text style="width: 100%" value={template().customArguments ?? ''} title={template().customArguments} onChange={(value) => updateTemplate(v => v.customArguments = value)} />
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.afterExport} heading={true} />
|
||||
<Setting name={lang.settingTab.openExportedFileLocation}>
|
||||
<Toggle checked={template().openExportedFileLocation ?? false} onChange={(checked) => updateTemplate(v => v.openExportedFileLocation = checked)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.openExportedFile}>
|
||||
<Toggle checked={template().openExportedFile ?? false} onChange={(checked) => updateTemplate(v => v.openExportedFile = checked)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.runCommand}>
|
||||
<Toggle checked={template().runCommand} onChange={(checked) => updateTemplate(v => v.runCommand = checked)} />
|
||||
</Setting>
|
||||
<Show when={template().runCommand}>
|
||||
<Setting>
|
||||
<Text style="width: 100%" value={template().command ?? ''} onChange={(value) => updateTemplate(v => v.command = value)} />
|
||||
</Setting>
|
||||
</Show>
|
||||
</>;
|
||||
};
|
||||
|
||||
const CustomCommandTempateEditBlock = () => {
|
||||
const template = () => currentEditCommandTemplate('custom');
|
||||
const updateTemplate = (update: (prev: Partial<CustomExportSetting>) => void) => {
|
||||
updateCurrentEditCommandTemplate(prev => prev.type === 'custom' ? update(prev) : undefined);
|
||||
};
|
||||
return <>
|
||||
<Setting name={lang.settingTab.command}>
|
||||
<Text style="width: 100%" value={template().command} onChange={(value) => updateTemplate(v => v.command = value)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.targetFileExtensions}>
|
||||
<Text value={template().targetFileExtensions ?? ''} onChange={(value) => updateTemplate(v => v.targetFileExtensions = value)} />
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.afterExport} heading={true} />
|
||||
<Setting name={lang.settingTab.showCommandOutput} >
|
||||
<Toggle checked={template().showCommandOutput ?? false} onChange={(checked) => updateTemplate(v => v.showCommandOutput = checked)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.openExportedFileLocation}>
|
||||
<Toggle checked={template().openExportedFileLocation ?? false} onChange={(checked) => updateTemplate(v => v.openExportedFileLocation = checked)} />
|
||||
</Setting>
|
||||
<Setting name={lang.settingTab.openExportedFile}>
|
||||
<Toggle checked={template().openExportedFile ?? false} onChange={(checked) => updateTemplate(v => v.openExportedFile = checked)} />
|
||||
</Setting>
|
||||
</>;
|
||||
};
|
||||
|
||||
const resetSettings = async () => {
|
||||
await plugin.resetSettings();
|
||||
setSettings(plugin.settings);
|
||||
};
|
||||
|
||||
const chooseCustomDefaultExportDirectory = async () => {
|
||||
const retval = await ct.remote.dialog.showOpenDialog({
|
||||
defaultPath: customDefaultExportDirectory() ?? ct.remote.app.getPath('documents'),
|
||||
properties: ['createDirectory', 'openDirectory'],
|
||||
});
|
||||
|
||||
if (!retval.canceled && retval.filePaths.length > 0) {
|
||||
setSettings('customDefaultExportDirectory', v => setPlatformValue(v, retval.filePaths[0]));
|
||||
}
|
||||
};
|
||||
|
||||
const choosePandocPath = async () => {
|
||||
const retval = await ct.remote.dialog.showOpenDialog({
|
||||
filters: process.platform == 'win32' ? [{ extensions: ['exe'], name: 'pandoc' }]: undefined,
|
||||
properties: ['openFile'],
|
||||
});
|
||||
|
||||
if (!retval.canceled && retval.filePaths.length > 0) {
|
||||
setSettings('pandocPath', (v) => setPlatformValue(v, retval.filePaths[0]));
|
||||
}
|
||||
};
|
||||
|
||||
createEffect(async () => {
|
||||
try {
|
||||
const env = createEnv(getPlatformValue(settings.env) ?? {});
|
||||
setPandocVersion(await pandoc.getVersion(getPlatformValue(settings.pandocPath), env));
|
||||
} catch {
|
||||
setPandocVersion(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
return <>
|
||||
<Setting name={lang.settingTab.general} heading={true}>
|
||||
<ExtraButton icon='reset' onClick={resetSettings} />
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.pandocPath} description={pandocDescription()}>
|
||||
<Text
|
||||
placeholder={lang.settingTab.pandocPathPlaceholder}
|
||||
value={getPlatformValue(settings.pandocPath) ?? ''}
|
||||
onChange={(value) => setSettings('pandocPath', (v) => setPlatformValue(v, value))}
|
||||
/>
|
||||
<ExtraButton icon="folder" onClick={choosePandocPath} />
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.defaultFolderForExportedFile}>
|
||||
<DropDown options={[
|
||||
{ name: lang.settingTab.auto, value: 'Auto' },
|
||||
{ name: lang.settingTab.sameFolderWithCurrentFile, value: 'Same' },
|
||||
{ name: lang.settingTab.customLocation, value: 'Custom' }
|
||||
]} selected={settings.defaultExportDirectoryMode} onChange={(v: 'Auto' | 'Same' | 'Custom') => setSettings('defaultExportDirectoryMode', v)} />
|
||||
|
||||
</Setting>
|
||||
|
||||
<Show when={settings.defaultExportDirectoryMode === 'Custom'}>
|
||||
<Setting>
|
||||
<Text value={customDefaultExportDirectory() ?? ''} title={customDefaultExportDirectory()} />
|
||||
<ExtraButton icon="folder" onClick={chooseCustomDefaultExportDirectory} />
|
||||
</Setting>
|
||||
</Show>
|
||||
|
||||
<Setting name={lang.settingTab.openExportedFileLocation}>
|
||||
<Toggle
|
||||
checked={settings.openExportedFileLocation}
|
||||
onChange={(v) => setSettings('openExportedFileLocation', v)}
|
||||
/>
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.openExportedFile} >
|
||||
<Toggle
|
||||
checked={settings.openExportedFile}
|
||||
onChange={(v) => setSettings('openExportedFile', v)} />
|
||||
</Setting>
|
||||
|
||||
|
||||
<Setting name={lang.settingTab.ShowExportProgressBar}>
|
||||
<Toggle
|
||||
checked={settings.showExportProgressBar}
|
||||
onChange={(v) => setSettings('showExportProgressBar', v)}
|
||||
/>
|
||||
</Setting>
|
||||
|
||||
<Setting name={lang.settingTab.editCommandTemplate} heading={true} />
|
||||
|
||||
<Setting name={lang.settingTab.chooseCommandTemplate}>
|
||||
<DropDown
|
||||
options={settings.items.map(o => ({ name: o.name, value: o.name }))}
|
||||
selected={settings.lastEditName}
|
||||
onChange={(v) => setSettings('lastEditName', v)}
|
||||
/>
|
||||
<ExtraButton
|
||||
icon="plus"
|
||||
tooltip={lang.settingTab.add}
|
||||
onClick={() => setModal(() => AddCommandTemplateModal)} />
|
||||
<ExtraButton
|
||||
icon="pencil"
|
||||
tooltip={lang.settingTab.rename}
|
||||
onClick={() => setModal(() => RenameCommandTemplateModal)} />
|
||||
<ExtraButton
|
||||
icon="trash"
|
||||
tooltip={lang.settingTab.remove}
|
||||
onClick={() => batch(() => {
|
||||
setSettings('items', (items) => items.filter(n => n.name !== currentEditCommandTemplate()?.name));
|
||||
setSettings('lastEditName', settings.items.first()?.name);
|
||||
})} />
|
||||
</Setting>
|
||||
|
||||
<Switch>
|
||||
<Match when={currentEditCommandTemplate('pandoc')}>
|
||||
<PandocCommandTempateEditBlock />
|
||||
</Match>
|
||||
<Match when={currentEditCommandTemplate('custom')}>
|
||||
<CustomCommandTempateEditBlock />
|
||||
</Match>
|
||||
</Switch>
|
||||
|
||||
|
||||
<Setting name={lang.settingTab.advanced} heading={true} />
|
||||
|
||||
{/* TODO:// optimize UI as https://www.jetbrains.com/help/idea/absolute-path-variables.html */}
|
||||
<Setting name={lang.settingTab.environmentVariables} description={lang.settingTab.environmentVariablesDesc}>
|
||||
<TextArea
|
||||
style='width: 100%;height: 5em'
|
||||
value={envVars()}
|
||||
onChange={setEnvVars}
|
||||
/>
|
||||
</Setting>
|
||||
|
||||
<Show when={modal()}>
|
||||
<Dynamic component={modal()} ref={(el: Node) => document.body.appendChild(el)} />
|
||||
</Show>
|
||||
</>;
|
||||
};
|
||||
|
||||
|
||||
export default class extends PluginSettingTab {
|
||||
plugin: UniversalExportPlugin;
|
||||
#dispose?: () => void;
|
||||
|
||||
public get lang() {
|
||||
return this.plugin.lang;
|
||||
}
|
||||
|
||||
constructor(plugin: UniversalExportPlugin) {
|
||||
super(plugin.app, plugin);
|
||||
this.plugin = plugin;
|
||||
this.name = this.plugin.lang.settingTab.title;
|
||||
}
|
||||
|
||||
display() {
|
||||
this.#dispose = createRoot(dispose => {
|
||||
insert(this.containerEl, <SettingTab plugin={this.plugin} lang={this.lang} />);
|
||||
onCleanup(() => {
|
||||
this.containerEl.empty();
|
||||
});
|
||||
return dispose;
|
||||
});
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.#dispose();
|
||||
}
|
||||
}
|
5
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Button.tsx
vendored
Normal file
5
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Button.tsx
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import type { ParentProps } from 'solid-js/types';
|
||||
|
||||
export default (props: ParentProps<{ cta?: boolean, onClick?: () => void}> ) => {
|
||||
return <button classList={{'mod-cta': props.cta}} onClick={props.onClick}>{props.children}</button>;
|
||||
};
|
12
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Icon.tsx
vendored
Normal file
12
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Icon.tsx
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import { setIcon } from 'obsidian';
|
||||
import type { JSX } from 'solid-js/jsx-runtime';
|
||||
|
||||
export default (props: { name: string, title?: string, class?: string, onClick?: JSX.EventHandlerUnion<HTMLDivElement, MouseEvent> }) => {
|
||||
return <div
|
||||
ref={(el) => setIcon(el, props.name)}
|
||||
class={props.class}
|
||||
classList={{ 'clickable-icon': !!props.onClick }}
|
||||
onClick={props.onClick}
|
||||
title={props.title}
|
||||
/>;
|
||||
};
|
53
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Modal.tsx
vendored
Normal file
53
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Modal.tsx
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
import { App, Modal } from 'obsidian';
|
||||
import { JSX, createEffect, onCleanup, onMount } from 'solid-js';
|
||||
import { insert } from 'solid-js/web';
|
||||
|
||||
export default (props: {
|
||||
app: App,
|
||||
title?: JSX.Element,
|
||||
children: JSX.Element,
|
||||
classList?: {
|
||||
[k: string]: boolean;
|
||||
},
|
||||
hidden?: boolean,
|
||||
onClose?: () => void
|
||||
}) => {
|
||||
const modal = new Modal(props.app);
|
||||
let classes: string[] = [];
|
||||
let clean = false;
|
||||
createEffect(() => {
|
||||
insert(modal.titleEl, () => props.title);
|
||||
});
|
||||
createEffect(() => {
|
||||
insert(modal.contentEl, () => props.children);
|
||||
});
|
||||
createEffect(() => {
|
||||
const newClasses = Object.entries(props.classList ?? {}).filter(([, v]) => v).map(([k,]) => k);
|
||||
if (classes.length > 0) {
|
||||
modal.containerEl.removeClasses(classes);
|
||||
}
|
||||
if (newClasses.length > 0) {
|
||||
modal.containerEl.addClasses(newClasses);
|
||||
}
|
||||
classes = newClasses;
|
||||
});
|
||||
createEffect(() => {
|
||||
modal.containerEl.style.display = props.hidden ? 'None' : '';
|
||||
});
|
||||
|
||||
modal.onClose = () => {
|
||||
if (clean) return;
|
||||
clean = true;
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
onMount(() => modal.open());
|
||||
|
||||
onCleanup(() => {
|
||||
if (!clean) {
|
||||
modal.close();
|
||||
}
|
||||
});
|
||||
|
||||
return document.createTextNode('');
|
||||
};
|
36
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/ProgressBar.tsx
vendored
Normal file
36
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/ProgressBar.tsx
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import { createRoot, onCleanup } from 'solid-js';
|
||||
import { insert } from 'solid-js/web';
|
||||
|
||||
const ProgressBar = (props: { message: string, ref: HTMLDivElement }) => {
|
||||
return <>
|
||||
<div ref={props.ref} class="progress-bar">
|
||||
<div class="progress-bar-message u-center-text">{props.message}</div>
|
||||
<div class="progress-bar-indicator">
|
||||
<div class="progress-bar-line"></div>
|
||||
<div class="progress-bar-subline" style="display: none;"></div>
|
||||
<div class="progress-bar-subline mod-increase"></div>
|
||||
<div class="progress-bar-subline mod-decrease"></div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
const show = (message: string) => createRoot(dispose => {
|
||||
let disposed = false;
|
||||
const cleanup = () => {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
dispose();
|
||||
};
|
||||
let el: HTMLDivElement;
|
||||
insert(document.body, () => <ProgressBar ref={el} message={message} />);
|
||||
onCleanup(() => {
|
||||
el instanceof Node && document.body.contains(el) && document.body.removeChild(el);
|
||||
});
|
||||
return cleanup;
|
||||
});
|
||||
|
||||
|
||||
export default { show }
|
155
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/PropertyGrid.tsx
vendored
Normal file
155
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/PropertyGrid.tsx
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
import { FileFilter, remote } from 'electron';
|
||||
import { For, JSX, createEffect, createSignal, untrack } from 'solid-js';
|
||||
import Setting, { Toggle, DropDown, Text, ExtraButton } from './Setting';
|
||||
|
||||
|
||||
const editors = {
|
||||
checkbox: (props: { meta: CheckboxMeta, onChange?: (value: unknown) => void }) => {
|
||||
return <>
|
||||
<Setting name={props.meta.title} description={props.meta.description}>
|
||||
<Toggle checked={getDefaultValue(props.meta)} onChange={props.onChange} />
|
||||
</Setting>
|
||||
</>;
|
||||
},
|
||||
textInput: (props: { meta: TextInputMeta, onChange?: (value: unknown) => void }) => {
|
||||
return <>
|
||||
<Setting name={props.meta.title} description={props.meta.description}>
|
||||
<Text value={getDefaultValue(props.meta)} onChange={props.onChange} />
|
||||
</Setting>
|
||||
</>;
|
||||
},
|
||||
dropdown: (props: { meta: DropDownMeta, onChange?: (value: unknown) => void }) => {
|
||||
return <>
|
||||
<Setting name={props.meta.title} description={props.meta.description}>
|
||||
<DropDown selected={getDefaultValue(props.meta)} options={props.meta.options} onChange={(v) => props.onChange(v)} />
|
||||
</Setting>
|
||||
</>;
|
||||
},
|
||||
fileSelectDialog: (props: { meta: FileSelectDialogMeta, onChange?: (value: unknown) => void }) => {
|
||||
const [filePath, setFilePath] = createSignal<string>(getDefaultValue(props.meta));
|
||||
|
||||
const chooseFile = async () => {
|
||||
const retval = await remote.dialog.showOpenDialog({
|
||||
properties: ['openFile'],
|
||||
filters: props.meta.filters
|
||||
});
|
||||
|
||||
if (!retval.canceled && retval.filePaths.length > 0) {
|
||||
setFilePath(retval.filePaths[0]);
|
||||
props.onChange && props.onChange(untrack(filePath));
|
||||
}
|
||||
};
|
||||
|
||||
return <>
|
||||
<Setting name={props.meta.title} description={props.meta.description}>
|
||||
<Text value={filePath() ?? ''} readOnly={true} />
|
||||
<ExtraButton icon='folder' onClick={chooseFile} />
|
||||
</Setting>
|
||||
</>;
|
||||
}
|
||||
};
|
||||
|
||||
const getdefaultEditor = (meta: AnyPropertyGridControl, onChange?: (value: unknown) => void) => {
|
||||
switch (meta.type) {
|
||||
case 'checkbox': {
|
||||
const E = editors[meta.type];
|
||||
return <E meta={meta} onChange={onChange} />;
|
||||
}
|
||||
case 'dropdown': {
|
||||
const E = editors[meta.type];
|
||||
return <E meta={meta} onChange={onChange} />;
|
||||
}
|
||||
case 'textInput': {
|
||||
const E = editors[meta.type];
|
||||
return <E meta={meta} onChange={onChange} />;
|
||||
}
|
||||
case 'fileSelectDialog': {
|
||||
const E = editors[meta.type];
|
||||
return <E meta={meta} onChange={onChange} />;
|
||||
}
|
||||
default:
|
||||
return <div>Unsupported {JSON.stringify(meta)} </div>;
|
||||
}
|
||||
};
|
||||
|
||||
export interface PropertyGridControlMeta<T = unknown> {
|
||||
title: string,
|
||||
description?: string,
|
||||
default?: T | (() => T)
|
||||
}
|
||||
|
||||
export interface FileSelectDialogMeta extends PropertyGridControlMeta<string> {
|
||||
type: 'fileSelectDialog',
|
||||
filters?: FileFilter[]
|
||||
}
|
||||
|
||||
export interface DropDownMeta extends PropertyGridControlMeta<string> {
|
||||
type: 'dropdown',
|
||||
options: {
|
||||
name?: string,
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface CheckboxMeta extends PropertyGridControlMeta<boolean> {
|
||||
type: 'checkbox'
|
||||
|
||||
}
|
||||
|
||||
export interface TextInputMeta extends PropertyGridControlMeta<string> {
|
||||
type: 'textInput'
|
||||
}
|
||||
|
||||
export type AnyPropertyGridControl = DropDownMeta | CheckboxMeta | TextInputMeta | FileSelectDialogMeta;
|
||||
|
||||
|
||||
export type PropertyGridMeta = {
|
||||
[k: string]: AnyPropertyGridControl
|
||||
}
|
||||
|
||||
export type PropertyGridProps = {
|
||||
meta: PropertyGridMeta,
|
||||
value?: Record<string, unknown>,
|
||||
customEditor?: (meta: AnyPropertyGridControl, onChange?: (value: unknown) => void) => JSX.Element | undefined,
|
||||
onChange?: (value: Record<string, unknown>, key: string) => void
|
||||
}
|
||||
|
||||
|
||||
export default (props: PropertyGridProps) => {
|
||||
|
||||
let obj: Record<string, unknown> = {};
|
||||
createEffect(() => obj = props.value ?? createDefaultObject(props.meta));
|
||||
|
||||
const onChange = (key: string, value: unknown) => {
|
||||
obj[key] = value;
|
||||
props.onChange && props.onChange(obj, key);
|
||||
};
|
||||
|
||||
const createEditor = (key: string, meta: AnyPropertyGridControl) => {
|
||||
const onValueChange = (value: unknown) => onChange(key, value);
|
||||
let editor: JSX.Element | undefined = undefined;
|
||||
if (props.customEditor) {
|
||||
editor = props.customEditor(meta, onValueChange);
|
||||
if (editor) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
return getdefaultEditor(meta, onValueChange);
|
||||
};
|
||||
|
||||
return <>
|
||||
<For each={Object.entries(props.meta)}>
|
||||
{([key, meta]) => createEditor(key, meta)}
|
||||
</For>
|
||||
</>;
|
||||
};
|
||||
|
||||
export const createDefaultObject = (meta: PropertyGridMeta): Record<string, unknown> => {
|
||||
return Object.fromEntries(Object.entries(meta).map(([k, m]) => [k, getDefaultValue(m)]));
|
||||
};
|
||||
|
||||
const getDefaultValue = <T, M extends PropertyGridControlMeta<T>>(meta: M) => {
|
||||
if (meta.default) {
|
||||
return meta.default instanceof Function ? meta.default() : meta.default;
|
||||
}
|
||||
};
|
124
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Setting.tsx
vendored
Normal file
124
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/components/Setting.tsx
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
import { For, JSX, createContext, onCleanup, onMount, useContext } from 'solid-js';
|
||||
import * as Ob from 'obsidian';
|
||||
|
||||
type SettingContext = {
|
||||
settingEl: HTMLDivElement
|
||||
}
|
||||
|
||||
const Context = createContext<SettingContext>();
|
||||
|
||||
const useSetting = () => useContext(Context);
|
||||
|
||||
export default (props: {
|
||||
name?: string,
|
||||
description?: string,
|
||||
class?: string,
|
||||
heading?: boolean,
|
||||
disabled?: boolean,
|
||||
noInfo?: boolean,
|
||||
children?: JSX.Element
|
||||
}) => {
|
||||
const context: SettingContext = {
|
||||
settingEl: null
|
||||
};
|
||||
return <>
|
||||
<Context.Provider value={context}>
|
||||
<div
|
||||
ref={(el) => context.settingEl = el}
|
||||
class={`setting-item ${props.class ?? ''}`.trimEnd()}
|
||||
classList={{
|
||||
'setting-item-heading': props.heading,
|
||||
'is-disable': props.disabled
|
||||
}}>
|
||||
<div class="setting-item-info">
|
||||
<div class="setting-item-name">{props.name}</div>
|
||||
<div class="setting-item-description">{props.description}</div>
|
||||
</div>
|
||||
<div class="setting-item-control">
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
</Context.Provider>
|
||||
</>;
|
||||
};
|
||||
|
||||
|
||||
export const Toggle = (props: { checked?: boolean, onChange?: (checked: boolean) => void }) => {
|
||||
const setting = useSetting();
|
||||
onMount(() => {
|
||||
setting.settingEl.addClass('mod-toggle');
|
||||
});
|
||||
onCleanup(() => {
|
||||
setting.settingEl.removeClass('mod-toggle');
|
||||
});
|
||||
return <>
|
||||
<div class="checkbox-container" classList={{ 'is-enabled': props.checked }} onClick={() => props.onChange && props.onChange(!props.checked)} >
|
||||
<input type="checkbox" />
|
||||
</div>
|
||||
</>;
|
||||
};
|
||||
|
||||
|
||||
export const ExtraButton = (props: { icon?: string, onClick?: () => void, tooltip?: string }) => {
|
||||
return <div
|
||||
ref={(el) => props.icon && Ob.setIcon(el, props.icon)}
|
||||
class="setting-editor-extra-setting-button"
|
||||
classList={{ 'clickable-icon': props.icon && !!props.onClick }}
|
||||
aria-label={props.tooltip}
|
||||
onClick={props.onClick}
|
||||
/>;
|
||||
};
|
||||
|
||||
|
||||
export const Text = (props: { placeholder?: string,
|
||||
title?: string,
|
||||
value?: string,
|
||||
style?: string,
|
||||
disabled?: boolean,
|
||||
readOnly?: boolean,
|
||||
spellcheck?: boolean,
|
||||
onChange?: (value: string) => void }) => {
|
||||
return <input
|
||||
type="text"
|
||||
title={props.title}
|
||||
readOnly={props.readOnly}
|
||||
placeholder={props.placeholder}
|
||||
spellcheck={props.spellcheck ?? false}
|
||||
style={props.style}
|
||||
value={props.value}
|
||||
onChange={(e) => props.onChange?.(e.target.value)}
|
||||
disabled={props.disabled}
|
||||
/>;
|
||||
};
|
||||
|
||||
export const TextArea = (props: { placeholder?: string,
|
||||
title?: string,
|
||||
value?: string,
|
||||
style?: string,
|
||||
disabled?: boolean,
|
||||
spellcheck?: boolean,
|
||||
onChange?: (value: string) => void }) => {
|
||||
return <textarea
|
||||
placeholder={props.placeholder}
|
||||
spellcheck={props.spellcheck ?? false}
|
||||
style={props.style}
|
||||
value={props.value}
|
||||
onChange={(e) => props.onChange?.(e.target.value)}
|
||||
disabled={props.disabled}
|
||||
/>;
|
||||
};
|
||||
|
||||
|
||||
export const DropDown = (props: {
|
||||
options: { name?: string, value: string }[],
|
||||
selected?: string,
|
||||
onChange?: (value: string, index: number) => void
|
||||
}) => {
|
||||
return <>
|
||||
<select class="dropdown" onChange={(e) => props.onChange?.(e.target.value, e.target.selectedIndex)} autofocus={true}>
|
||||
<For each={props.options}>
|
||||
{(item) => <option value={item.value} selected={item.value === props.selected}>{item.name ?? item.value}</option>}
|
||||
</For>
|
||||
</select>
|
||||
</>;
|
||||
};
|
6
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/index.tsx
vendored
Normal file
6
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/index.tsx
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import ExportDialog from './ExportDialog';
|
||||
import ExportSettingTab from './SettingTab';
|
||||
|
||||
export {
|
||||
ExportDialog, ExportSettingTab
|
||||
};
|
158
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/export_dialog.ts
vendored
Normal file
158
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/export_dialog.ts
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
import { App, Modal, Setting, TFile, TextComponent } from 'obsidian';
|
||||
import * as ct from 'electron';
|
||||
import { extractDefaultExtension as extractExtension } from '../../settings';
|
||||
import { setPlatformValue, getPlatformValue } from '../../utils';
|
||||
import { exportToOo } from '../../exporto0o';
|
||||
import { setTooltip, setVisible } from './setting_tab';
|
||||
import type UniversalExportPlugin from '../../main';
|
||||
|
||||
export class ExportDialog extends Modal {
|
||||
readonly plugin: UniversalExportPlugin;
|
||||
readonly currentFile: TFile;
|
||||
get lang() {
|
||||
return this.plugin.lang;
|
||||
}
|
||||
constructor(app: App, plugin: UniversalExportPlugin, currentFile: TFile) {
|
||||
super(app);
|
||||
this.plugin = plugin;
|
||||
this.currentFile = currentFile;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const {
|
||||
titleEl,
|
||||
contentEl,
|
||||
currentFile,
|
||||
plugin: { settings: globalSetting },
|
||||
lang,
|
||||
} = this;
|
||||
|
||||
const exportDirectoryMode = globalSetting.defaultExportDirectoryMode;
|
||||
|
||||
let exportType = globalSetting.lastExportType ?? globalSetting.items.first()?.name;
|
||||
|
||||
let setting = globalSetting.items.find(o => o.name === exportType);
|
||||
let extension = extractExtension(setting);
|
||||
|
||||
let showOverwriteConfirmation = globalSetting.showOverwriteConfirmation;
|
||||
let candidateOutputDirectory = `${getPlatformValue(globalSetting.lastExportDirectory) ?? ct.remote.app.getPath('documents')}`;
|
||||
let candidateOutputFileName = `${currentFile.basename}${extension}`;
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let candidateOutputFileNameSetting: Setting;
|
||||
|
||||
if (exportDirectoryMode === 'Same') {
|
||||
const fullPath: string = this.app.vault.adapter.getFullPath(currentFile.path);
|
||||
candidateOutputDirectory = fullPath.substring(0, fullPath.length - currentFile.name.length - 1);
|
||||
} else if (exportDirectoryMode === 'Custom') {
|
||||
candidateOutputDirectory = getPlatformValue(globalSetting.customDefaultExportDirectory);
|
||||
}
|
||||
|
||||
titleEl.setText(lang.exportDialog.title(setting.name));
|
||||
|
||||
new Setting(contentEl).setName(lang.exportDialog.type).addDropdown(cb => {
|
||||
cb.addOptions(Object.fromEntries(globalSetting.items.map(o => [o.name, o.name])))
|
||||
.onChange(v => {
|
||||
exportType = v;
|
||||
setting = globalSetting.items.find(o => o.name === exportType);
|
||||
titleEl.setText(lang.exportDialog.title(setting.name));
|
||||
|
||||
extension = extractExtension(setting);
|
||||
if (candidateOutputFileName.includes('.')) {
|
||||
candidateOutputFileName = candidateOutputFileName.substring(0, candidateOutputFileName.lastIndexOf('.')) + extension;
|
||||
} else {
|
||||
candidateOutputFileName = candidateOutputFileName + extension;
|
||||
}
|
||||
(candidateOutputFileNameSetting.components.first() as TextComponent)
|
||||
?.setValue(candidateOutputFileName)
|
||||
.inputEl.setAttribute('title', candidateOutputFileName);
|
||||
})
|
||||
.setValue(exportType);
|
||||
});
|
||||
|
||||
candidateOutputFileNameSetting = new Setting(contentEl).setName(lang.exportDialog.fileName).addText(cb => {
|
||||
cb.setValue(candidateOutputFileName)
|
||||
.onChange(v => {
|
||||
candidateOutputFileName = v;
|
||||
setTooltip(cb.inputEl, v);
|
||||
})
|
||||
.inputEl.setAttribute('title', candidateOutputFileName);
|
||||
});
|
||||
|
||||
const candidateOutputDirectorySetting = new Setting(contentEl)
|
||||
.setName(lang.exportDialog.exportTo)
|
||||
.addText(cb => {
|
||||
cb.setValue(candidateOutputDirectory).onChange(v => {
|
||||
candidateOutputDirectory = v;
|
||||
setTooltip(cb.inputEl, candidateOutputDirectory);
|
||||
});
|
||||
cb.setDisabled(true);
|
||||
setTooltip(cb.inputEl, candidateOutputDirectory);
|
||||
})
|
||||
.addExtraButton(cb => {
|
||||
cb.setIcon('folder').onClick(async () => {
|
||||
const retval = await ct.remote.dialog.showOpenDialog({
|
||||
title: lang.exportDialog.selectExportFolder,
|
||||
defaultPath: candidateOutputDirectory,
|
||||
properties: ['createDirectory', 'openDirectory'],
|
||||
});
|
||||
if (!retval.canceled && retval.filePaths?.length > 0) {
|
||||
candidateOutputDirectory = retval.filePaths[0];
|
||||
(candidateOutputDirectorySetting.components.first() as TextComponent)
|
||||
?.setValue(candidateOutputDirectory)
|
||||
.inputEl.setAttribute('title', candidateOutputDirectory);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(contentEl).setName(lang.exportDialog.overwriteConfirmation).addToggle(cb => {
|
||||
cb.setValue(showOverwriteConfirmation).onChange(v => (showOverwriteConfirmation = v));
|
||||
});
|
||||
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: lang.exportDialog.export,
|
||||
cls: ['mod-cta'],
|
||||
parent: el,
|
||||
}).onclick = async () => {
|
||||
await exportToOo(
|
||||
this.plugin,
|
||||
currentFile,
|
||||
candidateOutputDirectory,
|
||||
candidateOutputFileName,
|
||||
setting,
|
||||
showOverwriteConfirmation,
|
||||
async () => {
|
||||
globalSetting.showOverwriteConfirmation = showOverwriteConfirmation;
|
||||
globalSetting.lastExportDirectory = setPlatformValue(globalSetting.lastExportDirectory, candidateOutputDirectory);
|
||||
|
||||
globalSetting.lastExportType = setting.name;
|
||||
await this.plugin.saveSettings();
|
||||
this.close();
|
||||
},
|
||||
() => {
|
||||
setVisible(this.containerEl, true);
|
||||
},
|
||||
() => {
|
||||
setVisible(this.containerEl, false);
|
||||
}
|
||||
);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
const show = (plugin: UniversalExportPlugin, currentFile: TFile) => {
|
||||
const dialog = new ExportDialog(plugin.app, plugin, currentFile);
|
||||
dialog.open();
|
||||
return () => dialog.close();
|
||||
};
|
||||
|
||||
export default {
|
||||
show,
|
||||
};
|
4
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/index.ts
vendored
Normal file
4
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/index.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import ExportDialog from './export_dialog';
|
||||
import ExportSettingTab from './setting_tab';
|
||||
|
||||
export { ExportDialog, ExportSettingTab };
|
573
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/setting_tab.ts
vendored
Normal file
573
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/legacy/setting_tab.ts
vendored
Normal file
@ -0,0 +1,573 @@
|
||||
import { App, PluginSettingTab, Setting, TextComponent } from 'obsidian';
|
||||
import * as ct from 'electron';
|
||||
import { CustomExportSetting, ExportSetting, PandocExportSetting, UniversalExportPluginSettings } from '../../settings';
|
||||
import { setPlatformValue, getPlatformValue } from '../../utils';
|
||||
import pandoc from '../../pandoc';
|
||||
|
||||
import { Modal } from 'obsidian';
|
||||
import export_command_templates from '../../export_templates';
|
||||
import type ExportSettingTab from './setting_tab';
|
||||
import type UniversalExportPlugin from '../../main';
|
||||
|
||||
export default class extends PluginSettingTab {
|
||||
plugin: UniversalExportPlugin;
|
||||
|
||||
public get lang() {
|
||||
return this.plugin.lang;
|
||||
}
|
||||
|
||||
constructor(plugin: UniversalExportPlugin) {
|
||||
super(plugin.app, plugin);
|
||||
this.plugin = plugin;
|
||||
this.name = this.plugin.lang.settingTab.title;
|
||||
}
|
||||
|
||||
hide() {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
}
|
||||
display(): void {
|
||||
const { containerEl, lang, plugin } = this;
|
||||
containerEl.empty();
|
||||
const validateCallback = (v: unknown, k: keyof typeof t, t: unknown): boolean => {
|
||||
const sv = t[k];
|
||||
if (v === sv) {
|
||||
return false;
|
||||
}
|
||||
// noinspection RedundantIfStatementJS
|
||||
if (k !== 'lastEditName' && sv === undefined && (v === false || v === '')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const changedCallback = async (v: unknown, k: keyof typeof t, t: unknown) => {
|
||||
if (v !== undefined) {
|
||||
if (v === false || (typeof v === 'string' && v.trim() === '')) {
|
||||
delete t[k];
|
||||
}
|
||||
}
|
||||
await plugin.saveSettings();
|
||||
};
|
||||
|
||||
const globalSettingWatcher = new Watcher<UniversalExportPluginSettings>({
|
||||
onChangingCallback: validateCallback,
|
||||
onChangedCallback: changedCallback,
|
||||
});
|
||||
|
||||
const settingWatcher = new Watcher<ExportSetting>({
|
||||
onChangingCallback: validateCallback,
|
||||
onChangedCallback: changedCallback,
|
||||
});
|
||||
const pandocSettingWatcher = settingWatcher.as<PandocExportSetting>();
|
||||
const customSettingWatcher = settingWatcher.as<CustomExportSetting>();
|
||||
|
||||
let globalSetting = new Proxy(plugin.settings, globalSettingWatcher);
|
||||
let current = new Proxy(
|
||||
globalSetting.items.find(v => v.name === globalSetting.lastEditName) ?? globalSetting.items.first(),
|
||||
settingWatcher
|
||||
);
|
||||
|
||||
const changeEditExportSetting = (name: string) => {
|
||||
const newSetting = globalSetting.items.find(v => v.name === name) ?? globalSetting.items.first();
|
||||
if (globalSetting.lastEditName !== newSetting.name) {
|
||||
globalSetting.lastEditName = newSetting.name;
|
||||
}
|
||||
if (newSetting) {
|
||||
current = new Proxy(newSetting, settingWatcher);
|
||||
settingWatcher.fireChanged(current);
|
||||
}
|
||||
};
|
||||
|
||||
containerEl.createEl('h2', { text: lang.settingTab.title });
|
||||
|
||||
// General
|
||||
new Setting(containerEl)
|
||||
.setName(lang.settingTab.general)
|
||||
.addExtraButton(cb => {
|
||||
cb.setIcon('reset')
|
||||
.setTooltip(lang.settingTab.reset)
|
||||
.onClick(async () => {
|
||||
await this.plugin.resetSettings();
|
||||
|
||||
globalSetting = new Proxy(plugin.settings, globalSettingWatcher);
|
||||
globalSettingWatcher.fireChanged(globalSetting);
|
||||
|
||||
changeEditExportSetting(globalSetting.lastEditName);
|
||||
});
|
||||
})
|
||||
.setHeading();
|
||||
|
||||
const pandocPathSetting = new Setting(containerEl);
|
||||
pandoc
|
||||
.getVersion(getPlatformValue(globalSetting.pandocPath))
|
||||
.then(ver => {
|
||||
pandocPathSetting.setDesc(lang.settingTab.pandocVersion(ver.version));
|
||||
})
|
||||
.catch(() => {
|
||||
pandocPathSetting.setDesc(lang.settingTab.pandocNotFound);
|
||||
});
|
||||
|
||||
pandocPathSetting.setName(lang.settingTab.pandocPath).addText(cb => {
|
||||
cb.setPlaceholder(lang.settingTab.pandocPathPlaceholder).onChange(v => {
|
||||
if (globalSetting.pandocPath !== v) {
|
||||
globalSetting.pandocPath = setPlatformValue(globalSetting.pandocPath, v);
|
||||
pandoc
|
||||
.getVersion(getPlatformValue(globalSetting.pandocPath))
|
||||
.then(ver => {
|
||||
pandocPathSetting.setDesc(lang.settingTab.pandocVersion(ver.version));
|
||||
})
|
||||
.catch(() => {
|
||||
pandocPathSetting.setDesc(lang.settingTab.pandocNotFound);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
globalSettingWatcher.watchOnChanged('pandocPath', value => {
|
||||
cb.setValue(getPlatformValue(value) ?? '');
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.defaultFolderForExportedFile).addDropdown(cb => {
|
||||
cb.addOptions({
|
||||
'Auto': lang.settingTab.auto,
|
||||
'Same': lang.settingTab.sameFolderWithCurrentFile,
|
||||
'Custom': lang.settingTab.customLocation,
|
||||
}).onChange((v: 'Auto' | 'Same' | 'Custom') => {
|
||||
if (globalSetting.defaultExportDirectoryMode !== v) {
|
||||
globalSetting.defaultExportDirectoryMode = v;
|
||||
}
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('defaultExportDirectoryMode', (value: 'Auto' | 'Same' | 'Custom') => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
});
|
||||
|
||||
const customDefaultExportDirectorySetting = new Setting(containerEl)
|
||||
.addText(cb => {
|
||||
globalSettingWatcher.watchOnChanged('customDefaultExportDirectory', (value?) => {
|
||||
const val = getPlatformValue(value);
|
||||
cb.setValue(val ?? '');
|
||||
setTooltip(cb.inputEl, val);
|
||||
});
|
||||
})
|
||||
.setClass('ex-setting-item')
|
||||
.addExtraButton(cb => {
|
||||
cb.setIcon('folder').onClick(async () => {
|
||||
const retval = await ct.remote.dialog.showOpenDialog({
|
||||
defaultPath: getPlatformValue(globalSetting.customDefaultExportDirectory) ?? ct.remote.app.getPath('documents'),
|
||||
properties: ['createDirectory', 'openDirectory'],
|
||||
});
|
||||
|
||||
if (!retval.canceled && retval.filePaths.length > 0) {
|
||||
globalSetting.customDefaultExportDirectory = setPlatformValue(globalSetting.customDefaultExportDirectory, retval.filePaths[0]);
|
||||
}
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('customDefaultExportDirectory', value => {
|
||||
const text = customDefaultExportDirectorySetting.components.first() as TextComponent;
|
||||
const val = getPlatformValue(value);
|
||||
text.setValue(val ?? '');
|
||||
setTooltip(text.inputEl, val);
|
||||
});
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('defaultExportDirectoryMode', value => {
|
||||
setVisible(customDefaultExportDirectorySetting.settingEl, value === 'Custom');
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.openExportedFileLocation).addToggle(cb => {
|
||||
cb.onChange(v => {
|
||||
if (globalSetting.openExportedFileLocation !== v) {
|
||||
globalSetting.openExportedFileLocation = v;
|
||||
}
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('openExportedFileLocation', v => {
|
||||
cb.setValue(v);
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.openExportedFile).addToggle(cb => {
|
||||
cb.onChange(v => {
|
||||
if (globalSetting.openExportedFile !== v) {
|
||||
globalSetting.openExportedFile = v;
|
||||
}
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('openExportedFile', v => {
|
||||
cb.setValue(v);
|
||||
});
|
||||
});
|
||||
|
||||
// settings for export type
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.editCommandTemplate).setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(lang.settingTab.chooseCommandTemplate)
|
||||
.addDropdown(cb => {
|
||||
cb.onChange(v => {
|
||||
if (globalSetting.lastEditName !== v) {
|
||||
changeEditExportSetting(v);
|
||||
}
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('items', (value: ExportSetting[]) => {
|
||||
cb.selectEl.empty();
|
||||
cb.addOptions(Object.fromEntries(value.map(o => [o.name, o.name])));
|
||||
cb.setValue(globalSetting.lastEditName ?? globalSetting.items.first()?.name);
|
||||
});
|
||||
globalSettingWatcher.watchOnChanged('lastEditName', value => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
})
|
||||
.addExtraButton(button => {
|
||||
button.setTooltip(lang.settingTab.add);
|
||||
button.setIcon('plus');
|
||||
button.onClick(() => {
|
||||
new AddNewModal(this.app, this, s => {
|
||||
globalSetting.items = [...globalSetting.items, s];
|
||||
changeEditExportSetting(s.name);
|
||||
}).open();
|
||||
});
|
||||
})
|
||||
.addExtraButton(button => {
|
||||
button.setTooltip(lang.settingTab.rename);
|
||||
button.setIcon('pencil');
|
||||
button.onClick(() => {
|
||||
new RenemeModal(this.app, this, current, n => {
|
||||
current.name = n;
|
||||
globalSetting.items = [...globalSetting.items];
|
||||
changeEditExportSetting(n);
|
||||
}).open();
|
||||
});
|
||||
})
|
||||
.addExtraButton(button => {
|
||||
button.setTooltip(lang.settingTab.remove);
|
||||
button.setIcon('trash');
|
||||
button.onClick(() => {
|
||||
globalSetting.items = globalSetting.items.filter(o => o.name != current.name);
|
||||
changeEditExportSetting(globalSetting.items.first()?.name);
|
||||
});
|
||||
});
|
||||
|
||||
const commandSetting = new Setting(containerEl).setName(lang.settingTab.command).addText(cb => {
|
||||
cb.setDisabled(true);
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'custom' && current.command !== v) {
|
||||
current.command = v;
|
||||
}
|
||||
});
|
||||
customSettingWatcher.watchOnChanged('command', value => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
cb.setDisabled(value !== 'custom');
|
||||
});
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
setVisible(commandSetting.settingEl, value === 'custom');
|
||||
});
|
||||
|
||||
const argumentsSetting = new Setting(containerEl).setName(lang.settingTab.arguments).addText(cb => {
|
||||
cb.setDisabled(true);
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'pandoc' && current.arguments !== v) {
|
||||
current.arguments = v;
|
||||
setTooltip(cb.inputEl, current.arguments);
|
||||
}
|
||||
});
|
||||
pandocSettingWatcher.watchOnChanged('arguments', value => {
|
||||
cb.setValue(value ?? '');
|
||||
setTooltip(cb.inputEl, value);
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
cb.setDisabled(value !== 'custom');
|
||||
});
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
setVisible(argumentsSetting.settingEl, value === 'pandoc');
|
||||
});
|
||||
|
||||
const targetFileExtensionsSetting = new Setting(containerEl).setName(lang.settingTab.targetFileExtensions).addText(cb => {
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'custom' && current.targetFileExtensions !== v) {
|
||||
current.targetFileExtensions = v;
|
||||
}
|
||||
});
|
||||
|
||||
customSettingWatcher.watchOnChanged('targetFileExtensions', value => {
|
||||
cb.setValue(value ?? '');
|
||||
});
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
setVisible(targetFileExtensionsSetting.settingEl, value === 'custom');
|
||||
});
|
||||
|
||||
const customArgumentsSetting = new Setting(containerEl).setName(lang.settingTab.extraArguments).addText(cb => {
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'pandoc' && current.customArguments !== v) {
|
||||
current.customArguments = v;
|
||||
}
|
||||
});
|
||||
pandocSettingWatcher.watchOnChanged('customArguments', value => {
|
||||
cb.setValue(value ?? '');
|
||||
setTooltip(cb.inputEl, value);
|
||||
});
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
setVisible(customArgumentsSetting.settingEl, value === 'pandoc');
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.afterExport).setHeading();
|
||||
|
||||
const showCommandOutputSetting = new Setting(containerEl).setName(lang.settingTab.showCommandOutput).addToggle(cb => {
|
||||
if (current.type === 'custom') {
|
||||
cb.setValue(current.showCommandOutput);
|
||||
}
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'custom' && current.showCommandOutput !== v) {
|
||||
current.showCommandOutput = v;
|
||||
}
|
||||
});
|
||||
});
|
||||
settingWatcher.watchOnChanged('type', value => {
|
||||
setVisible(showCommandOutputSetting.settingEl, value === 'custom');
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.openExportedFileLocation).addToggle(cb => {
|
||||
cb.onChange(v => {
|
||||
if (current.openExportedFileLocation !== v) {
|
||||
current.openExportedFileLocation = v;
|
||||
}
|
||||
});
|
||||
|
||||
settingWatcher.watchOnChanged('openExportedFileLocation', value => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName(lang.settingTab.runCommand).addToggle(cb => {
|
||||
cb.onChange(v => {
|
||||
if (current.type === 'pandoc' && current.runCommand !== v) {
|
||||
current.runCommand = v;
|
||||
}
|
||||
});
|
||||
pandocSettingWatcher.watchOnChanged('runCommand', value => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
});
|
||||
|
||||
const commandAfterExportSetting = new Setting(containerEl).addText(cb => {
|
||||
cb.onChange(v => {
|
||||
if (current.command !== v) {
|
||||
current.command = v;
|
||||
}
|
||||
});
|
||||
|
||||
pandocSettingWatcher.watchOnChanged('command', value => {
|
||||
cb.setValue(value);
|
||||
});
|
||||
|
||||
pandocSettingWatcher.watchOnChanged('runCommand', (value, _, target) => {
|
||||
setVisible(commandAfterExportSetting.settingEl, target.type === 'pandoc' && value);
|
||||
cb.setValue(current.command);
|
||||
});
|
||||
});
|
||||
globalSettingWatcher.fireChanged(globalSetting);
|
||||
settingWatcher.fireChanged(current);
|
||||
}
|
||||
}
|
||||
|
||||
class AddNewModal extends Modal {
|
||||
readonly settingTab: ExportSettingTab;
|
||||
readonly callback: (setting: ExportSetting) => void;
|
||||
get lang() {
|
||||
return this.settingTab.lang;
|
||||
}
|
||||
constructor(app: App, settingTab: ExportSettingTab, callback: (setting: ExportSetting) => void) {
|
||||
super(app);
|
||||
this.settingTab = settingTab;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl, titleEl, lang, callback } = this;
|
||||
titleEl.setText(lang.settingTab.new);
|
||||
let tpl = Object.values(export_command_templates).first();
|
||||
let tplName = tpl.name;
|
||||
let name = tpl.name;
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let nameSetting: Setting;
|
||||
|
||||
new Setting(contentEl).setName(lang.settingTab.template).addDropdown(cb => {
|
||||
cb.addOptions(Object.fromEntries(Object.values(export_command_templates).map(o => [o.name, o.name])))
|
||||
.setValue(tplName)
|
||||
.onChange(v => {
|
||||
tplName = v;
|
||||
name = v;
|
||||
|
||||
(nameSetting.components.first() as TextComponent)?.setValue(name);
|
||||
});
|
||||
});
|
||||
|
||||
nameSetting = new Setting(contentEl).setName(lang.settingTab.name).addText(cb => {
|
||||
cb.setValue(name).onChange(v => (name = v));
|
||||
});
|
||||
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: lang.settingTab.add,
|
||||
cls: ['mod-cta'],
|
||||
parent: el,
|
||||
}).onclick = async () => {
|
||||
tpl = JSON.parse(JSON.stringify(export_command_templates[tplName]));
|
||||
tpl.name = name;
|
||||
callback(tpl);
|
||||
this.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
class RenemeModal extends Modal {
|
||||
private readonly settingTab: ExportSettingTab;
|
||||
private readonly setting: ExportSetting;
|
||||
private readonly callback: (name: string) => void;
|
||||
get lang() {
|
||||
return this.settingTab.lang;
|
||||
}
|
||||
constructor(app: App, settingTab: ExportSettingTab, setting: ExportSetting, callback: (name: string) => void) {
|
||||
super(app);
|
||||
this.settingTab = settingTab;
|
||||
this.setting = setting;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
const { contentEl, titleEl, lang, setting } = this;
|
||||
titleEl.setText(lang.settingTab.rename);
|
||||
|
||||
let name = setting.name;
|
||||
|
||||
new Setting(contentEl).setName(lang.settingTab.name).addText(cb => {
|
||||
cb.setValue(setting.name).onChange(v => (name = v));
|
||||
});
|
||||
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: lang.settingTab.save,
|
||||
cls: ['mod-cta'],
|
||||
parent: el,
|
||||
}).onclick = async () => {
|
||||
// success
|
||||
this.callback(name);
|
||||
this.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
|
||||
type TOnChangingHandler<T extends object, K extends keyof T> = (value: T[K], key: K, target: T) => boolean;
|
||||
type TOnChangedHandler<T extends object, K extends keyof T> = (value: T[K], key: K, target: T) => void;
|
||||
|
||||
export class Watcher<T extends object> {
|
||||
onChanging: { [k in keyof T]?: TOnChangingHandler<T, keyof T>[] };
|
||||
onChanged: { [k in keyof T]?: TOnChangedHandler<T, keyof T>[] };
|
||||
private readonly _onChangingCallback: TOnChangingHandler<T, keyof T>;
|
||||
private readonly _onChangedCallback: TOnChangedHandler<T, keyof T>;
|
||||
constructor(options?: { onChangingCallback?: TOnChangingHandler<T, keyof T>; onChangedCallback?: TOnChangedHandler<T, keyof T> }) {
|
||||
this.onChanging = {};
|
||||
this.onChanged = {};
|
||||
this._onChangingCallback = options?.onChangingCallback ?? (() => true);
|
||||
this._onChangedCallback = options?.onChangedCallback ?? (() => void 0);
|
||||
}
|
||||
as<T extends object>(): Watcher<T> {
|
||||
return this as unknown as Watcher<T>;
|
||||
}
|
||||
watchOnChanging<K extends keyof T>(key: K, handler: TOnChangingHandler<T, K>): void {
|
||||
(this.onChanging[key] ?? (this.onChanging[key] = [])).push(handler);
|
||||
}
|
||||
watchOnChanged<K extends keyof T>(key: K, handler: TOnChangedHandler<T, K>): void {
|
||||
(this.onChanged[key] ?? (this.onChanged[key] = [])).push(handler);
|
||||
}
|
||||
|
||||
set<K extends keyof T>(target: T, key: K, value: T[K]): boolean {
|
||||
if (this._onChangingCallback && this._onChangingCallback(value, key, target) === false) {
|
||||
return false;
|
||||
}
|
||||
const onChangingHandlers = this.onChanging[key];
|
||||
if (onChangingHandlers) {
|
||||
let invalid = false;
|
||||
for (const h of onChangingHandlers) {
|
||||
if (!h(value, key, target)) {
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
if (invalid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The default behavior to store the value
|
||||
target[key] = value;
|
||||
|
||||
const onChangedHandlers = this.onChanged[key];
|
||||
if (onChangedHandlers) {
|
||||
for (const h of onChangedHandlers) {
|
||||
try {
|
||||
h(value, key, target);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._onChangedCallback) {
|
||||
this._onChangedCallback(value, key, target);
|
||||
}
|
||||
|
||||
// Indicate success
|
||||
return true;
|
||||
}
|
||||
|
||||
fireChanged(target: T) {
|
||||
for (const key of Object.keys(this.onChanged)) {
|
||||
const k = key as keyof T;
|
||||
const onChangedHandlers = this.onChanged[k];
|
||||
if (onChangedHandlers) {
|
||||
for (const h of onChangedHandlers) {
|
||||
try {
|
||||
h(target[k], k, target);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setVisible(el: Element, visible: boolean) {
|
||||
if (visible) {
|
||||
el.removeAttribute('hidden');
|
||||
} else {
|
||||
el.setAttribute('hidden', '');
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
export function setTooltip(el: Element, tooltip?: string) {
|
||||
if (tooltip && tooltip.trim() != '') {
|
||||
el.setAttribute('title', tooltip);
|
||||
} else {
|
||||
el.removeAttribute('title');
|
||||
}
|
||||
return el;
|
||||
}
|
110
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/message_box.ts
vendored
Normal file
110
.obsidian/plugins/obsidian-enhancing-export-main/src/ui/message_box.ts
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
import { App, Modal } from 'obsidian';
|
||||
import lang, { Lang } from '../lang';
|
||||
|
||||
export interface MessageBoxOptions {
|
||||
message: string;
|
||||
title?: string;
|
||||
buttons: 'Yes' | 'YesNo' | 'Ok' | 'OkCancel';
|
||||
buttonsLabel?: {
|
||||
yes?: string;
|
||||
no?: string;
|
||||
ok?: string;
|
||||
cancel?: string;
|
||||
};
|
||||
buttonsClass?: {
|
||||
yes?: string;
|
||||
no?: string;
|
||||
ok?: string;
|
||||
cancel?: string;
|
||||
};
|
||||
callback?: {
|
||||
yes?: () => void;
|
||||
no?: () => void;
|
||||
ok?: () => void;
|
||||
cancel?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export class MessageBox extends Modal {
|
||||
readonly options: MessageBoxOptions;
|
||||
readonly lang: Lang;
|
||||
|
||||
constructor(app: App, message: string);
|
||||
constructor(app: App, message: string, title?: string);
|
||||
constructor(app: App, options: MessageBoxOptions);
|
||||
constructor(app: App, options: MessageBoxOptions | string, title?: string) {
|
||||
super(app);
|
||||
this.options = typeof options === 'string' ? { message: options, buttons: 'Ok', title } : options;
|
||||
this.lang = lang.current;
|
||||
}
|
||||
onOpen(): void {
|
||||
const {
|
||||
titleEl,
|
||||
contentEl,
|
||||
lang,
|
||||
options: { message, title, buttons, callback, buttonsLabel: label, buttonsClass },
|
||||
} = this;
|
||||
if (title) {
|
||||
titleEl.setText(title);
|
||||
}
|
||||
contentEl.createDiv({ text: message });
|
||||
switch (buttons) {
|
||||
case 'Yes':
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: label?.yes ?? lang.messageBox.yes,
|
||||
cls: ['mod-cta', buttonsClass?.yes],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.yes);
|
||||
});
|
||||
break;
|
||||
case 'YesNo':
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: label?.yes ?? lang.messageBox.yes,
|
||||
cls: ['mod-cta', buttonsClass?.yes],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.yes);
|
||||
el.createEl('button', {
|
||||
text: label?.no ?? lang.messageBox.no,
|
||||
cls: ['mod-cta', buttonsClass?.no],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.no);
|
||||
});
|
||||
break;
|
||||
case 'Ok':
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: label?.ok ?? lang.messageBox.ok,
|
||||
cls: ['mod-cta', buttonsClass?.no],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.ok);
|
||||
});
|
||||
break;
|
||||
case 'OkCancel':
|
||||
contentEl.createEl('div', { cls: ['modal-button-container'], parent: contentEl }, el => {
|
||||
el.createEl('button', {
|
||||
text: label?.ok ?? lang.messageBox.ok,
|
||||
cls: ['mod-cta', buttonsClass?.ok],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.ok);
|
||||
el.createEl('button', {
|
||||
text: label?.cancel ?? lang.messageBox.cancel,
|
||||
cls: ['mod-cta', buttonsClass?.cancel],
|
||||
parent: el,
|
||||
}).onclick = () => this.call(callback?.cancel);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
private call(callback?: () => void): void {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
127
.obsidian/plugins/obsidian-enhancing-export-main/src/utils.ts
vendored
Normal file
127
.obsidian/plugins/obsidian-enhancing-export-main/src/utils.ts
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
import { ExecOptions, exec as node_exec } from 'child_process';
|
||||
import process from 'process';
|
||||
|
||||
export type PlatformKey = typeof process.platform | '*';
|
||||
|
||||
export type PlatformValue<T> = { [k in PlatformKey]?: T };
|
||||
|
||||
export function setPlatformValue<T>(obj: PlatformValue<T>, value: T, platform?: PlatformKey | PlatformKey[]): PlatformValue<T> {
|
||||
if (typeof value === 'string' && value.trim() === '') {
|
||||
value = undefined;
|
||||
}
|
||||
|
||||
if (platform instanceof Array) {
|
||||
return platform.reduce((o, p) => setPlatformValue(o, value, p), obj);
|
||||
}
|
||||
|
||||
platform ??= process.platform;
|
||||
|
||||
return {
|
||||
...(obj ?? {}),
|
||||
[platform]: value,
|
||||
};
|
||||
}
|
||||
|
||||
export function getPlatformValue<T>(obj: PlatformValue<T>, platform?: PlatformKey): T {
|
||||
obj ??= {};
|
||||
const val = obj[platform ?? process.platform];
|
||||
const all = obj['*'];
|
||||
if (all && typeof all === 'object') {
|
||||
return Object.assign({}, all, val);
|
||||
}
|
||||
return val ?? all;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
export function strTpl(strings: TemplateStringsArray, ...keys: number[]): (...values: any[]) => string {
|
||||
return function (...values) {
|
||||
const dict = values[values.length - 1] || {};
|
||||
const result = [strings[0]];
|
||||
keys.forEach(function (key, i) {
|
||||
const value = Number.isInteger(key) ? values[key] : dict[key];
|
||||
result.push(value, strings[i + 1]);
|
||||
});
|
||||
return result.join('');
|
||||
};
|
||||
}
|
||||
|
||||
export function exec(cmd: string, options?: ExecOptions): Promise<string> {
|
||||
options = options ?? {};
|
||||
return new Promise((resolve, reject) => {
|
||||
node_exec(cmd, options, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
console.error(stdout, error);
|
||||
return;
|
||||
}
|
||||
if (stderr && stderr !== '') {
|
||||
reject(stderr);
|
||||
console.error(stdout, error);
|
||||
return;
|
||||
}
|
||||
if (stdout?.trim().length === 0 && '1' === localStorage.getItem('debug-plugin')) {
|
||||
console.log(stdout);
|
||||
}
|
||||
resolve(stdout);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function joinEnvPath(...paths: string[]) {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
return paths.join(';');
|
||||
default:
|
||||
return paths.join(':');
|
||||
}
|
||||
}
|
||||
|
||||
export function trimQuotes(s: string) {
|
||||
return (s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'")) ? s.substring(1, s.length - 1) : s;
|
||||
}
|
||||
|
||||
/**
|
||||
* render template
|
||||
* @example
|
||||
* renderTemplate('Hi, ${name}', { name: 'John' }) // returns 'Hi, John'
|
||||
* @param template
|
||||
* @param variables
|
||||
* @returns {string}
|
||||
*/
|
||||
export function renderTemplate(template: string, variables: Record<string, unknown> = {}): string {
|
||||
while (true) {
|
||||
try {
|
||||
const keys = Object.keys(variables).filter(isVarName) as Array<keyof typeof variables>;
|
||||
const values = keys.map(k => variables[k]);
|
||||
return new Function(...keys, `{ return \`${template.replaceAll('\\', '\\\\')}\` }`).bind(variables)(...values);
|
||||
} catch (e: unknown) {
|
||||
if (e instanceof ReferenceError && e.message.endsWith('is not defined')) {
|
||||
const name = e.message.substring(0, e.message.indexOf(' '));
|
||||
const value =
|
||||
Object.keys(variables)
|
||||
.filter(n => n.toLowerCase() === name.toLowerCase())
|
||||
.map(n => variables[n])[0] ?? `\${${name}}`;
|
||||
variables[name] = value;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isVarName = (str: string) => {
|
||||
if (typeof str !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str.trim() !== str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
new Function(str, 'var ' + str);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
1
.obsidian/plugins/obsidian-enhancing-export-main/src/vite-env.d.ts
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
38
.obsidian/plugins/obsidian-enhancing-export-main/tests/common.ts
vendored
Normal file
38
.obsidian/plugins/obsidian-enhancing-export-main/tests/common.ts
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
import os from 'os';
|
||||
import { exec as execSync, ExecException } from 'child_process';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
|
||||
export async function exec(cmd: string, options: { lineSeparator: '\n' | '\r\n' | '\r' }): Promise<string> {
|
||||
function lineSeparator(s?: string, ls?: '\n' | '\r\n' | '\r') {
|
||||
if (!s || os.EOL === ls || !ls) {
|
||||
return s;
|
||||
}
|
||||
return s.replaceAll(os.EOL, ls);
|
||||
}
|
||||
return await new Promise((resolve, reject) => {
|
||||
execSync(cmd, { encoding: 'utf-8', cwd: module.path }, (e: ExecException, stdout: string, stderr: string) => {
|
||||
if (!e) {
|
||||
resolve(lineSeparator(stdout, options?.lineSeparator));
|
||||
} else {
|
||||
reject(lineSeparator(stderr, options?.lineSeparator));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export const testConversion = async (name: string, filter?: string) => {
|
||||
process.chdir(module.path);
|
||||
const input_file = `./markdowns/${name}.md`;
|
||||
const expect_out = `./markdowns/${name}.out`;
|
||||
let pandoc: string;
|
||||
if (filter) {
|
||||
const lua_script = `../lua/${filter}.lua`;
|
||||
pandoc = `pandoc -s -L ${lua_script} -t native -f markdown "${input_file}" -o -`;
|
||||
} else {
|
||||
pandoc = `pandoc -s -t native -f markdown "${input_file}" -o -`;
|
||||
}
|
||||
const ret = await exec(pandoc, { lineSeparator: '\n'});
|
||||
expect(ret).toBe(await readFile(expect_out, { encoding: 'utf-8', flag: 'r' }));
|
||||
};
|
15
.obsidian/plugins/obsidian-enhancing-export-main/tests/internalLink.spec.ts
vendored
Normal file
15
.obsidian/plugins/obsidian-enhancing-export-main/tests/internalLink.spec.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
import { testConversion } from './common';
|
||||
|
||||
|
||||
test('test basic internal link block parsing', async () => {
|
||||
await testConversion('internal-link-basic', 'markdown');
|
||||
});
|
||||
|
||||
test('test complex internal link block parsing', async () => {
|
||||
await testConversion('internal-link-bullet', 'markdown');
|
||||
});
|
||||
|
||||
test('test basic internal link with description', async () => {
|
||||
await testConversion('internal-link-described', 'markdown');
|
||||
});
|
1
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-basic.md
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-basic.md
vendored
Normal file
@ -0,0 +1 @@
|
||||
[[#Some complex section]]
|
14
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-basic.out
vendored
Normal file
14
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-basic.out
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Para
|
||||
[ Link
|
||||
( "" , [] , [] )
|
||||
[ Str "Some"
|
||||
, Space
|
||||
, Str "complex"
|
||||
, Space
|
||||
, Str "section"
|
||||
]
|
||||
( "#Some-complex-section" , "" )
|
||||
]
|
||||
]
|
3
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-bullet.md
vendored
Normal file
3
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-bullet.md
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
- potato
|
||||
- [[#more complex vegetables]]
|
||||
- cucumber
|
19
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-bullet.out
vendored
Normal file
19
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-bullet.out
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ BulletList
|
||||
[ [ Plain [ Str "potato" ] ]
|
||||
, [ Plain
|
||||
[ Link
|
||||
( "" , [] , [] )
|
||||
[ Str "more"
|
||||
, Space
|
||||
, Str "complex"
|
||||
, Space
|
||||
, Str "vegetables"
|
||||
]
|
||||
( "#more-complex-vegetables" , "" )
|
||||
]
|
||||
]
|
||||
, [ Plain [ Str "cucumber" ] ]
|
||||
]
|
||||
]
|
1
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-described.md
vendored
Normal file
1
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-described.md
vendored
Normal file
@ -0,0 +1 @@
|
||||
[[#Some complex section|with custom description]]
|
14
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-described.out
vendored
Normal file
14
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/internal-link-described.out
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Para
|
||||
[ Link
|
||||
( "" , [] , [] )
|
||||
[ Str "with"
|
||||
, Space
|
||||
, Str "custom"
|
||||
, Space
|
||||
, Str "description"
|
||||
]
|
||||
( "#Some-complex-section" , "" )
|
||||
]
|
||||
]
|
41
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01-no-empty-lines.md
vendored
Normal file
41
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01-no-empty-lines.md
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
$$
|
||||
\left(\begin{array}{c}
|
||||
\hat{F}_{1,i,j}\\ \hat{F}_{2,i,j} \\ \vdots \\ \hat{F}_{C-1,i,j} \\ \hat{F}_{C,i,j}
|
||||
\end{array}\right)
|
||||
=
|
||||
\begin{pmatrix}
|
||||
\frac{\gamma_1}{\sqrt{\hat{\sigma}^2_1}+\epsilon} & 0 & \cdots & &0
|
||||
\\
|
||||
0 && \frac{\gamma_2}{\sqrt{\hat{\sigma}^2_2}+\epsilon} & & & &
|
||||
\\
|
||||
\vdots && \ddots && \vdots
|
||||
\\
|
||||
&&& \frac{\gamma_{C-1}}{\sqrt{\hat{\sigma}^2_{C-1}+\epsilon}} & 0
|
||||
\\
|
||||
0 && \cdots &0 & \frac{\gamma_C}{\sqrt{\hat{\sigma}^2_{C}+\epsilon}}
|
||||
\end{pmatrix}
|
||||
\cdot
|
||||
\begin{pmatrix}
|
||||
F_{1,i,j}
|
||||
\\
|
||||
F_{2,i,j}
|
||||
\\
|
||||
\vdots
|
||||
\\
|
||||
F_{C-1,i,j}
|
||||
\\
|
||||
F_{C,i,j}
|
||||
\end{pmatrix}
|
||||
+
|
||||
\begin{pmatrix}
|
||||
\beta_1-\gamma_1\frac{\hat{\mu}_1}{\sqrt{\hat{\sigma}^2_1+\epsilon}}
|
||||
\\
|
||||
\beta_2-\gamma_2\frac{\hat{\mu}_2}{\sqrt{\hat{\sigma}^2_2+\epsilon}}
|
||||
\\
|
||||
\vdots
|
||||
\\
|
||||
\beta_{C-1}-\gamma_{C-1}\frac{\hat{\mu}_{C-1}}{\sqrt{\hat{\sigma}^2_{C-1}+\epsilon}}
|
||||
\\
|
||||
\beta_C-\gamma_C\frac{\hat{\mu}_C}{\sqrt{\hat{\sigma}^2_C+\epsilon}}
|
||||
\end{pmatrix}
|
||||
$$
|
@ -0,0 +1,8 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Para
|
||||
[ Math
|
||||
DisplayMath
|
||||
"\n\\left(\\begin{array}{c}\n\\hat{F}_{1,i,j}\\\\ \\hat{F}_{2,i,j} \\\\ \\vdots \\\\ \\hat{F}_{C-1,i,j} \\\\ \\hat{F}_{C,i,j}\n\\end{array}\\right)\n=\n\\begin{pmatrix}\n\\frac{\\gamma_1}{\\sqrt{\\hat{\\sigma}^2_1}+\\epsilon} & 0 & \\cdots & &0\n\\\\\n0 && \\frac{\\gamma_2}{\\sqrt{\\hat{\\sigma}^2_2}+\\epsilon} & & & &\n\\\\\n\\vdots && \\ddots && \\vdots\n\\\\\n&&& \\frac{\\gamma_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}} & 0\n\\\\\n0 && \\cdots &0 & \\frac{\\gamma_C}{\\sqrt{\\hat{\\sigma}^2_{C}+\\epsilon}}\n\\end{pmatrix}\n\\cdot\n\\begin{pmatrix}\nF_{1,i,j}\n\\\\\nF_{2,i,j}\n\\\\\n\\vdots\n\\\\\nF_{C-1,i,j}\n\\\\\nF_{C,i,j}\n\\end{pmatrix}\n+\n\\begin{pmatrix}\n\\beta_1-\\gamma_1\\frac{\\hat{\\mu}_1}{\\sqrt{\\hat{\\sigma}^2_1+\\epsilon}}\n\\\\\n\\beta_2-\\gamma_2\\frac{\\hat{\\mu}_2}{\\sqrt{\\hat{\\sigma}^2_2+\\epsilon}}\n\\\\\n\\vdots\n\\\\\n\\beta_{C-1}-\\gamma_{C-1}\\frac{\\hat{\\mu}_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}}\n\\\\\n\\beta_C-\\gamma_C\\frac{\\hat{\\mu}_C}{\\sqrt{\\hat{\\sigma}^2_C+\\epsilon}}\n\\end{pmatrix} \n"
|
||||
]
|
||||
]
|
51
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.md
vendored
Normal file
51
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.md
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
$$
|
||||
\left(\begin{array}{c}
|
||||
\hat{F}_{1,i,j}\\ \hat{F}_{2,i,j} \\ \vdots \\ \hat{F}_{C-1,i,j} \\ \hat{F}_{C,i,j}
|
||||
\end{array}\right)
|
||||
|
||||
=
|
||||
|
||||
\begin{pmatrix}
|
||||
\frac{\gamma_1}{\sqrt{\hat{\sigma}^2_1}+\epsilon} & 0 & \cdots & &0
|
||||
\\
|
||||
0 && \frac{\gamma_2}{\sqrt{\hat{\sigma}^2_2}+\epsilon} & & & &
|
||||
\\
|
||||
\vdots && \ddots && \vdots
|
||||
\\
|
||||
&&& \frac{\gamma_{C-1}}{\sqrt{\hat{\sigma}^2_{C-1}+\epsilon}} & 0
|
||||
\\
|
||||
0 && \cdots &0 & \frac{\gamma_C}{\sqrt{\hat{\sigma}^2_{C}+\epsilon}}
|
||||
|
||||
\end{pmatrix}
|
||||
|
||||
|
||||
\cdot
|
||||
|
||||
\begin{pmatrix}
|
||||
F_{1,i,j}
|
||||
\\
|
||||
F_{2,i,j}
|
||||
\\
|
||||
\vdots
|
||||
\\
|
||||
F_{C-1,i,j}
|
||||
\\
|
||||
|
||||
F_{C,i,j}
|
||||
\end{pmatrix}
|
||||
|
||||
+
|
||||
|
||||
\begin{pmatrix}
|
||||
\beta_1-\gamma_1\frac{\hat{\mu}_1}{\sqrt{\hat{\sigma}^2_1+\epsilon}}
|
||||
\\
|
||||
\beta_2-\gamma_2\frac{\hat{\mu}_2}{\sqrt{\hat{\sigma}^2_2+\epsilon}}
|
||||
\\
|
||||
\vdots
|
||||
\\
|
||||
\beta_{C-1}-\gamma_{C-1}\frac{\hat{\mu}_{C-1}}{\sqrt{\hat{\sigma}^2_{C-1}+\epsilon}}
|
||||
\\
|
||||
\beta_C-\gamma_C\frac{\hat{\mu}_C}{\sqrt{\hat{\sigma}^2_C+\epsilon}}
|
||||
|
||||
\end{pmatrix}
|
||||
$$
|
28
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.orig
vendored
Normal file
28
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.orig
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Plain
|
||||
[ Str "$$"
|
||||
, SoftBreak
|
||||
, RawInline (Format "tex") "\\left"
|
||||
, Str "("
|
||||
]
|
||||
, RawBlock
|
||||
(Format "tex")
|
||||
"\\begin{array}{c}\n\\hat{F}_{1,i,j}\\\\ \\hat{F}_{2,i,j} \\\\ \\vdots \\\\ \\hat{F}_{C-1,i,j} \\\\ \\hat{F}_{C,i,j}\n\\end{array}"
|
||||
, Header
|
||||
1
|
||||
( "section" , [] , [] )
|
||||
[ RawInline (Format "tex") "\\right" , Str ")" ]
|
||||
, RawBlock
|
||||
(Format "tex")
|
||||
"\\begin{pmatrix}\n\\frac{\\gamma_1}{\\sqrt{\\hat{\\sigma}^2_1}+\\epsilon} & 0 & \\cdots & &0\n\\\\\n0 && \\frac{\\gamma_2}{\\sqrt{\\hat{\\sigma}^2_2}+\\epsilon} & & & &\n\\\\\n\\vdots && \\ddots && \\vdots\n\\\\\n&&& \\frac{\\gamma_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}} & 0\n\\\\\n0 && \\cdots &0 & \\frac{\\gamma_C}{\\sqrt{\\hat{\\sigma}^2_{C}+\\epsilon}}\n\n\\end{pmatrix}"
|
||||
, RawBlock (Format "tex") "\\cdot"
|
||||
, RawBlock
|
||||
(Format "tex")
|
||||
"\\begin{pmatrix}\nF_{1,i,j}\n\\\\\nF_{2,i,j}\n\\\\\n\\vdots\n\\\\\nF_{C-1,i,j}\n\\\\\n\nF_{C,i,j}\n\\end{pmatrix}"
|
||||
, BulletList [ [] ]
|
||||
, RawBlock
|
||||
(Format "tex")
|
||||
"\\begin{pmatrix}\n\\beta_1-\\gamma_1\\frac{\\hat{\\mu}_1}{\\sqrt{\\hat{\\sigma}^2_1+\\epsilon}}\n\\\\\n\\beta_2-\\gamma_2\\frac{\\hat{\\mu}_2}{\\sqrt{\\hat{\\sigma}^2_2+\\epsilon}}\n\\\\\n\\vdots\n\\\\\n\\beta_{C-1}-\\gamma_{C-1}\\frac{\\hat{\\mu}_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}}\n\\\\\n\\beta_C-\\gamma_C\\frac{\\hat{\\mu}_C}{\\sqrt{\\hat{\\sigma}^2_C+\\epsilon}}\n\n\\end{pmatrix}"
|
||||
, Para [ Str "$$" ]
|
||||
]
|
11
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.out
vendored
Normal file
11
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block-01.out
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Plain []
|
||||
, Para []
|
||||
, Para []
|
||||
, Para
|
||||
[ Math
|
||||
DisplayMath
|
||||
"\n\\left(\\begin{array}{c}\n\\hat{F}_{1,i,j}\\\\ \\hat{F}_{2,i,j} \\\\ \\vdots \\\\ \\hat{F}_{C-1,i,j} \\\\ \\hat{F}_{C,i,j}\n\\end{array}\\right)=\\begin{pmatrix}\n\\frac{\\gamma_1}{\\sqrt{\\hat{\\sigma}^2_1}+\\epsilon} & 0 & \\cdots & &0\n\\\\\n0 && \\frac{\\gamma_2}{\\sqrt{\\hat{\\sigma}^2_2}+\\epsilon} & & & &\n\\\\\n\\vdots && \\ddots && \\vdots\n\\\\\n&&& \\frac{\\gamma_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}} & 0\n\\\\\n0 && \\cdots &0 & \\frac{\\gamma_C}{\\sqrt{\\hat{\\sigma}^2_{C}+\\epsilon}}\n\n\\end{pmatrix}\\cdot\\begin{pmatrix}\nF_{1,i,j}\n\\\\\nF_{2,i,j}\n\\\\\n\\vdots\n\\\\\nF_{C-1,i,j}\n\\\\\n\nF_{C,i,j}\n\\end{pmatrix}\\begin{pmatrix}\n\\beta_1-\\gamma_1\\frac{\\hat{\\mu}_1}{\\sqrt{\\hat{\\sigma}^2_1+\\epsilon}}\n\\\\\n\\beta_2-\\gamma_2\\frac{\\hat{\\mu}_2}{\\sqrt{\\hat{\\sigma}^2_2+\\epsilon}}\n\\\\\n\\vdots\n\\\\\n\\beta_{C-1}-\\gamma_{C-1}\\frac{\\hat{\\mu}_{C-1}}{\\sqrt{\\hat{\\sigma}^2_{C-1}+\\epsilon}}\n\\\\\n\\beta_C-\\gamma_C\\frac{\\hat{\\mu}_C}{\\sqrt{\\hat{\\sigma}^2_C+\\epsilon}}\n\n\\end{pmatrix}\n"
|
||||
]
|
||||
]
|
13
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.md
vendored
Normal file
13
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
$$
|
||||
\begin{align*}
|
||||
\begin{rcases}
|
||||
\lambda_{1}(a_{11}^{*}, \ldots, a_{22}^{*}) < 0 \\
|
||||
\lambda_{2}(a_{11}^{*}, \ldots, a_{22}^{*}) < 0 \\
|
||||
\end{rcases} & \Rightarrow \text{stable knot} \\
|
||||
|
||||
\begin{rcases}
|
||||
\lambda_{1}(a_{11}^{*}, \ldots, a_{22}^{*}) > 0 \\
|
||||
\lambda_{2}(a_{11}^{*}, \ldots, a_{22}^{*}) < 0 \\
|
||||
\end{rcases} & \Rightarrow \text{saddle}
|
||||
\end{align*}
|
||||
$$
|
12
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.orig
vendored
Normal file
12
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.orig
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Para
|
||||
[ Str "$$"
|
||||
, SoftBreak
|
||||
, RawInline
|
||||
(Format "tex")
|
||||
"\\begin{align*}\n\\begin{rcases}\n\\lambda_{1}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n\\lambda_{2}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n\\end{rcases} & \\Rightarrow \\text{stable knot} \\\\\n\n \\begin{rcases}\n \\lambda_{1}(a_{11}^{*}, \\ldots, a_{22}^{*}) > 0 \\\\\n \\lambda_{2}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n \\end{rcases} & \\Rightarrow \\text{saddle}\n\\end{align*}"
|
||||
, SoftBreak
|
||||
, Str "$$"
|
||||
]
|
||||
]
|
8
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.out
vendored
Normal file
8
.obsidian/plugins/obsidian-enhancing-export-main/tests/markdowns/math-block.out
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
Pandoc
|
||||
Meta { unMeta = fromList [] }
|
||||
[ Para
|
||||
[ Math
|
||||
DisplayMath
|
||||
"\n\\begin{align*}\n\\begin{rcases}\n\\lambda_{1}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n\\lambda_{2}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n\\end{rcases} & \\Rightarrow \\text{stable knot} \\\\\n\n \\begin{rcases}\n \\lambda_{1}(a_{11}^{*}, \\ldots, a_{22}^{*}) > 0 \\\\\n \\lambda_{2}(a_{11}^{*}, \\ldots, a_{22}^{*}) < 0 \\\\\n \\end{rcases} & \\Rightarrow \\text{saddle}\n\\end{align*}\n"
|
||||
]
|
||||
]
|
23
.obsidian/plugins/obsidian-enhancing-export-main/tests/mathBlock.spec.ts
vendored
Normal file
23
.obsidian/plugins/obsidian-enhancing-export-main/tests/mathBlock.spec.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
import { testConversion } from './common';
|
||||
|
||||
|
||||
test('test math-block parsing', async () => {
|
||||
await testConversion('math-block', 'math_block');
|
||||
});
|
||||
|
||||
|
||||
test('test math-block-01 parsing', async () => {
|
||||
await testConversion('math-block-01', 'math_block');
|
||||
});
|
||||
|
||||
test('test math-block-01-no-empty-lines parsing', async () => {
|
||||
await testConversion('math-block-01-no-empty-lines', 'math_block');
|
||||
});
|
||||
|
||||
test('test math-block-01-no-empty-lines parsing filter off', async () => {
|
||||
await testConversion('math-block-01-no-empty-lines');
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
7
.obsidian/plugins/obsidian-enhancing-export-main/tests/pandocVersion.spec.ts
vendored
Normal file
7
.obsidian/plugins/obsidian-enhancing-export-main/tests/pandocVersion.spec.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import pandoc from '../src/pandoc';
|
||||
|
||||
|
||||
test('test get pandoc version', async () => {
|
||||
const out = await pandoc.getVersion();
|
||||
expect(out.compare('3.1.5')).toBe(1);
|
||||
});
|
26
.obsidian/plugins/obsidian-enhancing-export-main/tests/platformValue.spec.ts
vendored
Normal file
26
.obsidian/plugins/obsidian-enhancing-export-main/tests/platformValue.spec.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
import { getPlatformValue, setPlatformValue } from '../src/utils';
|
||||
|
||||
|
||||
test('test get set platformValue 1', async () => {
|
||||
const val = setPlatformValue({}, 'abc');
|
||||
expect(getPlatformValue(val)).toBe('abc');
|
||||
});
|
||||
|
||||
test('test get set platformValue 2', async () => {
|
||||
const val = setPlatformValue({}, 'abc', '*');
|
||||
expect(getPlatformValue(val)).toBe('abc');
|
||||
});
|
||||
|
||||
test('test get set platformValue 3', async () => {
|
||||
let val = setPlatformValue<Record<string, string>>({}, { 'a': 'x' }, '*');
|
||||
val = setPlatformValue(val, { 'b': 'y' });
|
||||
expect(getPlatformValue(val)).toStrictEqual({ 'a': 'x', 'b': 'y' });
|
||||
});
|
||||
|
||||
test('test set platformValue on multi platform', async () => {
|
||||
const val = setPlatformValue<Record<string, string>>({}, { 'a': 'x' }, ['win32', 'darwin']);
|
||||
expect(val).toStrictEqual({
|
||||
'win32': { 'a': 'x' },
|
||||
'darwin': { 'a': 'x' }
|
||||
});
|
||||
});
|
32
.obsidian/plugins/obsidian-enhancing-export-main/tests/renderTemplate.spec.ts
vendored
Normal file
32
.obsidian/plugins/obsidian-enhancing-export-main/tests/renderTemplate.spec.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
import { renderTemplate } from '../src/utils';
|
||||
|
||||
|
||||
test('test Template rendering', async () => {
|
||||
const out = renderTemplate('s${luaDir}e', { luaDir: 'w123' });
|
||||
expect(out).toBe('sw123e');
|
||||
});
|
||||
|
||||
test('test Template rendering 2', async () => {
|
||||
const out = renderTemplate('${HOME}', {
|
||||
'HOME': 'C:\\Users\\Admin',
|
||||
'CommonProgramFiles(x86)': 'C:\\Program Files (x86)\\Common Files',
|
||||
});
|
||||
expect(out).toBe('C:\\Users\\Admin');
|
||||
});
|
||||
|
||||
|
||||
test('test Template rendering options.textemplate', async () => {
|
||||
expect(renderTemplate('pandoc ${ options.textemplate ? `--template="${options.textemplate}"` : `` }',
|
||||
{ options: { textemplate: 'dissertation.tex' } }))
|
||||
.toBe('pandoc --template="dissertation.tex"');
|
||||
|
||||
expect(renderTemplate('pandoc ${ options.textemplate ? `--template="${options.textemplate}"` : `` }',
|
||||
{ options: { textemplate: null } }))
|
||||
.toBe('pandoc ');
|
||||
});
|
||||
|
||||
|
||||
test('test Template rendering with undefined variable', async () => {
|
||||
expect(renderTemplate('Hi ${user}', { }))
|
||||
.toBe('Hi ${user}');
|
||||
});
|
1210
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/dissertation.tex
vendored
Normal file
1210
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/dissertation.tex
vendored
Normal file
File diff suppressed because it is too large
Load Diff
373
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/neurips.sty
vendored
Normal file
373
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/neurips.sty
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
% partial rewrite of the LaTeX2e package for submissions to the
|
||||
% Conference on Neural Information Processing Systems (NeurIPS):
|
||||
%
|
||||
% - uses more LaTeX conventions
|
||||
% - line numbers at submission time replaced with aligned numbers from
|
||||
% lineno package
|
||||
% - \nipsfinalcopy replaced with [final] package option
|
||||
% - automatically loads times package for authors
|
||||
% - loads natbib automatically; this can be suppressed with the
|
||||
% [nonatbib] package option
|
||||
% - adds foot line to first page identifying the conference
|
||||
% - adds preprint option for submission to e.g. arXiv
|
||||
% - conference acronym modified
|
||||
%
|
||||
% Roman Garnett (garnett@wustl.edu) and the many authors of
|
||||
% nips15submit_e.sty, including MK and drstrip@sandia
|
||||
%
|
||||
% last revision: March 2023
|
||||
|
||||
\NeedsTeXFormat{LaTeX2e}
|
||||
\ProvidesPackage{neurips}[2023/03/31 NeurIPS 2023 submission/camera-ready style file]
|
||||
|
||||
% declare final option, which creates camera-ready copy
|
||||
\newif\if@neuripsfinal\@neuripsfinalfalse
|
||||
\DeclareOption{final}{
|
||||
\@neuripsfinaltrue
|
||||
}
|
||||
|
||||
% declare nonatbib option, which does not load natbib in case of
|
||||
% package clash (users can pass options to natbib via
|
||||
% \PassOptionsToPackage)
|
||||
\newif\if@natbib\@natbibtrue
|
||||
\DeclareOption{nonatbib}{
|
||||
\@natbibfalse
|
||||
}
|
||||
|
||||
% declare preprint option, which creates a preprint version ready for
|
||||
% upload to, e.g., arXiv
|
||||
\newif\if@preprint\@preprintfalse
|
||||
\DeclareOption{preprint}{
|
||||
\@preprinttrue
|
||||
}
|
||||
|
||||
\ProcessOptions\relax
|
||||
|
||||
% determine whether this is an anonymized submission
|
||||
\newif\if@submission\@submissiontrue
|
||||
\if@neuripsfinal\@submissionfalse\fi
|
||||
\if@preprint\@submissionfalse\fi
|
||||
|
||||
% fonts
|
||||
\renewcommand{\rmdefault}{ptm}
|
||||
\renewcommand{\sfdefault}{phv}
|
||||
|
||||
% change this every year for notice string at bottom
|
||||
\newcommand{\@neuripsordinal}{}
|
||||
\newcommand{\@neuripsyear}{\the\year}
|
||||
\newcommand{\@neuripslocation}{}
|
||||
|
||||
% acknowledgments
|
||||
\usepackage{environ}
|
||||
\newcommand{\acksection}{\section*{Acknowledgments and Disclosure of Funding}}
|
||||
\NewEnviron{ack}{%
|
||||
\acksection
|
||||
\BODY
|
||||
}
|
||||
|
||||
|
||||
% load natbib unless told otherwise
|
||||
\if@natbib
|
||||
\RequirePackage{natbib}
|
||||
\fi
|
||||
|
||||
% set page geometry
|
||||
\usepackage[verbose=true,letterpaper]{geometry}
|
||||
\AtBeginDocument{
|
||||
\newgeometry{
|
||||
textheight=9in,
|
||||
textwidth=5.5in,
|
||||
top=1in,
|
||||
headheight=12pt,
|
||||
headsep=25pt,
|
||||
footskip=30pt
|
||||
}
|
||||
\@ifpackageloaded{fullpage}
|
||||
{\PackageWarning{neurips_2023}{fullpage package not allowed! Overwriting formatting.}}
|
||||
{}
|
||||
}
|
||||
|
||||
\widowpenalty=10000
|
||||
\clubpenalty=10000
|
||||
\flushbottom
|
||||
\sloppy
|
||||
|
||||
|
||||
% font sizes with reduced leading
|
||||
\renewcommand{\normalsize}{%
|
||||
\@setfontsize\normalsize\@xpt\@xipt
|
||||
\abovedisplayskip 7\p@ \@plus 2\p@ \@minus 5\p@
|
||||
\abovedisplayshortskip \z@ \@plus 3\p@
|
||||
\belowdisplayskip \abovedisplayskip
|
||||
\belowdisplayshortskip 4\p@ \@plus 3\p@ \@minus 3\p@
|
||||
}
|
||||
\normalsize
|
||||
\renewcommand{\small}{%
|
||||
\@setfontsize\small\@ixpt\@xpt
|
||||
\abovedisplayskip 6\p@ \@plus 1.5\p@ \@minus 4\p@
|
||||
\abovedisplayshortskip \z@ \@plus 2\p@
|
||||
\belowdisplayskip \abovedisplayskip
|
||||
\belowdisplayshortskip 3\p@ \@plus 2\p@ \@minus 2\p@
|
||||
}
|
||||
\renewcommand{\footnotesize}{\@setfontsize\footnotesize\@ixpt\@xpt}
|
||||
\renewcommand{\scriptsize}{\@setfontsize\scriptsize\@viipt\@viiipt}
|
||||
\renewcommand{\tiny}{\@setfontsize\tiny\@vipt\@viipt}
|
||||
\renewcommand{\large}{\@setfontsize\large\@xiipt{14}}
|
||||
\renewcommand{\Large}{\@setfontsize\Large\@xivpt{16}}
|
||||
\renewcommand{\LARGE}{\@setfontsize\LARGE\@xviipt{20}}
|
||||
\renewcommand{\huge}{\@setfontsize\huge\@xxpt{23}}
|
||||
\renewcommand{\Huge}{\@setfontsize\Huge\@xxvpt{28}}
|
||||
|
||||
% sections with less space
|
||||
\providecommand{\section}{}
|
||||
\renewcommand{\section}{%
|
||||
\@startsection{section}{1}{\z@}%
|
||||
{-2.0ex \@plus -0.5ex \@minus -0.2ex}%
|
||||
{ 1.5ex \@plus 0.3ex \@minus 0.2ex}%
|
||||
{\large\bf\raggedright}%
|
||||
}
|
||||
\providecommand{\subsection}{}
|
||||
\renewcommand{\subsection}{%
|
||||
\@startsection{subsection}{2}{\z@}%
|
||||
{-1.8ex \@plus -0.5ex \@minus -0.2ex}%
|
||||
{ 0.8ex \@plus 0.2ex}%
|
||||
{\normalsize\bf\raggedright}%
|
||||
}
|
||||
\providecommand{\subsubsection}{}
|
||||
\renewcommand{\subsubsection}{%
|
||||
\@startsection{subsubsection}{3}{\z@}%
|
||||
{-1.5ex \@plus -0.5ex \@minus -0.2ex}%
|
||||
{ 0.5ex \@plus 0.2ex}%
|
||||
{\normalsize\bf\raggedright}%
|
||||
}
|
||||
\providecommand{\paragraph}{}
|
||||
\renewcommand{\paragraph}{%
|
||||
\@startsection{paragraph}{4}{\z@}%
|
||||
{1.5ex \@plus 0.5ex \@minus 0.2ex}%
|
||||
{-1em}%
|
||||
{\normalsize\bf}%
|
||||
}
|
||||
\providecommand{\subparagraph}{}
|
||||
\renewcommand{\subparagraph}{%
|
||||
\@startsection{subparagraph}{5}{\z@}%
|
||||
{1.5ex \@plus 0.5ex \@minus 0.2ex}%
|
||||
{-1em}%
|
||||
{\normalsize\bf}%
|
||||
}
|
||||
\providecommand{\subsubsubsection}{}
|
||||
\renewcommand{\subsubsubsection}{%
|
||||
\vskip5pt{\noindent\normalsize\rm\raggedright}%
|
||||
}
|
||||
|
||||
% float placement
|
||||
\renewcommand{\topfraction }{0.85}
|
||||
\renewcommand{\bottomfraction }{0.4}
|
||||
\renewcommand{\textfraction }{0.1}
|
||||
\renewcommand{\floatpagefraction}{0.7}
|
||||
|
||||
\newlength{\@neuripsabovecaptionskip}\setlength{\@neuripsabovecaptionskip}{7\p@}
|
||||
\newlength{\@neuripsbelowcaptionskip}\setlength{\@neuripsbelowcaptionskip}{\z@}
|
||||
|
||||
\setlength{\abovecaptionskip}{\@neuripsabovecaptionskip}
|
||||
\setlength{\belowcaptionskip}{\@neuripsbelowcaptionskip}
|
||||
|
||||
% swap above/belowcaptionskip lengths for tables
|
||||
\renewenvironment{table}
|
||||
{\setlength{\abovecaptionskip}{\@neuripsbelowcaptionskip}%
|
||||
\setlength{\belowcaptionskip}{\@neuripsabovecaptionskip}%
|
||||
\@float{table}}
|
||||
{\end@float}
|
||||
|
||||
% footnote formatting
|
||||
\setlength{\footnotesep }{6.65\p@}
|
||||
\setlength{\skip\footins}{9\p@ \@plus 4\p@ \@minus 2\p@}
|
||||
\renewcommand{\footnoterule}{\kern-3\p@ \hrule width 12pc \kern 2.6\p@}
|
||||
\setcounter{footnote}{0}
|
||||
|
||||
% paragraph formatting
|
||||
\setlength{\parindent}{\z@}
|
||||
\setlength{\parskip }{5.5\p@}
|
||||
|
||||
% list formatting
|
||||
\setlength{\topsep }{4\p@ \@plus 1\p@ \@minus 2\p@}
|
||||
\setlength{\partopsep }{1\p@ \@plus 0.5\p@ \@minus 0.5\p@}
|
||||
\setlength{\itemsep }{2\p@ \@plus 1\p@ \@minus 0.5\p@}
|
||||
\setlength{\parsep }{2\p@ \@plus 1\p@ \@minus 0.5\p@}
|
||||
\setlength{\leftmargin }{3pc}
|
||||
\setlength{\leftmargini }{\leftmargin}
|
||||
\setlength{\leftmarginii }{2em}
|
||||
\setlength{\leftmarginiii}{1.5em}
|
||||
\setlength{\leftmarginiv }{1.0em}
|
||||
\setlength{\leftmarginv }{0.5em}
|
||||
\def\@listi {\leftmargin\leftmargini}
|
||||
\def\@listii {\leftmargin\leftmarginii
|
||||
\labelwidth\leftmarginii
|
||||
\advance\labelwidth-\labelsep
|
||||
\topsep 2\p@ \@plus 1\p@ \@minus 0.5\p@
|
||||
\parsep 1\p@ \@plus 0.5\p@ \@minus 0.5\p@
|
||||
\itemsep \parsep}
|
||||
\def\@listiii{\leftmargin\leftmarginiii
|
||||
\labelwidth\leftmarginiii
|
||||
\advance\labelwidth-\labelsep
|
||||
\topsep 1\p@ \@plus 0.5\p@ \@minus 0.5\p@
|
||||
\parsep \z@
|
||||
\partopsep 0.5\p@ \@plus 0\p@ \@minus 0.5\p@
|
||||
\itemsep \topsep}
|
||||
\def\@listiv {\leftmargin\leftmarginiv
|
||||
\labelwidth\leftmarginiv
|
||||
\advance\labelwidth-\labelsep}
|
||||
\def\@listv {\leftmargin\leftmarginv
|
||||
\labelwidth\leftmarginv
|
||||
\advance\labelwidth-\labelsep}
|
||||
\def\@listvi {\leftmargin\leftmarginvi
|
||||
\labelwidth\leftmarginvi
|
||||
\advance\labelwidth-\labelsep}
|
||||
|
||||
% create title
|
||||
\providecommand{\maketitle}{}
|
||||
\renewcommand{\maketitle}{%
|
||||
\par
|
||||
\begingroup
|
||||
\renewcommand{\thefootnote}{\fnsymbol{footnote}}
|
||||
% for perfect author name centering
|
||||
\renewcommand{\@makefnmark}{\hbox to \z@{$^{\@thefnmark}$\hss}}
|
||||
% The footnote-mark was overlapping the footnote-text,
|
||||
% added the following to fix this problem (MK)
|
||||
\long\def\@makefntext##1{%
|
||||
\parindent 1em\noindent
|
||||
\hbox to 1.8em{\hss $\m@th ^{\@thefnmark}$}##1
|
||||
}
|
||||
\thispagestyle{empty}
|
||||
\@maketitle
|
||||
\@thanks
|
||||
\@notice
|
||||
\endgroup
|
||||
\let\maketitle\relax
|
||||
\let\thanks\relax
|
||||
}
|
||||
|
||||
% rules for title box at top of first page
|
||||
\newcommand{\@toptitlebar}{
|
||||
\hrule height 4\p@
|
||||
\vskip 0.25in
|
||||
\vskip -\parskip%
|
||||
}
|
||||
\newcommand{\@bottomtitlebar}{
|
||||
\vskip 0.29in
|
||||
\vskip -\parskip
|
||||
\hrule height 1\p@
|
||||
\vskip 0.09in%
|
||||
}
|
||||
|
||||
% create title (includes both anonymized and non-anonymized versions)
|
||||
\providecommand{\@maketitle}{}
|
||||
\renewcommand{\@maketitle}{%
|
||||
\vbox{%
|
||||
\hsize\textwidth
|
||||
\linewidth\hsize
|
||||
\vskip 0.1in
|
||||
\@toptitlebar
|
||||
\centering
|
||||
{\LARGE\bf \@title\par}
|
||||
\@bottomtitlebar
|
||||
\if@submission
|
||||
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}
|
||||
Anonymous Author(s) \\
|
||||
Affiliation \\
|
||||
Address \\
|
||||
\texttt{email} \\
|
||||
\end{tabular}%
|
||||
\else
|
||||
\def\And{%
|
||||
\end{tabular}\hfil\linebreak[0]\hfil%
|
||||
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\ignorespaces%
|
||||
}
|
||||
\def\AND{%
|
||||
\end{tabular}\hfil\linebreak[4]\hfil%
|
||||
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\ignorespaces%
|
||||
}
|
||||
\begin{tabular}[t]{c}\bf\rule{\z@}{24\p@}\@author\end{tabular}%
|
||||
\fi
|
||||
\vskip 0.3in \@minus 0.1in
|
||||
}
|
||||
}
|
||||
|
||||
% add conference notice to bottom of first page
|
||||
\newcommand{\ftype@noticebox}{8}
|
||||
\newcommand{\@notice}{%
|
||||
% give a bit of extra room back to authors on first page
|
||||
\enlargethispage{2\baselineskip}%
|
||||
\@float{noticebox}[b]%
|
||||
\footnotesize\@noticestring%
|
||||
\end@float%
|
||||
}
|
||||
|
||||
% abstract styling
|
||||
\renewenvironment{abstract}%
|
||||
{%
|
||||
\vskip 0.075in%
|
||||
\centerline%
|
||||
{\large\bf Abstract}%
|
||||
\vspace{0.5ex}%
|
||||
\begin{quote}%
|
||||
}
|
||||
{
|
||||
\par%
|
||||
\end{quote}%
|
||||
\vskip 1ex%
|
||||
}
|
||||
|
||||
% handle tweaks for camera-ready copy vs. submission copy
|
||||
\if@preprint
|
||||
\newcommand{\@noticestring}{%
|
||||
Preprint. Under review.%
|
||||
}
|
||||
\else
|
||||
\if@neuripsfinal
|
||||
\newcommand{\@noticestring}{%
|
||||
(\@neuripsyear) \@title
|
||||
}
|
||||
\else
|
||||
\newcommand{\@noticestring}{%
|
||||
(\@neuripsyear) \@title %
|
||||
}
|
||||
|
||||
% hide the acknowledgements
|
||||
\NewEnviron{hide}{}
|
||||
\let\ack\hide
|
||||
\let\endack\endhide
|
||||
|
||||
% line numbers for submission
|
||||
\RequirePackage{lineno}
|
||||
\linenumbers
|
||||
|
||||
% fix incompatibilities between lineno and amsmath, if required, by
|
||||
% transparently wrapping linenomath environments around amsmath
|
||||
% environments
|
||||
\AtBeginDocument{%
|
||||
\@ifpackageloaded{amsmath}{%
|
||||
\newcommand*\patchAmsMathEnvironmentForLineno[1]{%
|
||||
\expandafter\let\csname old#1\expandafter\endcsname\csname #1\endcsname
|
||||
\expandafter\let\csname oldend#1\expandafter\endcsname\csname end#1\endcsname
|
||||
\renewenvironment{#1}%
|
||||
{\linenomath\csname old#1\endcsname}%
|
||||
{\csname oldend#1\endcsname\endlinenomath}%
|
||||
}%
|
||||
\newcommand*\patchBothAmsMathEnvironmentsForLineno[1]{%
|
||||
\patchAmsMathEnvironmentForLineno{#1}%
|
||||
\patchAmsMathEnvironmentForLineno{#1*}%
|
||||
}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{equation}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{align}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{flalign}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{alignat}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{gather}%
|
||||
\patchBothAmsMathEnvironmentsForLineno{multline}%
|
||||
}
|
||||
{}
|
||||
}
|
||||
\fi
|
||||
\fi
|
||||
|
||||
|
||||
\endinput
|
159
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/neurips.tex
vendored
Normal file
159
.obsidian/plugins/obsidian-enhancing-export-main/textemplate/neurips.tex
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
\documentclass{article}
|
||||
|
||||
|
||||
% if you need to pass options to natbib, use, e.g.:
|
||||
% \PassOptionsToPackage{numbers, compress}{natbib}
|
||||
% before loading neurips_2023
|
||||
|
||||
|
||||
% ready for submission
|
||||
\usepackage[final]{neurips}
|
||||
|
||||
|
||||
% to compile a preprint version, e.g., for submission to arXiv, add add the
|
||||
% [preprint] option:
|
||||
% \usepackage[preprint]{neurips_2023}
|
||||
|
||||
|
||||
% to compile a camera-ready version, add the [final] option, e.g.:
|
||||
% \usepackage[final]{neurips_2023}
|
||||
|
||||
|
||||
% to avoid loading the natbib package, add option nonatbib:
|
||||
% \usepackage[nonatbib]{neurips_2023}
|
||||
|
||||
|
||||
\usepackage[utf8]{inputenc} % allow utf-8 input
|
||||
\usepackage[T1]{fontenc} % use 8-bit T1 fonts
|
||||
\usepackage{hyperref} % hyperlinks
|
||||
\usepackage{url} % simple URL typesetting
|
||||
\usepackage{booktabs} % professional-quality tables
|
||||
\usepackage{amsfonts} % blackboard math symbols
|
||||
\usepackage{nicefrac} % compact symbols for 1/2, etc.
|
||||
\usepackage{microtype} % microtypography
|
||||
\usepackage{xcolor} % colors
|
||||
\usepackage{graphicx}
|
||||
|
||||
\makeatletter
|
||||
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
|
||||
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
|
||||
\makeatother
|
||||
% Scale images if necessary, so that they will not overflow the page
|
||||
% margins by default, and it is still possible to overwrite the defaults
|
||||
% using explicit options in \includegraphics[width, height, ...]{}
|
||||
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
|
||||
% Set default figure placement to htbp
|
||||
\makeatletter
|
||||
\def\fps@figure{htbp}
|
||||
\makeatother
|
||||
|
||||
$if(csl-refs)$
|
||||
\newlength{\cslhangindent}
|
||||
\setlength{\cslhangindent}{1.5em}
|
||||
\newlength{\csllabelwidth}
|
||||
\setlength{\csllabelwidth}{3em}
|
||||
\newlength{\cslentryspacingunit} % times entry-spacing
|
||||
\setlength{\cslentryspacingunit}{\parskip}
|
||||
\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
|
||||
{% don't indent paragraphs
|
||||
\setlength{\parindent}{0pt}
|
||||
% turn on hanging indent if param 1 is 1
|
||||
\ifodd #1
|
||||
\let\oldpar\par
|
||||
\def\par{\hangindent=\cslhangindent\oldpar}
|
||||
\fi
|
||||
% set entry spacing
|
||||
\setlength{\parskip}{#2\cslentryspacingunit}
|
||||
}%
|
||||
{}
|
||||
\usepackage{calc}
|
||||
\newcommand{\CSLBlock}[1]{#1\hfill\break}
|
||||
\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
|
||||
\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
|
||||
\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
|
||||
$endif$
|
||||
\providecommand{\tightlist}{%
|
||||
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
|
||||
\title{$title$}
|
||||
|
||||
|
||||
% Iterate through the authors except last to add \And.
|
||||
|
||||
\author{%
|
||||
$for(authors/allbutlast)$
|
||||
$authors.name$\\$authors.affiliation$\\$authors.institution$\\$authors.email$\\$authors.address$ \And
|
||||
$endfor$
|
||||
$for(authors/last)$
|
||||
$authors.name$\\$authors.affiliation$\\$authors.institution$\\$authors.email$\\$authors.address$
|
||||
$endfor$
|
||||
}
|
||||
|
||||
% \author{%
|
||||
% David S.~Hippocampus \\
|
||||
% Department of Computer Science\\
|
||||
% Cranberry-Lemon University\\
|
||||
% Pittsburgh, PA 15213 \\
|
||||
% \texttt{hippo@cs.cranberry-lemon.edu} \\
|
||||
% % examples of more authors
|
||||
% % \And
|
||||
% % Coauthor \\
|
||||
% % Affiliation \\
|
||||
% % Address \\
|
||||
% % \texttt{email} \\
|
||||
% % \AND
|
||||
% % Coauthor \\
|
||||
% % Affiliation \\
|
||||
% % Address \\
|
||||
% % \texttt{email} \\
|
||||
% % \And
|
||||
% % Coauthor \\
|
||||
% % Affiliation \\
|
||||
% % Address \\
|
||||
% % \texttt{email} \\
|
||||
% % \And
|
||||
% % Coauthor \\
|
||||
% % Affiliation \\
|
||||
% % Address \\
|
||||
% % \texttt{email} \\
|
||||
% }
|
||||
|
||||
|
||||
\begin{document}
|
||||
|
||||
|
||||
\maketitle
|
||||
|
||||
|
||||
\begin{abstract}
|
||||
$if(abstract)$
|
||||
$abstract$
|
||||
$else$
|
||||
Add your abstract at the beginning of your markdown file like this
|
||||
\begin{verbatim}
|
||||
---
|
||||
title: "Your Title"
|
||||
abstract: "your abstract here"
|
||||
authors:
|
||||
- name: Leonardo V. Castorina
|
||||
affiliation: School of Informatics
|
||||
institution: University of Edinburgh
|
||||
email: justanemail@domain.ext
|
||||
address: Edinburgh
|
||||
- name: Coauthor
|
||||
affiliation: Affiliation
|
||||
institution: Institution
|
||||
email: coauthor@example.com
|
||||
address: Address
|
||||
---
|
||||
\end{verbatim}
|
||||
This is called YAML frontmatter. If you set your abstract correctly you should not see this message.
|
||||
$endif$
|
||||
\end{abstract}
|
||||
|
||||
|
||||
$body$
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
\end{document}
|
29
.obsidian/plugins/obsidian-enhancing-export-main/tsconfig.json
vendored
Normal file
29
.obsidian/plugins/obsidian-enhancing-export-main/tsconfig.json
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES2021",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"importHelpers": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7",
|
||||
"ES2021"
|
||||
],
|
||||
"typeRoots": [ "./typings", "./node_modules/@types"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts", "**/*.tsx"
|
||||
]
|
||||
}
|
16204
.obsidian/plugins/obsidian-enhancing-export-main/typings/electron.d.ts
vendored
Normal file
16204
.obsidian/plugins/obsidian-enhancing-export-main/typings/electron.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
.obsidian/plugins/obsidian-enhancing-export-main/typings/obsidian.d.ts
vendored
Normal file
34
.obsidian/plugins/obsidian-enhancing-export-main/typings/obsidian.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
import 'obsidian';
|
||||
import type { EventRef } from 'obsidian';
|
||||
|
||||
|
||||
declare module 'obsidian' {
|
||||
|
||||
export interface DataAdapter {
|
||||
getBasePath(): string;
|
||||
getFullPath(path: string): string;
|
||||
startWatchPath(path: string): void;
|
||||
stopWatchPath(path: string): void;
|
||||
}
|
||||
|
||||
export interface PluginSettingTab {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface App {
|
||||
readonly loadProgress: { show(): void; hide(): void; setMessage(msg: string): void; };
|
||||
plugins: {
|
||||
enablePlugin(id: string): Promise<void>;
|
||||
disablePlugin(id: string): Promise<void>;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Vault {
|
||||
config: {
|
||||
attachmentFolderPath: string,
|
||||
useMarkdownLinks: boolean,
|
||||
}
|
||||
on(name: 'raw', callback: (file: string) => void, ctx?: any): EventRef;
|
||||
}
|
||||
}
|
29
.obsidian/plugins/obsidian-enhancing-export-main/version-bump.mjs
vendored
Normal file
29
.obsidian/plugins/obsidian-enhancing-export-main/version-bump.mjs
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { exec } from 'child_process';
|
||||
import process from 'process';
|
||||
|
||||
|
||||
const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
|
||||
|
||||
const version = process.argv.at(2) ?? pkg.version;
|
||||
|
||||
if (version != pkg.version) {
|
||||
pkg.version = version;
|
||||
writeFileSync('package.json', `${JSON.stringify(pkg, null, 2)}\n`);
|
||||
exec('git add package.json');
|
||||
}
|
||||
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync('manifest.json', 'utf8'));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = pkg.version;
|
||||
manifest.description = pkg.description;
|
||||
writeFileSync('manifest.json', JSON.stringify(manifest, null, 2));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync('versions.json', 'utf8'));
|
||||
versions[pkg.version] = minAppVersion;
|
||||
writeFileSync('versions.json', JSON.stringify(versions, null, '\t'));
|
||||
|
||||
exec('git add manifest.json versions.json');
|
53
.obsidian/plugins/obsidian-enhancing-export-main/versions.json
vendored
Normal file
53
.obsidian/plugins/obsidian-enhancing-export-main/versions.json
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
{
|
||||
"1.0.4": "0.12.0",
|
||||
"1.0.5": "0.12.0",
|
||||
"1.0.6": "0.12.0",
|
||||
"1.0.7": "0.12.0",
|
||||
"1.0.8": "0.12.0",
|
||||
"1.0.9": "0.12.0",
|
||||
"1.0.10": "0.12.0",
|
||||
"1.0.11": "0.12.0",
|
||||
"1.1.0": "0.12.0",
|
||||
"1.1.1": "0.12.0",
|
||||
"1.1.2": "0.12.0",
|
||||
"1.1.3": "0.12.0",
|
||||
"1.1.4": "0.12.0",
|
||||
"1.1.5": "0.12.0",
|
||||
"1.1.6": "0.12.0",
|
||||
"1.1.7": "0.12.0",
|
||||
"1.1.8": "0.12.0",
|
||||
"1.1.9": "0.12.0",
|
||||
"1.1.10": "0.12.0",
|
||||
"1.2.0": "0.12.0",
|
||||
"1.2.1": "0.12.0",
|
||||
"1.3.0": "0.12.0",
|
||||
"1.3.1": "0.12.0",
|
||||
"1.4.1": "0.12.0",
|
||||
"1.5.2": "0.12.0",
|
||||
"1.5.3": "0.12.0",
|
||||
"1.5.4": "0.12.0",
|
||||
"1.6.1": "0.12.0",
|
||||
"1.7.1": "0.12.0",
|
||||
"1.7.2": "0.12.0",
|
||||
"1.8.1": "0.12.0",
|
||||
"1.8.2": "0.12.0",
|
||||
"1.8.3": "0.12.0",
|
||||
"1.8.4": "0.12.0",
|
||||
"1.8.5": "0.12.0",
|
||||
"1.8.6": "0.12.0",
|
||||
"1.8.7": "0.12.0",
|
||||
"1.8.8": "0.12.0",
|
||||
"1.9.1": "0.12.0",
|
||||
"1.9.2": "0.12.0",
|
||||
"1.9.3": "0.12.0",
|
||||
"1.9.4": "0.12.0",
|
||||
"1.9.5": "0.12.0",
|
||||
"1.9.6": "0.12.0",
|
||||
"1.10.1": "0.12.0",
|
||||
"1.10.2": "0.12.0",
|
||||
"1.10.3": "0.12.0",
|
||||
"1.10.4": "0.12.0",
|
||||
"1.10.5": "0.12.0",
|
||||
"1.10.6": "1.6.3",
|
||||
"1.10.7": "1.6.3"
|
||||
}
|
143
.obsidian/plugins/obsidian-enhancing-export-main/vite.config.ts
vendored
Normal file
143
.obsidian/plugins/obsidian-enhancing-export-main/vite.config.ts
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
import { exec } from 'child_process';
|
||||
import { defineConfig, loadEnv, Plugin, UserConfig } from 'vite';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||
import solidPlugin from 'vite-plugin-solid';
|
||||
import builtins from 'builtin-modules';
|
||||
import path from 'path';
|
||||
import * as fsp from 'fs/promises';
|
||||
|
||||
|
||||
|
||||
const banner = `
|
||||
/*!
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository https://github.com/mokeyish/obsidian-enhancing-export .
|
||||
*/
|
||||
`;
|
||||
|
||||
|
||||
export default defineConfig(async ({ mode }) => {
|
||||
const { normalize } = path;
|
||||
const { rm } = fsp;
|
||||
const prod = mode === 'production';
|
||||
|
||||
let { OUT_DIR } = loadEnv(mode, process.cwd(), ['OUT_']);
|
||||
|
||||
OUT_DIR = normalize(OUT_DIR);
|
||||
if (OUT_DIR != 'dist' && OUT_DIR != path.join(process.cwd(), 'dist')) {
|
||||
await rm('dist', { recursive: true });
|
||||
exec(process.platform === 'win32' ? `mklink /J dist ${OUT_DIR}` : `ln -s ${OUT_DIR} dist`);
|
||||
}
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
solidPlugin(),
|
||||
viteStaticCopy({
|
||||
targets: [{
|
||||
src: 'manifest.json',
|
||||
dest: '.'
|
||||
}]
|
||||
}),
|
||||
loader({
|
||||
'.lua': 'binary',
|
||||
'.tex': 'binary',
|
||||
'.sty': 'binary'
|
||||
}), // src/resources.ts
|
||||
prod ? undefined : inject(['src/hmr.ts']),
|
||||
],
|
||||
build: {
|
||||
lib: {
|
||||
entry: 'src/main.ts',
|
||||
name: 'main',
|
||||
fileName: () => 'main.js',
|
||||
formats: ['cjs'],
|
||||
},
|
||||
minify: prod,
|
||||
sourcemap: prod ? false : 'inline',
|
||||
cssCodeSplit: false,
|
||||
emptyOutDir: false,
|
||||
// outDir: '',
|
||||
rollupOptions: {
|
||||
output: {
|
||||
exports: 'named',
|
||||
assetFileNames: (v) => v.name === 'style.css' ? 'styles.css' : v.name,
|
||||
banner,
|
||||
},
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
'@lezer/common',
|
||||
'@lezer/highlight',
|
||||
'@lezer/lr',
|
||||
...builtins
|
||||
],
|
||||
},
|
||||
}
|
||||
} as UserConfig;
|
||||
});
|
||||
|
||||
|
||||
const loader = (config: { [extention: string]: 'binary' }): Plugin => {
|
||||
const { extname } = path;
|
||||
return {
|
||||
name: 'binary-boader',
|
||||
enforce: 'pre',
|
||||
async load(id) {
|
||||
const format = config[extname(id)];
|
||||
if (format) {
|
||||
if (format === 'binary') {
|
||||
const buffer = await fsp.readFile(id);
|
||||
return {
|
||||
code: `export default Uint8Array.from(atob('${buffer.toString('base64')}'), c => c.charCodeAt(0));`
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const inject = (files: string[]): Plugin => {
|
||||
if (files && files.length > 0) {
|
||||
return {
|
||||
name: 'inject-code',
|
||||
async load(this, id) {
|
||||
const info = this.getModuleInfo(id);
|
||||
if (info.isEntry) {
|
||||
const code = await fsp.readFile(id, 'utf-8');
|
||||
const { relative, dirname, basename, extname, join } = path;
|
||||
const dir = dirname(id);
|
||||
const inject_code = files
|
||||
.map(v => relative(dir, v))
|
||||
.map(p => join('./', basename(p, extname(p))))
|
||||
.map(p => `import './${p}'`).join(';');
|
||||
return `
|
||||
${inject_code};
|
||||
${code}
|
||||
`;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user