Skip to content

Commit 630a4f3

Browse files
committed
✨ Feature(custom): support drag and drop, support multiple delete, support open image db
1 parent 6f4034b commit 630a4f3

File tree

9 files changed

+162
-26
lines changed

9 files changed

+162
-26
lines changed

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
"categories": [
2626
"Other"
2727
],
28-
"activationEvents": [],
28+
"activationEvents": [
29+
"onLanguage:plaintext",
30+
"onLanguage:markdown"
31+
],
2932
"main": "./dist/extension.js",
3033
"contributes": {
3134
"commands": [
@@ -48,6 +51,11 @@
4851
"command": "piclist.deleteImage",
4952
"title": "%command.delete.title%",
5053
"category": "PicList"
54+
},
55+
{
56+
"command": "piclist.openImageDB",
57+
"title": "%command.openImageDB.title%",
58+
"category": "PicList"
5159
}
5260
],
5361
"menus": {

package.nls.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"command.upload.clipboard.title": "Upload from clipboard",
55
"command.upload.explorer.title": "Upload from explorer",
66
"command.upload.inputBox.title": "Upload from input path or url",
7+
"command.openImageDB.title": "Open PicList image database",
78
"command.delete.title": "Delete Image by PicList",
89
"config.title": "PicList",
910
"config.uploadAPIUrl.description": "Upload API URL, default is `http://127.0.0.1:36677/upload`",
@@ -13,6 +14,7 @@
1314
"config.copyType.url": "URL: url",
1415
"config.copyType.ubb": "UBB: [img]url[/img]",
1516
"config.copyType.custom": "Custom",
17+
"config.copyType.description": "Copy type, default is `Markdown: ![alt](url)`, support `Markdown`, `HTML`, `URL`, `UBB`, `Custom`",
1618
"config.customType.description": "Custom copy type, default is `Markdown: ![$fileName]($url)`, support `$fileName`, `$url`",
1719
"config.encodeUrl.description": "Whether to encode the URL, default is `false`"
1820
}

src/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import * as vscode from 'vscode'
22
import { Commands } from './vscode/commands'
33
import { DataStore } from './vscode/db'
44
import { extractUrl } from './utils'
5+
import { UploadonDropProvider } from './vscode/dropProvider'
56

67
export async function activate(context: vscode.ExtensionContext) {
8+
const selector: vscode.DocumentSelector = {
9+
language: 'plaintext',
10+
}
711
const disposable = [
812
vscode.commands.registerCommand(
913
'piclist.uploadFromClipboard',
@@ -13,6 +17,10 @@ export async function activate(context: vscode.ExtensionContext) {
1317
'piclist.uploadFromExplorer',
1418
async () => await Commands.commandManager.uploadImageFromExplorer()
1519
),
20+
vscode.commands.registerCommand(
21+
'piclist.openImageDB',
22+
async () => await Commands.commandManager.openImageDB()
23+
),
1624
vscode.commands.registerCommand(
1725
'piclist.uploadFromInputBox',
1826
async () => await Commands.commandManager.uploadImageFromInputBox()
@@ -40,6 +48,7 @@ export async function activate(context: vscode.ExtensionContext) {
4048
})
4149
]
4250
context.subscriptions.push(...disposable)
51+
context.subscriptions.push(vscode.languages.registerDocumentDropEditProvider(selector, new UploadonDropProvider()))
4352

4453
return context
4554
}

src/utils/index.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const isUrlEncode = (url: string): boolean => {
1212
}
1313
}
1414

15-
export const handleUrlEncode = (url: string): string => isUrlEncode(url) ? url : encodeURI(url)
15+
export const handleUrlEncode = (url: string): string => (isUrlEncode(url) ? url : encodeURI(url))
1616

1717
export const isURL = (url: string | undefined): boolean => {
1818
if (!url) return false
@@ -24,20 +24,17 @@ export const isURL = (url: string | undefined): boolean => {
2424
}
2525
}
2626

