Skip to content

Commit 09371fd

Browse files
committed
feat: add custom editor
1 parent 10d0f4c commit 09371fd

File tree

8 files changed

+142
-42
lines changed

8 files changed

+142
-42
lines changed

package.json

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,22 @@
1212
],
1313
"main": "./out/extension",
1414
"activationEvents": [
15-
"onCommand:codingPlugin.helloWorld",
15+
"onCustomEditor:customEditor.mrDetail",
1616
"onView:codingPlugin.treeMR",
17-
"onView:codingPlugin.treeDepot",
18-
"onView:codingPlugin.webview"
17+
"onView:codingPlugin.treeDepot"
1918
],
2019
"contributes": {
21-
"commands": [
20+
"customEditors": [
2221
{
23-
"command": "codingPlugin.helloWorld",
24-
"title": "Hello World"
25-
},
22+
"viewType": "customEditor.mrDetail",
23+
"displayName": "MR Detail",
24+
"selector": [{
25+
"fileNamePattern": "hosts"
26+
}],
27+
"priority": "default"
28+
}
29+
],
30+
"commands": [
2631
{
2732
"command": "codingPlugin.mrTreeItemClick",
2833
"title": "Click MR Tree Item"
@@ -37,16 +42,6 @@
3742
}
3843
],
3944
"menus": {
40-
"editor/context": [
41-
{
42-
"command": "codingPlugin.helloWorld",
43-
"group": "z_commands",
44-
"when": "editorTextFocus"
45-
},
46-
{
47-
"group": "z_commands"
48-
}
49-
],
5045
"view/item/context": [
5146
{
5247
"command": "codingPlugin.createDepot",
@@ -64,12 +59,6 @@
6459
"id": "CODING-DEPOT",
6560
"title": "CODING 仓库"
6661
}
67-
],
68-
"rightside": [
69-
{
70-
"id": "WebviewContainerId",
71-
"title": "CODING 合并请求详情"
72-
}
7362
]
7463
},
7564
"views": {
@@ -84,12 +73,6 @@
8473
"id": "codingPlugin.treeDepot",
8574
"name": "CODING 仓库"
8675
}
87-
],
88-
"WebviewContainerId": [
89-
{
90-
"id": "codingPlugin.webview",
91-
"title": "CODING 合并请求详情"
92-
}
9376
]
9477
}
9578
},

src/customEditors/mergeRequest.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import hx from 'hbuilderx';
2+
import path from 'path';
3+
import toast from '../utils/toast';
4+
5+
interface IMessage {
6+
command: string;
7+
data: any;
8+
}
9+
10+
const { CustomDocument, CustomEditorProvider } = hx.CustomEditor;
11+
12+
class MRCustomDocument extends CustomDocument {
13+
constructor(uri: string) {
14+
super(uri);
15+
}
16+
17+
dispose() {
18+
super.dispose();
19+
}
20+
}
21+
22+
export default class MRCustomEditorProvider extends CustomEditorProvider {
23+
constructor(context: any) {
24+
super();
25+
this.context = context;
26+
this.panel = null;
27+
}
28+
29+
listen() {
30+
this.panel.webView.onDidReceiveMessage((message: IMessage) => {
31+
console.log('webview receive message => ', message);
32+
const { command, data } = message;
33+
34+
switch (command) {
35+
case 'webview.mrDetail':
36+
hx.env.openExternal(data);
37+
break;
38+
case 'webview.toast':
39+
toast.error(data);
40+
break;
41+
default:
42+
hx.commands.executeCommand(command);
43+
return;
44+
}
45+
});
46+
47+
this.panel.onDidDispose(function () {
48+
console.log('custom editor disposed');
49+
});
50+
}
51+
52+
update(data: any) {
53+
const webview = this.panel.webView;
54+
const fileInfo = hx.Uri.file(path.resolve(__dirname, '../../out/webviews/main.js'));
55+
56+
webview.html = `
57+
<body>
58+
<div>
59+
<div id='root'></div>
60+
</div>
61+
<script>
62+
window.__CODING__ = '${JSON.stringify(data)}'
63+
</script>
64+
<script src='${fileInfo}'></script>
65+
</body>
66+
`;
67+
}
68+
69+
openCustomDocument(uri: any) {
70+
return Promise.resolve(new MRCustomDocument(uri));
71+
}
72+
73+
resolveCustomEditor(document: any, webViewPanel: IWebviewPanel) {
74+
this.panel = webViewPanel;
75+
this.listen();
76+
}
77+
78+
saveCustomDocument(document: any) {
79+
return true;
80+
}
81+
82+
saveCustomDocumentAs(document: any, destination: any) {
83+
return true;
84+
}
85+
}

src/webview.ts renamed to src/customEditors/webview.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import hx from 'hbuilderx';
22
import path from 'path';
3-
import toast from './utils/toast';
3+
import toast from '../utils/toast';
44

