Skip to content

Commit bff0bbf

Browse files
committed
feat(overmind-devtools-vscode): wIP add actionable codelenses to run action directly from inside vsc
1 parent d8b1ad7 commit bff0bbf

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

packages/node_modules/overmind-devtools-vscode/src/extension.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as vscode from 'vscode'
22
import { DevtoolsPanel } from './DevtoolsPanel'
33
import { log } from './utils/Logger'
44
import * as path from 'path'
5+
import { initRunActions } from './runActions'
56

67
const DevtoolBackend = require('overmind-devtools-client/DevtoolBackend')
78

@@ -29,8 +30,18 @@ export function activate(context: vscode.ExtensionContext) {
2930
},
3031
}
3132
const devtoolBackend = DevtoolBackend.create({
32-
onMessage(message) {
33-
// handle messages
33+
onMessage(messageStr: string) {
34+
const devMessage = JSON.parse(messageStr)
35+
const { appName, message } = devMessage
36+
if (message.type === 'init' || message.type === 're_init') {
37+
const actions = message.data.actions
38+
initRunActions(
39+
context,
40+
appName,
41+
devtoolBackend.clientSockets[appName],
42+
actions
43+
)
44+
}
3445
},
3546
onRelaunch() {
3647
devtoolBackend.close()
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import * as vscode from 'vscode'
2+
import { log } from './utils/Logger'
3+
4+
const findActionRegex = /^\s*export (?:const|let)\s([^:]+)\s*?:\s*?(?:Async)?Action(?:<([^>]*?)>)?\s*?=/g
5+
6+
export const initRunActions = (
7+
context: vscode.ExtensionContext,
8+
appName: string,
9+
appNameConnection: { send(payload: string): void },
10+
avaiableActions: string[]
11+
) => {
12+
const sendExecuteMessage = (actionName: string, payload: any = undefined) => {
13+
appNameConnection.send(
14+
JSON.stringify({
15+
appName,
16+
type: 'executeAction',
17+
data: {
18+
name: actionName,
19+
payload,
20+
},
21+
})
22+
)
23+
}
24+
const executeAction = (actionName: string, needsPayload: boolean) => {
25+
if (needsPayload) {
26+
vscode.window
27+
.showInputBox({
28+
ignoreFocusOut: true,
29+
prompt: `Payload for ${actionName}`,
30+
placeHolder: `{some:"data"}`,
31+
})
32+
.then((payload) => {
33+
// TODO: Detect primitive types e.g. numbers, strings, boolean
34+
if (payload !== undefined) {
35+
let data: any = payload
36+
if (!payload.startsWith('"')) {
37+
data = parseInt(payload, 10)
38+
}
39+
sendExecuteMessage(actionName, data)
40+
}
41+
})
42+
} else {
43+
sendExecuteMessage(actionName)
44+
}
45+
}
46+
const getExactOrSingleMatch = (searchActionName: string) => {
47+
if (avaiableActions.indexOf(searchActionName) !== -1) {
48+
return searchActionName
49+
}
50+
const matches = avaiableActions.filter((actionName) =>
51+
actionName.includes(searchActionName)
52+
)
53+
if (matches.length === 1) {
54+
return matches[0]
55+
}
56+
return null
57+
}
58+
59+
context.subscriptions.push(
60+
vscode.commands.registerCommand(
61+
'overmind-devtools.runAction',
62+
(preSelectActionName: string, needsPayload: boolean) => {
63+
const foundAction = getExactOrSingleMatch(preSelectActionName)
64+
if (foundAction) {
65+
executeAction(foundAction, needsPayload)
66+
} else {
67+
const quickPick = vscode.window.createQuickPick()
68+
quickPick.value = preSelectActionName
69+
quickPick.ignoreFocusOut = true
70+
quickPick.canSelectMany = false
71+
quickPick.title = 'Which action do you want to execute:'
72+
quickPick.items = avaiableActions.map((label) => ({
73+
label,
74+
}))
75+
quickPick.onDidAccept(() => {
76+
quickPick.dispose()
77+
const selectedAction = quickPick.selectedItems[0].label
78+
executeAction(selectedAction, needsPayload)
79+
})
80+
quickPick.onDidHide(() => quickPick.dispose())
81+
quickPick.show()
82+
}
83+
}
84+
)
85+
)
86+
87+
// TODO: How to clean up code lenses
88+
// adding this to the context isn't disposing
89+
// when the DevtoolsPanel is closed
90+
context.subscriptions.push(
91+
vscode.languages.registerCodeLensProvider(
92+
{ scheme: 'file', language: 'typescript' },
93+
{
94+
provideCodeLenses(
95+
doc: vscode.TextDocument,
96+
token: vscode.CancellationToken
97+
) {
98+
const text = doc.getText()
99+
const lenses: vscode.CodeLens[] = []
100+
const lines = text.split('\n')
101+
102+
lines.forEach((line: string, index) => {
103+
const match = findActionRegex.exec(line)
104+
if (match !== null) {
105+
const actionName = match[1]
106+
const needsPayload = match[2] !== undefined
107+
lenses.push(
108+
new vscode.CodeLens(
109+
new vscode.Range(
110+
new vscode.Position(index, match.index),
111+
new vscode.Position(index, match.index + match[0].length)
112+
),
113+
{
114+
title: `Run ${actionName}...`,
115+
command: 'overmind-devtools.runAction',
116+
arguments: [actionName, needsPayload],
117+
}
118+
)
119+
)
120+
}
121+
})
122+
123+
return lenses
124+
},
125+
resolveCodeLens(
126+
codeLens: vscode.CodeLens,
127+
token: vscode.CancellationToken
128+
) {
129+
return codeLens
130+
},
131+
}
132+
)
133+
)
134+
}

0 commit comments

Comments
 (0)