Skip to content

Commit

Permalink
Merge pull request #679 from obgnail/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
obgnail authored Jul 25, 2024
2 parents 25796b8 + f4fe434 commit 5e5c91d
Show file tree
Hide file tree
Showing 22 changed files with 408 additions and 914 deletions.
33 changes: 15 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,30 @@

## 如何使用:方法一(自动)

> 目前此方法仅限 Windows 平台。
> 此方法支持 Windows、Linux 平台。
1. [下载](https://github.com/obgnail/typora_plugin/releases/latest) 插件源码的压缩包,并将其解压

2. 进入 Typora 安装路径,找到包含 `window.html` 的文件夹 A(正式版的路径为 `Typora/resources/window.html`免费版的路径为 `Typora/resources/app/window.html`
2. 进入 Typora 安装路径,找到包含 `window.html` 的文件夹 A(正式版为 `Typora/resources/window.html`免费版为 `Typora/resources/app/window.html`

3. 打开文件夹 A,将解压后的 plugin 文件夹粘贴进该文件夹下(参考方法二的图片)

4. 进入文件夹 `A/plugin/updater/`,双击运行 `updater.exe`。如果看到下图,说明安装成功
4. 进入文件夹 `A/plugin/bin/`

![installer](assets/installer.png)
- 如果你是 Windows 系统,双击运行 `install_windows_amd_x64.exe`,如果看到下图,说明安装成功

- 如果你是 Linux 系统,以管理员运行 `install_linux.sh`,如果看到下图,说明安装成功

5. 验证:重启 Typora,在正文区域点击鼠标右键,弹出右键菜单栏,如果能看到 `常用插件` 栏目,说明一切顺利

> 每个插件皆有配置选项。开发者鼓励您修改配置,以符合自身需求。配置文件夹位于 [A/plugin/global/settings/](https://github.com/obgnail/typora_plugin/tree/master/plugin/global/settings)
| | Windows | Linux |
| ------ | ---------------------------------------------- | ------------------------------------------ |
| 步骤 4 | ![install_windows](assets/install_windows.png) | ![install_linux](assets/install_linux.png) |

附加说明:

- `install_windows.exe` 是提供给非技术用户用的。您也可以通过执行同目录下的 `install_windows.ps1` 安装插件。
- 每个插件皆有配置选项。开发者鼓励您修改配置,以符合自身需求。配置文件夹位于 [A/plugin/global/settings/](https://github.com/obgnail/typora_plugin/tree/master/plugin/global/settings)



Expand Down Expand Up @@ -205,17 +214,7 @@ JSBridge.invoke('executeJavaScript', 1, "_myValue=123; JSBridge.invoke('executeJ

### 如何升级插件?

- 方法一(全自动,仅限 Windows):右键菜单 -> 常用插件 -> 二级插件 -> 升级插件

- 方法二(半自动,仅限 Windows):有些用户将 Typora 装在 C 盘或者 Typora 的安装路径包含 `Program Files` 目录,经常会因为权限问题导致升级失败。此时可以通过以管理员身份打开终端,执行下面命令升级:

```bash
# 注意updater.exe改成你的路径
# proxy参数:你的代理URL。如果你所在地区能直连GitHub,可以删除此参数
D:/software/typora/resources/plugin/updater/updater.exe --action=update --proxy=http://127.0.0.1:7890
```

- 方法三(手动,支持 Windows、Linux):[安装方法二](#如何使用:方法二(手动)) 重新走一遍。
右键菜单 -> 常用插件 -> 二级插件 -> 升级插件



Expand Down Expand Up @@ -396,8 +395,6 @@ COMMANDS = [

### commander:命令行环境

> 有些插件依赖于此插件,不建议禁用。
功能:和 total commander 的命令行一样(快捷键也一样),一个快速执行命令的工具,并提供少量交互。

- `弹出执行框`:ctrl+G
Expand Down
Binary file added assets/install_linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/install_windows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/installer.png
Binary file not shown.
113 changes: 113 additions & 0 deletions plugin/bin/install.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libgen.h>

#ifdef _WIN32
#define PATH_SEPARATOR '\\'
#else
#include <linux/limits.h>
#define PATH_SEPARATOR '/'
#endif

#define APP "app"
#define APP_SRC "appsrc"
#define WINDOW_HTML "window.html"
#define WINDOW_HTML_BAK "window.html.bak"
#define PLUGIN_SCRIPT "<script src=\"./plugin/index.js\" defer=\"defer\"></script>"
#define OLD_FRAME_SCRIPT "<script src=\"./app/window/frame.js\" defer=\"defer\"></script>"
#define NEW_FRAME_SCRIPT "<script src=\"./appsrc/window/frame.js\" defer=\"defer\"></script>"

void finish() {
printf("Press Enter to exit...");
getchar();
exit(0);
}

int main() {
char cwd[PATH_MAX];
char root_path[PATH_MAX];
char app_path[PATH_MAX];
char appsrc_path[PATH_MAX];
char window_html_path[PATH_MAX];
char window_html_bak_path[PATH_MAX];
const char *frame_script;

getcwd(cwd, PATH_MAX);
strcpy(root_path, dirname(dirname(cwd)));
sprintf(app_path, "%s%c%s", root_path, PATH_SEPARATOR, APP);
sprintf(appsrc_path, "%s%c%s", root_path, PATH_SEPARATOR, APP_SRC);
sprintf(window_html_path, "%s%c%s", root_path, PATH_SEPARATOR, WINDOW_HTML);
sprintf(window_html_bak_path, "%s%c%s", root_path, PATH_SEPARATOR, WINDOW_HTML_BAK);

printf("[1/5] check whether file window.html exists in %s\n", root_path);
struct stat st;
if (stat(window_html_path, &st) == -1) {
fprintf(stderr, "window.html does not exist in %s\n", root_path);
finish();
}

printf("[2/5] check whether folder app/appsrc exists in %s\n", root_path);
if (stat(appsrc_path, &st) == 0) {
frame_script = NEW_FRAME_SCRIPT;
} else if (stat(app_path, &st) == 0) {
frame_script = OLD_FRAME_SCRIPT;
} else {
fprintf(stderr, "appsrc/app does not exist in %s\n", root_path);
finish();
}

FILE *window_html_fp = fopen(window_html_path, "r+");
if (window_html_fp == NULL) {
fprintf(stderr, "failed to open %s\n", window_html_path);
finish();
}

fseek(window_html_fp, 0, SEEK_END);
long window_html_size = ftell(window_html_fp);
rewind(window_html_fp);
char *file_content = malloc(window_html_size + 1);
if (file_content == NULL) {
fprintf(stderr, "malloc error\n");
finish();
}
fread(file_content, sizeof(char), window_html_size, window_html_fp);
file_content[window_html_size] = '\0';

printf("[3/5] check window.html content\n");
char *p = strstr(file_content, frame_script);
if (p == NULL) {
fprintf(stderr, "window.html does not contains %s\n", frame_script);
finish();
}
if (strstr(file_content, PLUGIN_SCRIPT) != NULL) {
printf("plugin has already been installed\n");
finish();
}

printf("[4/5] backup window.html\n");
FILE *window_html_bak_fp = fopen(window_html_bak_path, "w");
if (window_html_bak_fp == NULL) {
fprintf(stderr, "failed to open %s\n", window_html_bak_path);
finish();
}
fwrite(file_content, 1, strlen(file_content), window_html_bak_fp);
fclose(window_html_bak_fp);

printf("[5/5] update window.html\n");
fseek(window_html_fp, 0, SEEK_SET);
char replacement[strlen(frame_script) + strlen(PLUGIN_SCRIPT) + 1];
sprintf(replacement, "%s%s", frame_script, PLUGIN_SCRIPT);
char new_file_content[window_html_size + strlen(PLUGIN_SCRIPT) + 1];
sprintf(new_file_content, "%.*s%s%s", (int) (p - file_content), file_content, replacement, p + strlen(frame_script));
fwrite(new_file_content, 1, strlen(new_file_content), window_html_fp);

fclose(window_html_fp);
free(file_content);
printf("plugin install successfully\n");
finish();

return 0;
}
161 changes: 161 additions & 0 deletions plugin/bin/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package main

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
)

type Installer struct {
root string
insertFile string
insertContent string
oldMatch string
newMatch string
}

func newInstaller() (*Installer, error) {
fmt.Println("[1/4] new installer")
curDir, err := os.Getwd()
if err != nil {
return nil, err
}
return &Installer{
root: filepath.Dir(filepath.Dir(curDir)),
insertFile: "window.html",
insertContent: `<script src="./plugin/index.js" defer="defer"></script>`,
oldMatch: `<script src="./app/window/frame.js" defer="defer"></script>`,
newMatch: `<script src="./appsrc/window/frame.js" defer="defer"></script>`,
}, nil
}

func (i *Installer) prepare() (err error) {
fmt.Println("[2/4] prepare")
if err = checkExist(i.root, i.insertFile); err != nil {
return err
}
return nil
}

func (i *Installer) backupFile() (err error) {
fmt.Println("[3/4] backup window.html")
filePath := filepath.Join(i.root, i.insertFile)
backupFilePath := filePath + ".bak"
if err = copyFile(filePath, backupFilePath); err != nil {
return err
}
return nil
}

func (i *Installer) run() (err error) {
fmt.Println("[4/4] update window.html")
filePath := filepath.Join(i.root, i.insertFile)
file, err := ioutil.ReadFile(filePath)
if err != nil {
return err
}
if bytes.Contains(file, []byte(i.insertContent)) {
return
}

match := ""
if bytes.Contains(file, []byte(i.oldMatch)) {
match = i.oldMatch
} else if bytes.Contains(file, []byte(i.newMatch)) {
match = i.newMatch
}
if match == "" {
return fmt.Errorf("has not match")
}

result := bytes.Replace(file, []byte(match), []byte(match+i.insertContent), 1)
err = ioutil.WriteFile(filePath, result, 0644)
if err != nil {
return err
}
return nil
}

func copyFile(src, dst string) (err error) {
var srcFd *os.File
var dstFd *os.File
var srcInfo os.FileInfo

if srcFd, err = os.Open(src); err != nil {
return err
}
defer srcFd.Close()

if dstFd, err = os.Create(dst); err != nil {
return err
}
defer dstFd.Close()

if _, err = io.Copy(dstFd, srcFd); err != nil {
return err
}
if srcInfo, err = os.Stat(src); err != nil {
return err
}
if err = os.Chmod(dst, srcInfo.Mode()); err != nil {
return err
}
return nil
}

func checkExist(root, sub string) error {
if sub != "" {
root = filepath.Join(root, sub)
}
exist, err := pathExists(root)
if !exist {
err = fmt.Errorf("%s is not exist", root)
}
return err
}

func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, err
}
return false, err
}

func wait() {
fmt.Printf("Press Enter to exit ...")
endKey := make([]byte, 1)
os.Stdin.Read(endKey)
}

func install() (err error) {
installer, err := newInstaller()
if err != nil {
return err
}
if err = installer.prepare(); err != nil {
return err
}
if err = installer.backupFile(); err != nil {
return err
}
if err = installer.run(); err != nil {
return err
}
fmt.Println("plugin install successfully")
wait()
return nil
}

func main() {
if err := install(); err != nil {
fmt.Println()
panic(err)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ escapedPluginScript=$(escape "$pluginScript")
replacement="$escapedFrameScript$escapedPluginScript"
newContent=$(echo "$content" | sed "s|$escapedFrameScript|$replacement|")
echo "$newContent" >"$windowHTMLPath"
echo "plugin installed successfully"
echo "plugin install successfully"
Binary file added plugin/bin/install_linux_amd_x64
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ Copy-Item -Path $windowHTMLPath -Destination $windowHTMLBakPath
Write-Host "[5/5] update window.html"
$newFileContent = $fileContent -Replace [Regex]::Escape($frameScript), $replacement
Set-Content -Path $windowHTMLPath -Value $newFileContent -Encoding UTF8
finish "plugin installed successfully"
finish "plugin install successfully"
Binary file added plugin/bin/install_windows_amd_x64.exe
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ escapedPluginScript=$(escape "$pluginScript")
replacement=""
newContent=$(echo "$content" | sed "s|$escapedPluginScript|$replacement|")
echo "$newContent" >"$windowHTMLPath"
echo "plugin uninstalled successfully"
echo "plugin uninstall successfully"
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ Remove-Item -Path $windowHTMLBakPath
Write-Host "[5/5] update window.html"
$newFileContent = $fileContent -Replace [Regex]::Escape($pluginScript), $replacement
Set-Content -Path $windowHTMLPath -Value $newFileContent -Encoding UTF8
finish "plugin uninstalled successfully"
finish "plugin uninstall successfully"
4 changes: 4 additions & 0 deletions plugin/bin/报毒了怎么办.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
如果不信任 `install_windows_amd_x64.exe``install_linux_amd_x64`,有如下两种方法:

1. 找到目录下的 `install_windows.ps1` 文件,右键它,点击【使用 PowerShell 运行】。
2. 本项目开放所有代码,可以 review 同目录下的 `install.c` 或者 `install.go` 文件并编译。
Loading

0 comments on commit 5e5c91d

Please sign in to comment.