55
interface IMessage {
66
command: string;

src/extension.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import init from './init';
2-
import WebviewProvider from './webview';
32
import CodingServer from './services/codingServer';
43
import ACTIONS, { dispatch } from './utils/actions';
54
import { proxyCtx } from './utils/proxy';
@@ -18,7 +17,6 @@ const user = {
1817
async function activate(context: IContext) {
1918
// TODO: 认证,拿到用户信息
2019

21-
const webviewProvider = new WebviewProvider();
2220
const repoInfo = await CodingServer.getRepoParams();
2321
console.log('repoInfo ==> ', repoInfo);
2422

@@ -35,7 +33,6 @@ async function activate(context: IContext) {
3533
dispatch(ACTIONS.SET_CTX, {
3634
context,
3735
value: {
38-
webviewProvider,
3936
codingServer,
4037
depots: [],
4138
selectedDepot: null,

src/init.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import hx from 'hbuilderx';
22
import DepotTreeDataProvider from './trees/depot';
33
import MRTreeDataProvider from './trees/mr';
4+
import MRCustomEditorProvider from './customEditors/mergeRequest';
45

56
import toast from './utils/toast';
67
import ACTIONS, { dispatch } from './utils/actions';
8+
import { openHosts } from './utils/mr';
79
import { IDepot, IMRItem } from './typings/common';
810

911
const { registerCommand } = hx.commands;
1012

1113
export function registerCommands(context: IContext) {
12-
const { codingServer, webviewProvider } = context;
13-
14-
context.subscriptions.push(
15-
registerCommand('codingPlugin.helloWorld', () => {
16-
toast.info('hello');
17-
}),
18-
);
14+
const { codingServer } = context;
1915

2016
context.subscriptions.push(
2117
registerCommand('codingPlugin.mrTreeItemClick', async function ([team, mrItem]: [string, IMRItem]) {
18+
openHosts();
2219
const matchRes = mrItem.path.match(/\/p\/([^/]+)\/d\/([^/]+)\/git\/merge\/([0-9]+)/);
2320
if (matchRes) {
2421
const [, project, repo, mergeRequestIId] = matchRes;
2522
const result = await codingServer.getMrDetail({ team, project, repo, mergeRequestIId });
26-
webviewProvider.update({
23+
context.mrCustomEditor.update({
2724
session: codingServer.session,
2825
mrItem: result,
2926
repoInfo: {
@@ -90,8 +87,20 @@ export function clear(context: IContext) {
9087
context.subscriptions.forEach(({ dispose }) => dispose());
9188
}
9289

90+
export function registerCustomEditors(context: IContext) {
91+
const mrCustomEditor = new MRCustomEditorProvider(context);
92+
93+
hx.window.registerCustomEditorProvider('customEditor.mrDetail', mrCustomEditor);
94+
95+
dispatch(ACTIONS.SET_MR_CUSTOM_EDITOR, {
96+
context,
97+
value: mrCustomEditor,
98+
});
99+
}
100+
93101
export default function init(context: IContext) {
94102
registerCommands(context);
95103
createTreeViews(context);
104+
registerCustomEditors(context);
96105
workspaceInit();
97106
}

src/typings/hbuilderx.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ interface IContext {
99
subscriptions: any[];
1010
ctx: {
1111
[key: string]: any;
12-
},
12+
};
1313
[key: string]: any;
1414
}
1515

1616
interface IWebviewPanel {
1717
webView: any;
1818
postMessage: (message: any) => void;
19+
onDidDispose: (cb: () => void) => void;
20+
dispose: () => void;
1921
}
2022

2123
interface ITreeItem {

src/utils/actions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const enum ACTIONS {
22
SET_DEPOTS = 'SET_DEPOTS',
33
SET_SELECTED_DEPOT = 'SET_SELECTED_DEPOT',
44
SET_CTX = 'SET_CTX',
5+
SET_MR_CUSTOM_EDITOR = 'SET_MR_CUSTOM_EDITOR',
56
}
67

78
interface IPayload {
@@ -20,6 +21,9 @@ export const dispatch = (type: ACTIONS, { context, value }: IPayload) => {
2021
case ACTIONS.SET_CTX:
2122
context.ctx = value;
2223
break;
24+
case ACTIONS.SET_MR_CUSTOM_EDITOR:
25+
context.mrCustomEditor = value;
26+
break;
2327
default:
2428
return;
2529
}

src/utils/mr.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import hx from 'hbuilderx';
2+
import os from 'os';
13
import { IRepoInfo, IDepot, IUserInfo } from '../typings/common';
24

35
export const getMrListParams = (selectedDepot: IDepot, depots: IDepot[], user: IUserInfo): IRepoInfo | undefined => {
@@ -17,3 +19,21 @@ export const getMrListParams = (selectedDepot: IDepot, depots: IDepot[], user: I
1719
}
1820
}
1921
};
22+
23+
export const getHostsPath = () => {
24+
const operatingSystem = os.platform();
25+
let file;
26+
switch (operatingSystem) {
27+
case 'win32':
28+
break;
29+
case 'darwin':
30+
default:
31+
file = '/etc/hosts';
32+
}
33+
return file;
34+
};
35+
36+
export const openHosts = () => {
37+
const hostsPath = getHostsPath();
38+
hx.workspace.openTextDocument(hostsPath);
39+
};

0 commit comments

Comments
 (0)