Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 24 additions & 22 deletions pdl-live-react/src/view/masonry/MasonryCombo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Button,
BackToTop,
Modal,
type ModalProps,
ModalBody,
ModalFooter,
ModalHeader,
Expand All @@ -28,6 +27,7 @@ import MasonryTileWrapper from "./MasonryTileWrapper"
import Toolbar, { type SML } from "./Toolbar"

import computeModel from "./model"
import ConditionVariable from "./condvar"
import {
hasContextInformation,
hasTimingInformation,
Expand All @@ -39,11 +39,7 @@ import RunningIcon from "@patternfly/react-icons/dist/esm/icons/running-icon"

import "./Masonry.css"

export type Runner = (
block: NonScalarPdlBlock,
onExit: () => void,
modalVariant?: ModalProps["variant"],
) => void
export type Runner = (block: NonScalarPdlBlock, onExit: () => void) => void

type Props = {
value: string
Expand All @@ -60,9 +56,6 @@ function setSMLUserSetting(sml: SML) {

/** Combines <Masonry/>, <Timeline/>, ... */
export default function MasonryCombo({ value, setValue }: Props) {
const [modalVariant, setModalVariant] =
useState<ModalProps["variant"]>("large")

const block = useMemo(() => {
if (value) {
try {
Expand All @@ -83,11 +76,17 @@ export default function MasonryCombo({ value, setValue }: Props) {
cmd: string
args?: string[]
onExit?: (exitCode: number) => void
cancelCondVar?: ConditionVariable
}>(null)
const cancelModal = useCallback(
() => modalContent?.cancelCondVar?.signal(),
[modalContent?.cancelCondVar],
)
const closeModal = useCallback(() => {
modalContent?.cancelCondVar?.signal()
setModalContent(null)
setModalIsDone(-1)
}, [setModalContent, setModalIsDone])
}, [modalContent?.cancelCondVar, setModalContent, setModalIsDone])
const onExit = useCallback(
(exitCode: number) => {
setModalIsDone(exitCode)
Expand All @@ -97,19 +96,16 @@ export default function MasonryCombo({ value, setValue }: Props) {
},
[setModalIsDone, modalContent],
)
useEffect(() => setModalIsDone(-2), [modalContent])

// special form of setModalContent for running a PDL program
const run = useCallback<Runner>(
async (runThisBlock, onExit, modalVariant) => {
async (runThisBlock, onExit) => {
if (!isNonScalarPdlBlock(block)) {
onExit()
return
}

if (modalVariant) {
setModalVariant(modalVariant)
}

const [cmd, input, output] = (await invoke("replay_prep", {
trace: JSON.stringify(runThisBlock),
name:
Expand All @@ -132,6 +128,7 @@ export default function MasonryCombo({ value, setValue }: Props) {
...(!data ? [] : ["--data", JSON.stringify(data)]),
input,
],
cancelCondVar: new ConditionVariable(),
onExit: async () => {
onExit()
try {
Expand Down Expand Up @@ -198,15 +195,11 @@ export default function MasonryCombo({ value, setValue }: Props) {

<BackToTop scrollableSelector=".pdl-masonry-page-section" />

<Modal
variant={modalVariant}
isOpen={!!modalContent}
onClose={closeModal}
>
<Modal variant="large" isOpen={!!modalContent} onClose={closeModal}>
<ModalHeader
title={modalContent?.header}
titleIconVariant={
modalIsDone === -1
modalIsDone < 0
? RunningIcon
: modalIsDone === 0
? "success"
Expand All @@ -218,6 +211,7 @@ export default function MasonryCombo({ value, setValue }: Props) {
<RunTerminal
cmd={modalContent?.cmd ?? ""}
args={modalContent?.args}
cancel={modalContent?.cancelCondVar}
onExit={onExit}
/>
</Suspense>
Expand All @@ -228,10 +222,18 @@ export default function MasonryCombo({ value, setValue }: Props) {
key="Close"
variant={modalIsDone > 0 ? "danger" : "primary"}
onClick={closeModal}
isDisabled={modalIsDone === -1}
isDisabled={modalIsDone < 0}
>
Close
</Button>
<Button
key="Cancel"
variant="secondary"
onClick={cancelModal}
isDisabled={modalIsDone !== -2}
>
Cancel
</Button>
</ModalFooter>
</Modal>
</>
Expand Down
2 changes: 1 addition & 1 deletion pdl-live-react/src/view/masonry/MasonryTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default function MasonryTile({
const myRun = useCallback(() => {
if (block && run) {
setIsRunning(true)
run(block, () => setIsRunning(false), "medium")
run(block, () => setIsRunning(false))
}
}, [block, run, setIsRunning])

Expand Down
29 changes: 29 additions & 0 deletions pdl-live-react/src/view/masonry/condvar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export default class ConditionVariable {
private condition: boolean = false
private waitingPromises: {
resolve: () => void
reject: (reason?: unknown) => void
}[] = []

public async wait(): Promise<void> {
if (this.condition) {
return Promise.resolve()
}

return new Promise((resolve, reject) => {
this.waitingPromises.push({ resolve, reject })
})
}

public signal(): void {
if (this.waitingPromises.length > 0) {
const { resolve } = this.waitingPromises.shift()!
resolve()
this.condition = true
}
}

public reset(): void {
this.condition = false
}
}
21 changes: 18 additions & 3 deletions pdl-live-react/src/view/term/RunTerminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ import { ClipboardAddon } from "@xterm/addon-clipboard"
import "./RunTerminal.css"

type Props = {
/** The cmd part of `cmd ...args` */
cmd: string

/** The args part of `cmd ...args */
args?: string[]

/** A callback provided by caller to be invoked upon pty completion */
onExit?: (exitCode: number) => void

/** A condition variable used by caller to request pty cancellation */
cancel?: import("../masonry/condvar").default
}

export default function RunTerminal({ cmd, args = [], onExit }: Props) {
export default function RunTerminal({ cmd, args = [], onExit, cancel }: Props) {
const ref = createRef<HTMLDivElement>()
const [term, setTerm] = useState<null | Terminal>(null)
const [exitCode, setExitCode] = useState(-1)

/** Schema adapter from our props.onExit to that of tauri-pty */
const onExit2 = useCallback(
({ exitCode }: { exitCode: number }) => {
setExitCode(exitCode)
Expand All @@ -28,7 +37,8 @@ export default function RunTerminal({ cmd, args = [], onExit }: Props) {
[onExit, setExitCode],
)

useEffect(() => setExitCode(-1), [cmd, args, onExit])
/** Re-initialization of exit code if props change */
useEffect(() => setExitCode(-1), [cmd, args, onExit, cancel])

// Why a two-stage useEffect? Otherwise: cannot read properties of
// undefined (reading 'dimensions')
Expand Down Expand Up @@ -64,6 +74,11 @@ export default function RunTerminal({ cmd, args = [], onExit }: Props) {
rows: term.rows,
})

/** Respond to cancellation request by killing the pty */
cancel?.wait().then(() => {
pty.kill()
})

pty.onData((data) => term.write(data))
term.onData((data) => pty.write(data))

Expand All @@ -78,7 +93,7 @@ export default function RunTerminal({ cmd, args = [], onExit }: Props) {
}
}
}
}, [term, ref, exitCode, args, cmd, onExit2])
}, [term, ref, exitCode, cmd, args, cancel, onExit2])

return (
<div className="pdl-run-terminal" ref={ref} style={{ height: "600px" }} />
Expand Down