27-
export function extractUrl (str: string): string {
28-
const patterns = [
29-
/!\[.*?\]\((.*?)\)/,
30-
/<img src="(.*?)" alt=".*?">/,
31-
/(https?:\/\/[^\s]+)/,
32-
/\[img\](.*?)\[\/img\]/
33-
];
27+
export function extractUrl(str: string): string[] {
28+
const patterns = [/!\[.*?\]\((.*?)\)/g, /<img src="(.*?)" alt=".*?">/g, /(https?:\/\/[^\s]+)/g, /\[img\](.*?)\[\/img\]/g]
3429

30+
const urls = []
3531
for (const pattern of patterns) {
36-
const match = str.match(pattern);
37-
if (match && match[1]) {
38-
return match[1];
32+
while (true) {
33+
const match = pattern.exec(str)
34+
if (!match) break
35+
urls.push(match[1])
3936
}
4037
}
41-
42-
return '';
38+
console.log(`urls: ${urls}`)
39+
return Array.from(new Set(urls))
4340
}

src/vscode/Editor.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export class Editor {
77

88
static async writeToEditor(text: string) {
99
const editor = this.editor
10-
console.log(editor?.selection ? editor.selection : 'no selection')
1110
return await editor?.edit((textEditor) => {
1211
textEditor.replace(editor.selection, text)
1312
})

src/vscode/commands.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,26 @@ export class Commands {
5757
}
5858
}
5959

60-
async DeleteImage(item: IStringKeyObject): Promise<boolean> {
61-
if (Object.keys(item).length === 0) return false
60+
async openImageDB() {
61+
const filePath = DataStore.dataStore.conUploadedFileDBPath
62+
if (fs.existsSync(filePath)) {
63+
vscode.commands.executeCommand('vscode.open', vscode.Uri.file(filePath))
64+
} else {
65+
showError('No uploaded image.')
66+
}
67+
}
68+
69+
async uploadImageFromStringList(input: string[]) {
70+
return await this.uploadCommand(input.map(item => path.resolve(item.trim())))
71+
}
72+
73+
async DeleteImage(items: IStringKeyObject[]): Promise<boolean> {
74+
if (items.length === 0) return true
6275
try {
6376
const res = await axios.post(
6477
Uploader.picgoAPI.getDeleteAPIUrl(),
6578
{
66-
list: [item]
79+
list: items
6780
},
6881
{
6982
headers: {
@@ -72,7 +85,7 @@ export class Commands {
7285
}
7386
)
7487
if (res.status === 200 && res.data.success) {
75-
DataStore.removeUploadedFileDBItem(item)
88+
DataStore.removeUploadedFileDBItem(items)
7689
return true
7790
} else {
7891
return false

src/vscode/db.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export class DataStore {
1313

1414
get appDataPath() {
1515
const appDataPath = getAppDataPath('vs-piclist')
16-
console.log('appDataPath', appDataPath)
1716
fs.ensureDirSync(appDataPath)
1817
return appDataPath
1918
}
@@ -25,7 +24,6 @@ export class DataStore {
2524
static writeUploadedFileDB(data: IStringKeyObject[]) {
2625
try {
2726
const originData = DataStore.readUploadedFileDB() || []
28-
console.log('data', data)
2927
const newData = [...originData, ...data]
3028
fs.writeJSONSync(DataStore.dataStore.conUploadedFileDBPath, newData)
3129
} catch (error) {
@@ -43,15 +41,26 @@ export class DataStore {
4341
}
4442
}
4543

46-
static searchUploadedFileDB(url: string): IStringKeyObject {
44+
static searchUploadedFileDB(urls: string[]): IStringKeyObject[] {
4745
const data = DataStore.readUploadedFileDB()
48-
const res = data.find(item => item.imgUrl === url || decodeURI(item.imgUrl) === url) || {}
46+
const res = [] as IStringKeyObject[]
47+
for (const url of urls) {
48+
const item = data.find(item => item.imgUrl === url || decodeURI(item.imgUrl) === url)
49+
if (item) {
50+
res.push(item)
51+
}
52+
}
4953
return res
5054
}
5155

52-
static removeUploadedFileDBItem(item: IStringKeyObject) {
56+
static removeUploadedFileDBItem(items: IStringKeyObject[]) {
5357
const data = DataStore.readUploadedFileDB()
54-
const newData = data.filter((i: IStringKeyObject) => i.id !== item.id)
55-
fs.writeJSONSync(DataStore.dataStore.conUploadedFileDBPath, newData)
58+
for (const item of items) {
59+
const index = data.findIndex((i: IStringKeyObject) => i.id === item.id)
60+
if (index !== -1) {
61+
data.splice(index, 1)
62+
}
63+
}
64+
fs.writeJSONSync(DataStore.dataStore.conUploadedFileDBPath, data)
5665
}
5766
}

src/vscode/dropProvider.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as vscode from 'vscode'
2+
import { Commands } from './commands'
3+
4+
const uriListMime = 'text/uri-list'
5+
6+
export class UploadonDropProvider implements vscode.DocumentDropEditProvider {
7+
async provideDocumentDropEdits(
8+
_document: vscode.TextDocument,
9+
_position: vscode.Position,
10+
dataTransfer: vscode.DataTransfer,
11+
token: vscode.CancellationToken
12+
): Promise<vscode.DocumentDropEdit | undefined> {
13+
const dataTransferItem = dataTransfer.get(uriListMime)
14+
if (!dataTransferItem) return undefined
15+
const urlList = await dataTransferItem.asString()
16+
if (token.isCancellationRequested) return undefined
17+
const uris: vscode.Uri[] = []
18+
for (const resource of urlList.split('\n')) {
19+
try {
20+
uris.push(vscode.Uri.parse(resource))
21+
} catch {}
22+
}
23+
if (!uris.length) return undefined
24+
25+
const snippet = new vscode.SnippetString()
26+
await Commands.commandManager.uploadImageFromStringList(uris.map(item => item.fsPath))
27+
28+
return new vscode.DocumentDropEdit(snippet)
29+
}
30+
}

test

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# vs-piclist
2+
3+
## 概览
4+
5+
`vs-piclist`是一个功能丰富的VSCode扩展,搭配PicList使用,可以轻松地将图像上传到各种图床,并自动将生成的URL插入到当前活动文件中。
6+
7+
`vs-piclist`通过和PicList配合使用,可以实现包括图像压缩,水印和其他高级图像处理功能。
8+
9+
### 先决条件
10+
11+
在使用`vs-piclist`之前,你必须先安装桌面软件[PicList](https://github.com/Kuingsmile/PicList)。
12+
13+
### 功能对比
14+
15+
尽管存在类似的扩展,如[vs-picgo](https://github.com/PicGo/vs-picgo),其依赖于[PicGo-Core](https://github.com/PicGo/PicGo-Core),但`vs-piclist`提供了更强大的功能,支持从图像处理、上传到云删除的一整套功能。
16+
17+
## 功能
18+
19+
- **轻松上传**:只需点击几下,即可将图像上传到您喜欢的远程图像托管服务。
20+
- **自动插入URL**:扩展会自动将图像URL插入到您的工作文件中。
21+
- **图像管理**:通过VSCode中的PicList轻松删除存储在远程托管服务中的图像。
22+
- **高级图像处理**:包括对图像压缩、水印和其他上传后处理的支持。
23+
24+
### Gif 演示
25+
26+
<img src="https://s2.loli.net/2023/08/31/XvZrtgiuWwLYIHy.gif" alt="clipboard.gif">
27+
<img src="https://s2.loli.net/2023/08/31/npvwQoT4Ucr5mPN.gif" alt="explorer.gif">
28+
<img src="https://s2.loli.net/2023/08/31/tAW54rVFhO2KSTo.gif" alt="input box.gif">
29+
<img src="https://s2.loli.net/2023/09/01/8oYzJinhgajLfdI.gif" alt="input box.gif">
30+
31+
## 设置
32+
33+
![setting](https://s2.loli.net/2023/08/31/vL7WgcDrxIGzZBR.webp)
34+
35+
### 上传API接口地址
36+
37+
这是PicList的上传api接口地址,默认为`http://127.0.0.1:36677/upload`,参考说明文档[PicList Server](https://piclist.cn/en/advanced.html#use-of-built-in-server)。
38+
39+
### 删除API接口地址
40+
41+
这是PicList的删除api接口地址,默认为`http://127.0.0.1:36677/delete`,参考说明文档[PicList Server](https://piclist.cn/en/advanced.html#use-of-built-in-server)。
42+
43+
### 粘贴格式
44+
45+
默认为markdown格式。
46+
47+
| 类型 | 格式 |
48+
| -------- | ----------------------- |
49+
| url | `url` |
50+
| markdown | `![alt](url)` |
51+
| html | `<img src=url alt=alt>` |
52+
| ubb | `[img]url[/img]` |
53+
| custom | `custom` |
54+
55+
### 自定义格式
56+
57+
默认为`![$filename]($url)`.
58+
59+
### URL编码
60+
61+
是否需要在插入时编码URL。
62+
63+
## 作者
64+
65+
- [Kuingsmile](https://github.com/Kuingsmile)
66+
67+
## 依赖
68+
69+
- [PicList](https://github.com/Kuingsmile/PicList)

0 commit comments

Comments
 (0)