Skip to content

Commit

Permalink
allow to copy non interactive shell output
Browse files Browse the repository at this point in the history
  • Loading branch information
christian-bromann committed Oct 17, 2022
1 parent 5a67e65 commit a186930
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 32 deletions.
8 changes: 8 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,11 @@ Supports changes to `$PATH`:
export PATH="/some/path:$PATH"
echo $PATH
```

## Copy From Result Cell

You can copy also results from the inline executed shell:

```sh { interactive=false }
openssl rand -base64 32
```
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
"stateful.runme/shell-stdout",
"stateful.runme/vercel-stdout",
"stateful.runme/deno-stdout",
"stateful.runme/html-stdout"
"stateful.runme/html-stdout",
"stateful.runme/output-items"
],
"requiresMessaging": "optional"
}
Expand Down
18 changes: 9 additions & 9 deletions src/client/components/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import '@vscode/webview-ui-toolkit/dist/button/index'

import { getContext } from '../utils'
import { Deployment } from '../../utils/deno/api_types'
import { DenoMessages } from '../../constants'
import type { DenoMessage } from '../../types'
import { ClientMessages } from '../../constants'
import type { ClientMessage } from '../../types'

import './spinner'

Expand Down Expand Up @@ -112,8 +112,8 @@ export class DenoOutput extends LitElement {

this.#isPromoting= true
this.requestUpdate()
ctx.postMessage(<DenoMessage<DenoMessages.promote>>{
type: DenoMessages.promote,
ctx.postMessage(<ClientMessage<ClientMessages.promote>>{
type: ClientMessages.promote,
output: {
id: deployment.projectId,
productionDeployment: deployment.id
Expand All @@ -129,19 +129,19 @@ export class DenoOutput extends LitElement {
return
}

ctx.onDidReceiveMessage((e: DenoMessage<DenoMessages>) => {
ctx.onDidReceiveMessage((e: ClientMessage<ClientMessages>) => {
if (!e.type.startsWith('deno:')) {
return
}

switch (e.type) {
case DenoMessages.deployed: {
const payload = e.output as DenoMessage<DenoMessages.deployed>['output']
case ClientMessages.deployed: {
const payload = e.output as ClientMessage<ClientMessages.deployed>['output']
this.#promoted = payload
break
}
case DenoMessages.update: {
const payload = e.output as DenoMessage<DenoMessages.update>['output']
case ClientMessages.update: {
const payload = e.output as ClientMessage<ClientMessages.update>['output']
this.deployed = Boolean(payload.deployed)
this.project = payload.project
this.deployments = payload.deployments
Expand Down
1 change: 1 addition & 0 deletions src/client/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './vercel'
export * from './deno'
export * from './vite'
export * from './svelte'
export * from './outputItems'
76 changes: 76 additions & 0 deletions src/client/components/outputItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { LitElement, css, html } from 'lit'
import { customElement, property } from 'lit/decorators.js'

import '@vscode/webview-ui-toolkit/dist/button/index'

import { getContext } from '../utils'
import { ClientMessage } from '../../types'
import { ClientMessages } from '../../constants'

@customElement('shell-output-items')
export class ShellOutputItems extends LitElement {
// Define scoped styles right with your component, in plain CSS
static styles = css`
.output-items {
display: flex;
width: 101%;
justify-content: flex-end;
}
vscode-button {
background: transparent;
color: #ccc;
transform: scale(.9);
}
vscode-button:hover {
background: var(--button-secondary-background);
}
vscode-button:focus {
outline: #007fd4 1px solid;
}
.icon {
width: 13px;
margin: 0 5px 0 -5px;
padding: 0;
}
`

@property({ type: String })
content = ''

// Render the UI as a function of component state
render() {
return html`<section class="output-items">
<vscode-button appearance="secondary" @click="${this.#copy}">
<svg
class="icon" width="16" height="16" viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg" fill="currentColor"
>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M4 4l1-1h5.414L14 6.586V14l-1 1H5l-1-1V4zm9 3l-3-3H5v10h8V7z"/>
<path fill-rule="evenodd" clip-rule="evenodd"
d="M3 1L2 2v10l1 1V2h6.414l-1-1H3z"/>
</svg>
Copy
</vscode-button>
</span>`
}

#copy () {
const ctx = getContext()

if (!ctx.postMessage) {
return
}

return navigator.clipboard.writeText(this.content).then(
() => ctx.postMessage!(<ClientMessage<ClientMessages.infoMessage>>{
type: ClientMessages.infoMessage,
output: 'Copied result content to clipboard!'
}),
(err) => ctx.postMessage!(<ClientMessage<ClientMessages.errorMessage>>{
type: ClientMessages.errorMessage,
output: `'Failed to copy to clipboard: ${err.message}!'`
})
)
}
}
5 changes: 5 additions & 0 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export const activate: ActivationFunction = (context: RendererContext<void>) =>
iframe.setAttribute('style', 'width: 100%; border: 0; height: 400px;')
element.appendChild(iframe)
break
case OutputType.outputItems:
const outputItemElem = document.createElement('shell-output-items')
outputItemElem.setAttribute('content', payload.output as string)
element.appendChild(outputItemElem)
break
case OutputType.error:
element.innerHTML = `⚠️ ${payload.output}`
break
Expand Down
5 changes: 4 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ export enum OutputType {
deno = 'stateful.runme/deno-stdout',
html = 'stateful.runme/html-stdout',
script = 'stateful.runme/script-stdout',
outputItems = 'stateful.runme/output-items',
error = 'error'
}

export enum DenoMessages {
export enum ClientMessages {
infoMessage = 'common:infoMessage',
errorMessage = 'common:errorMessage',
update = 'deno:deploymentUpdate',
deployed = 'deno:finishedDeployment',
promote = 'deno:promoteDeployment'
Expand Down
8 changes: 4 additions & 4 deletions src/extension/executors/deno/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { NotebookCellOutput, NotebookCellOutputItem, NotebookCellExecution } from 'vscode'

import { renderError } from '../utils'
import { OutputType, DenoMessages } from '../../../constants'
import { OutputType, ClientMessages } from '../../../constants'
import { ENV_STORE, DENO_ACCESS_TOKEN_KEY } from '../../constants'
import { API } from '../../../utils/deno/api'
import type { Kernel } from '../../kernel'
import type { CellOutput, DenoMessage } from '../../../types'
import type { CellOutput, ClientMessage } from '../../../types'

export async function deploy (
this: Kernel,
Expand Down Expand Up @@ -47,8 +47,8 @@ export async function deploy (
}

deployed = created > start
this.messaging.postMessage(<DenoMessage<DenoMessages.update>>{
type: DenoMessages.update,
this.messaging.postMessage(<ClientMessage<ClientMessages.update>>{
type: ClientMessages.update,
output: {
deployed,
deployments,
Expand Down
16 changes: 14 additions & 2 deletions src/extension/executors/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ async function shellExecutor(
const outputItems: string[] = []
const child = spawn(script, { cwd, shell: true, env })
console.log(`[Runme] Started process on pid ${child.pid}`)
// this needs more work / specification
/**
* this needs more work / specification
*/
const contentType = exec.cell.metadata.attributes?.['output']

/**
* handle output for stdout and stderr
*/
Expand All @@ -33,7 +36,16 @@ async function shellExecutor(
}, contentType)
}

exec.replaceOutput(new NotebookCellOutput([ item ]))
console.log('OITPUT TWIC')
exec.replaceOutput([
new NotebookCellOutput([ item ]),
new NotebookCellOutput([
NotebookCellOutputItem.json(<CellOutput<OutputType.outputItems>>{
type: OutputType.outputItems,
output: outputItems.join('\n')
}, OutputType.outputItems)
])
])
}

child.stdout.on('data', handleOutput)
Expand Down
20 changes: 13 additions & 7 deletions src/extension/kernel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import vscode, { ExtensionContext } from 'vscode'

import type { DenoMessage } from '../types'
import { DenoMessages } from '../constants'
import type { ClientMessage } from '../types'
import { ClientMessages } from '../constants'
import { API } from '../utils/deno/api'

import executor from './executors'
Expand Down Expand Up @@ -36,21 +36,27 @@ export class Kernel implements vscode.Disposable {
this.#disposables.forEach((d) => d.dispose())
}

async #handleRendererMessage ({ message }: { message: DenoMessage<DenoMessages> }) {
if (message.type === DenoMessages.promote) {
const payload = message as DenoMessage<DenoMessages.promote>
async #handleRendererMessage ({ message }: { message: ClientMessage<ClientMessages> }) {
if (message.type === ClientMessages.promote) {
const payload = message as ClientMessage<ClientMessages.promote>
const token = ENV_STORE.get(DENO_ACCESS_TOKEN_KEY)
if (!token) {
return
}

const api = API.fromToken(token)
const deployed = await api.promoteDeployment(payload.output.id, payload.output.productionDeployment)
this.messaging.postMessage(<DenoMessage<DenoMessages.deployed>>{
type: DenoMessages.deployed,
this.messaging.postMessage(<ClientMessage<ClientMessages.deployed>>{
type: ClientMessages.deployed,
output: deployed
})
} else if (message.type === ClientMessages.infoMessage) {
return vscode.window.showInformationMessage(message.output as string)
} else if (message.type === ClientMessages.errorMessage) {
return vscode.window.showInformationMessage(message.output as string)
}

console.log(`Unknown event type: ${message.type}`)
}

private async _executeAll(cells: vscode.NotebookCell[]) {
Expand Down
2 changes: 1 addition & 1 deletion src/extension/provider/copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import vscode from 'vscode'
export class CopyProvider implements vscode.NotebookCellStatusBarItemProvider {
async provideCellStatusBarItems(): Promise<vscode.NotebookCellStatusBarItem | undefined> {
const item = new vscode.NotebookCellStatusBarItem(
'$(clippy) Copy',
'$(copy) Copy',
vscode.NotebookCellStatusBarAlignment.Right
)
item.command = 'runme.copyCellToClipboard'
Expand Down
17 changes: 10 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OutputType, DenoMessages } from './constants'
import { OutputType, ClientMessages } from './constants'

export interface ParsedReadmeEntry {
name?: string
Expand Down Expand Up @@ -46,17 +46,20 @@ interface Payload {
type: string
payload: any
}
[OutputType.outputItems]: string
}

export interface DenoMessage <T extends DenoMessages> {
export interface ClientMessage <T extends ClientMessages> {
type: T
output: DenoMessagePayload[T]
output: ClientMessagePayload[T]
}
export interface DenoMessagePayload {
[DenoMessages.deployed]: boolean
[DenoMessages.update]: DenoPayload
[DenoMessages.promote]: {
export interface ClientMessagePayload {
[ClientMessages.deployed]: boolean
[ClientMessages.update]: DenoPayload
[ClientMessages.promote]: {
id: string
productionDeployment: string
}
[ClientMessages.infoMessage]: string
[ClientMessages.errorMessage]: string
}

0 comments on commit a186930

Please sign in to comment.