├── .gitignore
├── .npmignore
├── .prettierrc
├── LICENSE
├── README.md
├── images
├── clipboard.gif
├── inputbox.gif
└── selection.gif
├── package.json
├── package.nls.json
├── src
├── index.ts
├── picgo.ts
└── utils.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .vim/
2 | lib/
3 | node_modules
4 |
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | lib
2 | images/
3 | src/
4 | node_modules/
5 | sconfig.json
6 | *.map
7 | .tags
8 | .DS_Store
9 | webpack.config.js
10 | yarn.lock
11 | yarn-error.log
12 | .github
13 | .eslintrc.js
14 | .prettierrc
15 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "useTabs": false,
6 | "singleQuote": true,
7 | "bracketSpacing": true,
8 | "arrowParens": "avoid"
9 | }
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 PLDaily
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # coc-picgo
2 |
3 | [PicGo](https://github.com/Molunerfinn/PicGo) extension for coc.nvim, forked from [vs-picgo](https://github.com/PicGo/vs-picgo)
4 |
5 | ## Install
6 |
7 | `:CocInstall coc-picgo`
8 |
9 | ## Features
10 |
11 |
12 | Uploading an image from clipboard
13 |
14 |
15 |
16 |
17 | Uploading images from input box
18 |
19 |
20 |
21 |
22 | Use selection text as the uploaded fileName
23 |
24 | Notice: These characters: \$
, :
, /
, ?
and newline will be ignored in the image name. (Because they are invalid for file names.)
25 |
26 |
27 | ## Usage
28 |
29 | ```
30 | xmap a (coc-codeaction-selected)
31 | nmap a (coc-codeaction-selected)
32 | ```
33 |
34 | ## License
35 |
36 | MIT
37 |
38 | ---
39 |
40 | > This extension is created by [create-coc-extension](https://github.com/fannheyward/create-coc-extension)
41 |
--------------------------------------------------------------------------------
/images/clipboard.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PLDaily/coc-picgo/9bbd636371384c7f7c51d530d398d9c35bc2101a/images/clipboard.gif
--------------------------------------------------------------------------------
/images/inputbox.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PLDaily/coc-picgo/9bbd636371384c7f7c51d530d398d9c35bc2101a/images/inputbox.gif
--------------------------------------------------------------------------------
/images/selection.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PLDaily/coc-picgo/9bbd636371384c7f7c51d530d398d9c35bc2101a/images/selection.gif
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "coc-picgo",
3 | "version": "1.0.2",
4 | "description": "PicGo extension for coc.nvim, forked from vs-picgo",
5 | "author": "PLDaily ",
6 | "license": "MIT",
7 | "main": "lib/index.js",
8 | "keywords": [
9 | "coc.nvim",
10 | "vim",
11 | "picgo"
12 | ],
13 | "engines": {
14 | "coc": "^0.0.70"
15 | },
16 | "scripts": {
17 | "clean": "rimraf lib",
18 | "watch": "webpack --watch",
19 | "build": "webpack",
20 | "lint": "tslint -c tslint.json -p tsconfig.json --fix",
21 | "prepare": "npm-run-all clean build"
22 | },
23 | "devDependencies": {
24 | "@types/node": "^14.0.13",
25 | "coc.nvim": "^0.0.77",
26 | "npm-run-all": "^4.1.5",
27 | "prettier": "^2.0.5",
28 | "rimraf": "^3.0.2",
29 | "ts-loader": "^7.0.5",
30 | "tslint": "^6.1.2",
31 | "tslint-plugin-prettier": "^2.3.0",
32 | "typescript": "^3.9.5",
33 | "webpack": "^4.43.0",
34 | "webpack-cli": "^3.3.11"
35 | },
36 | "activationEvents": [
37 | "*"
38 | ],
39 | "contributes": {
40 | "configuration": {
41 | "type": "object",
42 | "title": "coc-picgo configuration",
43 | "properties": {
44 | "picgo.configPath": {
45 | "type": "string",
46 | "markdownDescription": "%config.configPath.description%",
47 | "default": ""
48 | },
49 | "picgo.dataPath": {
50 | "type": "string",
51 | "markdownDescription": "%config.dataPath.description%",
52 | "default": ""
53 | },
54 | "picgo.customUploadName": {
55 | "type": "string",
56 | "markdownDescription": "%config.customUploadName.description%",
57 | "default": "${fileName}${extName}"
58 | },
59 | "picgo.customOutputFormat": {
60 | "type": "string",
61 | "markdownDescription": "%config.customOutputFormat.description%",
62 | "default": ""
63 | },
64 | "picgo.picBed.current": {
65 | "type": "string",
66 | "enum": [
67 | "smms",
68 | "aliyun",
69 | "github",
70 | "imgur",
71 | "qiniu",
72 | "tcyun",
73 | "upyun",
74 | "weibo"
75 | ],
76 | "default": "smms",
77 | "markdownDescription": "%config.picBed.description%"
78 | },
79 | "picgo.picBed.smms.token": {
80 | "type": "string",
81 | "default": ""
82 | },
83 | "picgo.picBed.aliyun.accessKeyId": {
84 | "type": "string",
85 | "default": ""
86 | },
87 | "picgo.picBed.aliyun.accessKeySecret": {
88 | "type": "string",
89 | "default": ""
90 | },
91 | "picgo.picBed.aliyun.bucket": {
92 | "type": "string",
93 | "default": ""
94 | },
95 | "picgo.picBed.aliyun.area": {
96 | "type": "string",
97 | "default": ""
98 | },
99 | "picgo.picBed.aliyun.path": {
100 | "type": "string",
101 | "default": ""
102 | },
103 | "picgo.picBed.aliyun.customUrl": {
104 | "type": "string",
105 | "default": ""
106 | },
107 | "picgo.picBed.github.repo": {
108 | "type": "string",
109 | "default": "",
110 | "markdownDescription": "%config.picBed.github.repo.description%"
111 | },
112 | "picgo.picBed.github.token": {
113 | "type": "string",
114 | "default": ""
115 | },
116 | "picgo.picBed.github.path": {
117 | "type": "string",
118 | "default": ""
119 | },
120 | "picgo.picBed.github.customUrl": {
121 | "type": "string",
122 | "default": ""
123 | },
124 | "picgo.picBed.github.branch": {
125 | "type": "string",
126 | "default": ""
127 | },
128 | "picgo.picBed.imgur.clientId": {
129 | "type": "string",
130 | "default": ""
131 | },
132 | "picgo.picBed.imgur.proxy": {
133 | "type": "string",
134 | "default": ""
135 | },
136 | "picgo.picBed.qiniu.accessKey": {
137 | "type": "string",
138 | "default": ""
139 | },
140 | "picgo.picBed.qiniu.secretKey": {
141 | "type": "string",
142 | "default": ""
143 | },
144 | "picgo.picBed.qiniu.bucket": {
145 | "type": "string",
146 | "default": ""
147 | },
148 | "picgo.picBed.qiniu.url": {
149 | "type": "string",
150 | "default": ""
151 | },
152 | "picgo.picBed.qiniu.area": {
153 | "type": "string",
154 | "enum": [
155 | "z0",
156 | "z1",
157 | "z2",
158 | "na0",
159 | "as0"
160 | ],
161 | "default": "z0"
162 | },
163 | "picgo.picBed.qiniu.options": {
164 | "type": "string",
165 | "default": ""
166 | },
167 | "picgo.picBed.qiniu.path": {
168 | "type": "string",
169 | "default": ""
170 | },
171 | "picgo.picBed.tcyun.version": {
172 | "type": "string",
173 | "enum": [
174 | "v4",
175 | "v5"
176 | ],
177 | "default": "v5"
178 | },
179 | "picgo.picBed.tcyun.secretId": {
180 | "type": "string",
181 | "default": ""
182 | },
183 | "picgo.picBed.tcyun.secretKey": {
184 | "type": "string",
185 | "default": ""
186 | },
187 | "picgo.picBed.tcyun.bucket": {
188 | "type": "string",
189 | "default": ""
190 | },
191 | "picgo.picBed.tcyun.appId": {
192 | "type": "string",
193 | "default": ""
194 | },
195 | "picgo.picBed.tcyun.area": {
196 | "type": "string",
197 | "default": ""
198 | },
199 | "picgo.picBed.tcyun.path": {
200 | "type": "string",
201 | "default": ""
202 | },
203 | "picgo.picBed.tcyun.customUrl": {
204 | "type": "string",
205 | "default": ""
206 | },
207 | "picgo.picBed.upyun.bucket": {
208 | "type": "string",
209 | "default": ""
210 | },
211 | "picgo.picBed.upyun.operator": {
212 | "type": "string",
213 | "default": ""
214 | },
215 | "picgo.picBed.upyun.password": {
216 | "type": "string",
217 | "default": ""
218 | },
219 | "picgo.picBed.upyun.options": {
220 | "type": "string",
221 | "default": ""
222 | },
223 | "picgo.picBed.upyun.path": {
224 | "type": "string",
225 | "default": ""
226 | },
227 | "picgo.picBed.upyun.url": {
228 | "type": "string",
229 | "default": ""
230 | },
231 | "picgo.picBed.weibo.chooseCookie": {
232 | "type": "boolean",
233 | "default": true
234 | },
235 | "picgo.picBed.weibo.username": {
236 | "type": "string",
237 | "default": ""
238 | },
239 | "picgo.picBed.weibo.quality": {
240 | "type": "string",
241 | "enum": [
242 | "thumbnail",
243 | "mw690",
244 | "large"
245 | ],
246 | "default": "large"
247 | },
248 | "picgo.picBed.weibo.cookie": {
249 | "type": "string",
250 | "default": ""
251 | }
252 | }
253 | },
254 | "commands": [
255 | {
256 | "command": "picgo.uploadImageFromClipboard",
257 | "title": "picgo.uploadImageFromClipboard"
258 | },
259 | {
260 | "command": "picgo.uploadImageFromInputBox",
261 | "title": "picgo.uploadImageFromInputBox"
262 | }
263 | ]
264 | },
265 | "dependencies": {
266 | "lodash": "^4.17.19",
267 | "lodash-id": "^0.14.0",
268 | "picgo": "^1.4.10"
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/package.nls.json:
--------------------------------------------------------------------------------
1 | {
2 | "ext.displayName": "PicGo",
3 | "ext.description": "A fast and powerful image uploading plugin for VSCode based on PicGo. Supports most image types (png, jpg, gif, etc.) and many image hosting services (smms, qiniu, imgur, etc.)!",
4 | "ext.keywords": ["image", "picture", "upload", "image upload", "picture upload"],
5 | "command.upload.clipboard.title": "Upload image from clipboard",
6 | "command.upload.explorer.title": "Upload image from explorer",
7 | "command.upload.inputBox.title": "Upload image from inputBox",
8 | "config.title": "PicGo",
9 | "config.configPath.description": "The path to your PicGo-Core configuration. PicGo will use `#picgo.picBed#` if this is not specified.",
10 | "config.dataPath.description": "The path to your data file, including all uploaded images' info. PicGo will use `your_home_dir/vs-picgo-data.json` if this is not specified.",
11 | "config.customUploadName.description": "Customize the name of the image to be uploaded, image will be renamed before uploading.\n- `${fileName}`: the name of the original image, without extension name.\n **Notice: If you selected some text before uploading, the selection will become the `fileName` of the image to be uploaded.**\n- `${extName}`: the extension name of the original image.\n- `${mdFileName}`: the name of the current editing markdown file.\n- `${date}`: YY-MM-DD formatted date.\n- `${dateTime}`: YY-MM-DD-hh-mm-ss formatted date.\n\nExamples:\n- `${fileName}-${date}${extName}` -> `picName-2016-07-25.jpg`\n- `${mdFileName}`-`${dateTime}${extName}` -> `markdownName-2017-04-12-22-28-10.jpg`",
12 | "config.customOutputFormat.description": "Customize the output format of the uploaded image.\n- `${url}`: the url of the uploaded image.\n- `${uploadedName}`: the name of the uploaded image without extension name, see `#picgo.customUploadName#`, note that even if you used `${extName}` in `#picgo.customUploadName#`, there still will be no extension name in the output.\n\nExamples:\n- `` -> ``\n- `
` -> `
`",
13 | "config.picBed.description": "PicGo-Core configuration, please see [PicGo Docs](https://picgo.github.io/PicGo-Doc/zh/guide/config.html#%E5%9B%BE%E5%BA%8A%E5%8C%BA).",
14 | "config.picBed.smms.description": "SM.MS picBed configuration.",
15 | "config.picBed.weibo.description": "Weibo picBed configuration.",
16 | "config.picBed.qiniu.description": "Qiniu picBed configuration.",
17 | "config.picBed.upyun.description": "Upyun picBed configuration.",
18 | "config.picBed.tcyun.description": "Tencent COS picBed configuration.",
19 | "config.picBed.github.description": "GitHub configuration.",
20 | "config.picBed.github.repo.description": "`Username/Repo`. For example, PicGo/Images",
21 | "config.picBed.aliyun.description": "Aliyun OSS configuration.",
22 | "config.picBed.imgur.description": "Imgur picBed configuration."
23 | }
24 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CodeActionProvider,
3 | languages,
4 | commands,
5 | ExtensionContext,
6 | Uri,
7 | workspace,
8 | } from 'coc.nvim';
9 | import * as fs from 'fs';
10 | import * as path from 'path';
11 | import { Command, Range, TextDocument } from 'vscode-languageserver-protocol';
12 | import VSPicgo from './picgo';
13 |
14 | function uploadImageFromClipboard(
15 | vspicgo: VSPicgo,
16 | ): Promise {
17 | return vspicgo.upload();
18 | }
19 |
20 | async function uploadImageFromInputBox(
21 | vspicgo: VSPicgo,
22 | ): Promise {
23 | const doc = await workspace.document;
24 | if (!doc) return;
25 | let result = await workspace.requestInput(
26 | 'Please input an image location path',
27 | );
28 | if (!result) return;
29 |
30 | // check if `result` is a path of image file
31 | const imageReg = /\.(png|jpg|jpeg|webp|gif|bmp|tiff|ico)$/;
32 | if (result && imageReg.test(result)) {
33 | result = path.isAbsolute(result)
34 | ? result
35 | : path.join(Uri.parse(doc.uri).fsPath, '../', result);
36 | if (fs.existsSync(result)) {
37 | return vspicgo.upload([result]);
38 | } else {
39 | workspace.showMessage('No such image.');
40 | }
41 | } else {
42 | workspace.showMessage('No such image.');
43 | }
44 | }
45 |
46 | class ReactRefactorCodeActionProvider implements CodeActionProvider {
47 | async provideCodeActions(
48 | document: TextDocument,
49 | range: Range,
50 | ): Promise {
51 | const codeActions: Command[] = [];
52 | const selectedText = document.getText(range);
53 | if (selectedText) {
54 | codeActions.push({
55 | command: 'picgo.uploadImageFromClipboard',
56 | title: 'picgo.uploadImageFromClipboard',
57 | arguments: ['v'],
58 | });
59 | codeActions.push({
60 | command: 'picgo.uploadImageFromInputBox',
61 | title: 'picgo.uploadImageFromInputBox',
62 | arguments: ['v'],
63 | });
64 | }
65 | return codeActions;
66 | }
67 | }
68 |
69 | export async function activate(context: ExtensionContext): Promise {
70 | const vspicgo = new VSPicgo();
71 | const disposable = [
72 | languages.registerCodeActionProvider(
73 | [{ scheme: 'file', pattern: '**/*.{md,markdown}' }],
74 | new ReactRefactorCodeActionProvider(),
75 | 'coc-picgo',
76 | ),
77 | commands.registerCommand('picgo.uploadImageFromClipboard', async mode => {
78 | vspicgo.mode = mode;
79 | uploadImageFromClipboard(vspicgo);
80 | }),
81 | commands.registerCommand('picgo.uploadImageFromInputBox', mode => {
82 | vspicgo.mode = mode;
83 | uploadImageFromInputBox(vspicgo);
84 | }),
85 | ];
86 | context.subscriptions.push(...disposable);
87 | }
88 |
--------------------------------------------------------------------------------
/src/picgo.ts:
--------------------------------------------------------------------------------
1 | import { Uri, workspace } from 'coc.nvim';
2 | import { EventEmitter } from 'events';
3 | import * as fs from 'fs';
4 | import * as os from 'os';
5 | import * as path from 'path';
6 | import PicGo from 'picgo';
7 | import { IImgInfo, IPlugin } from 'picgo/dist/src/utils/interfaces';
8 | import { promisify } from 'util';
9 | import { TextEdit } from 'vscode-languageserver-protocol';
10 | import {
11 | formatParam,
12 | formatString,
13 | getUploadedName,
14 | showError,
15 | showInfo,
16 | } from './utils';
17 |
18 | const _ = require('lodash');
19 | const _db = require('lodash-id');
20 | _.mixin(_db);
21 |
22 | const writeFileP = promisify(fs.writeFile);
23 | const readFileP = promisify(fs.readFile);
24 |
25 | export interface INotice {
26 | body: string;
27 | text: string;
28 | title: string;
29 | }
30 |
31 | export interface IUploadName {
32 | date: string;
33 | dateTime: string;
34 | fileName: string;
35 | extName: string;
36 | mdFileName: string;
37 | [key: string]: string;
38 | }
39 |
40 | export interface IOutputUrl {
41 | uploadedName: string;
42 | url: string;
43 | [key: string]: string;
44 | }
45 |
46 | export enum EVSPicgoHooks {
47 | updated = 'updated',
48 | }
49 |
50 | export default class VSPicgo extends EventEmitter {
51 | private static picgo: PicGo = new PicGo();
52 | public mode: string = 'v';
53 |
54 | constructor() {
55 | super();
56 | this.configPicgo();
57 | // Before upload, we change names of the images.
58 | this.registerRenamePlugin();
59 | // After upload, we use the custom output format.
60 | this.addGenerateOutputListener();
61 | }
62 |
63 | configPicgo() {
64 | let config = workspace.getConfiguration('picgo');
65 | const picgoConfigPath = config.get('configPath');
66 | if (picgoConfigPath) {
67 | VSPicgo.picgo.setConfig(
68 | JSON.parse(
69 | fs.readFileSync(picgoConfigPath, {
70 | encoding: 'utf-8',
71 | }),
72 | ),
73 | );
74 | } else {
75 | const picBed = config.get('picBed');
76 | VSPicgo.picgo.setConfig({ picBed });
77 | }
78 | }
79 |
80 | addGenerateOutputListener() {
81 | VSPicgo.picgo.on('finished', async (ctx: PicGo) => {
82 | let urlText = '';
83 | const outputFormatTemplate =
84 | workspace.getConfiguration('picgo').get('customOutputFormat') ||
85 | '';
86 | try {
87 | urlText = ctx.output.reduce(
88 | (acc: string, imgInfo: IImgInfo): string => {
89 | return `${acc}${formatString(outputFormatTemplate, {
90 | uploadedName: getUploadedName(imgInfo),
91 | url: imgInfo.imgUrl,
92 | })}\n`;
93 | },
94 | '',
95 | );
96 | urlText = urlText.trim();
97 | await this.updateData(ctx.output);
98 | } catch (err) {
99 | if (err instanceof SyntaxError) {
100 | showError(
101 | `the data file ${this.dataPath} has syntax error, ` +
102 | `please fix the error by yourself or delete the data file and vs-picgo will recreate for you.`,
103 | );
104 | } else {
105 | showError(
106 | `failed to read from data file ${this.dataPath}: ${err || ''}`,
107 | );
108 | }
109 | return;
110 | }
111 | const doc = await workspace.document;
112 | if (!doc) return;
113 | let edits: TextEdit[] = [];
114 | if (!this.mode) {
115 | const position = await workspace.getCursorPosition();
116 | edits = [TextEdit.insert(position, urlText)];
117 | } else {
118 | const mode = await workspace.nvim.call('mode');
119 | const range = await workspace.getSelectedRange(mode, doc);
120 | if (!range) return;
121 | edits = [TextEdit.replace(range, urlText)];
122 | }
123 | await doc.applyEdits(edits);
124 | showInfo(`image uploaded successfully.`);
125 | this.emit(EVSPicgoHooks.updated, urlText);
126 | });
127 | }
128 |
129 | registerRenamePlugin() {
130 | let beforeUploadPlugin: IPlugin = {
131 | handle: async (ctx: PicGo) => {
132 | const uploadNameTemplate =
133 | workspace.getConfiguration('picgo').get('customUploadName') ||
134 | '${fileName}';
135 | if (ctx.output.length === 1) {
136 | ctx.output[0].fileName = await this.changeFilename(
137 | ctx.output[0].fileName || '',
138 | uploadNameTemplate,
139 | undefined,
140 | );
141 | } else {
142 | for (let index = 0; index < ctx.output.length; index++) {
143 | ctx.output[index].fileName = await this.changeFilename(
144 | ctx.output[index].filename || '',
145 | uploadNameTemplate,
146 | index,
147 | );
148 | }
149 | }
150 | },
151 | };
152 | if (VSPicgo.picgo.helper.beforeUploadPlugins.get('vsPicgoRenamePlugin')) {
153 | VSPicgo.picgo.helper.beforeUploadPlugins.unregister(
154 | 'vsPicgoRenamePlugin',
155 | );
156 | }
157 | VSPicgo.picgo.helper.beforeUploadPlugins.register(
158 | 'vsPicgoRenamePlugin',
159 | beforeUploadPlugin,
160 | );
161 | }
162 |
163 | /**
164 | * Returns the modified file name as per `customUploadName` setting
165 | * @param original The filename of the original image file.
166 | * @param template The template string.
167 | */
168 | async changeFilename(
169 | original: string,
170 | template: string,
171 | index: number | undefined,
172 | ) {
173 | const doc = await workspace.document;
174 | if (!doc) return;
175 | let selectedString: string;
176 | if (!this.mode) {
177 | selectedString = '';
178 | } else {
179 | const m = await workspace.nvim.call('visualmode');
180 | const range = await workspace.getSelectedRange(m, doc);
181 | if (!range) return;
182 | selectedString = doc.textDocument.getText(range);
183 | }
184 | const nameReg = /[:\/\?\$]+/g; // limitations of name
185 | const userDefineName = selectedString.replace(nameReg, () => '');
186 | if (userDefineName) {
187 | original = userDefineName + (index || '') + path.extname(original);
188 | }
189 | const mdFilePath = Uri.parse(doc.uri).fsPath;
190 | const mdFileName = path.basename(mdFilePath, path.extname(mdFilePath));
191 | let uploadNameData = formatParam(original, mdFileName);
192 | return formatString(template, uploadNameData);
193 | }
194 |
195 | get dataPath(): string {
196 | const picgoConfig = workspace.getConfiguration('picgo');
197 | return (
198 | picgoConfig.dataPath || path.resolve(os.homedir(), 'vs-picgo-data.json')
199 | );
200 | }
201 |
202 | async initDataFile(dataPath: string) {
203 | if (!fs.existsSync(dataPath)) {
204 | await writeFileP(
205 | dataPath,
206 | JSON.stringify({ uploaded: [] }, null, 2),
207 | 'utf8',
208 | );
209 | }
210 | }
211 |
212 | async upload(input?: string[]): Promise {
213 | // This is necessary, because user may have changed settings
214 | this.configPicgo();
215 |
216 | // uploading progress
217 | VSPicgo.picgo.on('uploadProgress', (p: number) => {
218 | showInfo(`image uploading ${p}% ...`);
219 | });
220 | VSPicgo.picgo.on('notification', (notice: INotice) => {
221 | showError(`${notice.title}! ${notice.body || ''}${notice.text || ''}`);
222 | });
223 | VSPicgo.picgo.on('failed', () => {
224 | showError(`image upload failed`);
225 | });
226 |
227 | return VSPicgo.picgo.upload(input);
228 | }
229 |
230 | async updateData(picInfos: Array) {
231 | const dataPath = this.dataPath;
232 | if (!fs.existsSync(dataPath)) {
233 | await this.initDataFile(dataPath);
234 | showInfo('data file created at ${dataPath}.');
235 | }
236 | const dataRaw = await readFileP(dataPath, 'utf8');
237 | const data = JSON.parse(dataRaw);
238 | if (!data.uploaded) {
239 | data.uploaded = [];
240 | }
241 | picInfos.forEach(picInfo => {
242 | _.insert(data['uploaded'], picInfo);
243 | });
244 | await writeFileP(dataPath, JSON.stringify(data, null, 2), 'utf8');
245 | }
246 | }
247 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { workspace } from 'coc.nvim';
2 | import * as path from 'path';
3 | import { IImgInfo } from 'picgo/dist/src/utils/interfaces';
4 | import { IOutputUrl, IUploadName } from './picgo';
5 |
6 | export function formatParam(file: string, mdFileName: string): IUploadName {
7 | const dt = new Date();
8 | const y = dt.getFullYear();
9 | const m = dt.getMonth() + 1;
10 | const d = dt.getDate();
11 | const h = dt.getHours();
12 | const mm = dt.getMinutes();
13 | const s = dt.getSeconds();
14 |
15 | let pad = function (x: number) {
16 | return ('00' + x).slice(-2);
17 | };
18 |
19 | const date = `${y}-${pad(m)}-${pad(d)}`;
20 | var extName = path.extname(file);
21 |
22 | return {
23 | date,
24 | dateTime: `${date}-${pad(h)}-${pad(mm)}-${pad(s)}`,
25 | fileName: path.basename(file, extName),
26 | extName,
27 | mdFileName,
28 | };
29 | }
30 |
31 | export function formatString(
32 | tplString: string,
33 | data: IUploadName | IOutputUrl,
34 | ) {
35 | const keys = Object.keys(data);
36 | const values = keys.map(k => data[k]);
37 | return new Function(keys.join(','), 'return `' + tplString + '`').apply(
38 | null,
39 | values,
40 | );
41 | }
42 |
43 | import nls = require('../package.nls.json');
44 |
45 | function addPeriod(messgae: string) {
46 | if (!messgae.endsWith('.') && !messgae.endsWith('!')) {
47 | messgae = messgae + '.';
48 | }
49 | return messgae;
50 | }
51 |
52 | export function showWarning(messgae: string) {
53 | messgae = addPeriod(messgae);
54 | workspace.showMessage(`${nls['ext.displayName']}: ${messgae}`);
55 | }
56 |
57 | export function showError(messgae: string) {
58 | messgae = addPeriod(messgae);
59 | workspace.showMessage(`${nls['ext.displayName']}: ${messgae}`);
60 | }
61 |
62 | export function showInfo(messgae: string) {
63 | messgae = addPeriod(messgae);
64 | workspace.showMessage(`${nls['ext.displayName']}: ${messgae}`);
65 | }
66 |
67 | /**
68 | * Return uploaded name accrding to `imgInfo.fileName`,
69 | * extname will be removed for the sake of simplicity when used as alt.
70 | * @param imgInfo
71 | */
72 | export function getUploadedName(imgInfo: IImgInfo): string {
73 | let fullName;
74 | if (!imgInfo.fileName) {
75 | fullName = '';
76 | } else {
77 | fullName = imgInfo.fileName as string;
78 | }
79 | let basename = path.basename(fullName, path.extname(fullName));
80 | return basename;
81 | }
82 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "lib": ["es2017", "es2018"],
5 | "module": "commonjs",
6 | "declaration": false,
7 | "sourceMap": true,
8 | "outDir": "lib",
9 | "strict": true,
10 | "moduleResolution": "node",
11 | "resolveJsonModule": true,
12 | "noImplicitAny": false,
13 | "esModuleInterop": true
14 | },
15 | "include": ["src"]
16 | }
17 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["tslint-plugin-prettier"],
3 | "rules": {
4 | "prettier": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.ts',
5 | target: 'node',
6 | mode: 'none',
7 | resolve: {
8 | mainFields: ['module', 'main'],
9 | extensions: ['.js', '.ts', '.json']
10 | },
11 | externals: {
12 | 'coc.nvim': 'commonjs coc.nvim',
13 | 'picgo': 'commonjs picgo'
14 | },
15 | module: {
16 | rules: [
17 | {
18 | test: /\.ts$/,
19 | include: [path.resolve(__dirname, 'src')],
20 | use: [
21 | {
22 | loader: 'ts-loader',
23 | options: {
24 | compilerOptions: {
25 | sourceMap: true
26 | }
27 | }
28 | }
29 | ]
30 | }
31 | ]
32 | },
33 | output: {
34 | path: path.join(__dirname, 'lib'),
35 | filename: 'index.js',
36 | libraryTarget: 'commonjs'
37 | },
38 | plugins: [],
39 | node: {
40 | __dirname: false,
41 | __filename: false
42 | }
43 | };
44 |
--------------------------------------------------------------------------------