diff --git a/src/argon.ts b/src/argon.ts index e463e8a..61518bc 100644 --- a/src/argon.ts +++ b/src/argon.ts @@ -29,8 +29,6 @@ function run(command: string) { process.stderr?.on('data', (data) => { log(data) }) - - return process } export function init(project: string, template: string, options: string[]) { @@ -38,7 +36,11 @@ export function init(project: string, template: string, options: string[]) { } export function serve(project: string, options: string[]) { - return run(`serve ${project} ${options.join(' ')}`) + const id = Date.now() + + run(`serve ${project} ${id} ${options.join(' ')}`) + + return id } export function exec(code: string) { @@ -52,3 +54,7 @@ export function studio() { export function plugin() { run('plugin') } + +export function stop(id: number) { + run(`stop ${id}`) +} diff --git a/src/commands/openMenu.ts b/src/commands/openMenu.ts index eba31c1..10ea934 100644 --- a/src/commands/openMenu.ts +++ b/src/commands/openMenu.ts @@ -5,25 +5,25 @@ import { State } from '../state' export function openMenu(state: State) { return vscode.commands.registerCommand('argon.openMenu', () => { - const quickPick = vscode.window.createQuickPick() - - quickPick.title = 'Argon' - quickPick.items = menu.items() - - quickPick.onDidAccept(async () => { - const item = quickPick.selectedItems[0] as menu.Item - - try { - await menu.onDidAccept(item.action, state) - } catch (err) { - if (err) { - logger.error(`Failed to run command: ${err}`) + const items = menu.items() + const quickPick = vscode.window + .showQuickPick(items, { + title: 'Argon', + }) + .then(async (item) => { + if (!item) { + return } - } - quickPick.dispose() - }) + item = item as menu.Item - quickPick.show() + try { + await menu.onDidAccept(item.action, state) + } catch (err) { + if (err) { + logger.error(`Failed to run command: ${err}`) + } + } + }) }) } diff --git a/src/extension.ts b/src/extension.ts index 98ec6c4..a98ca01 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,6 +4,8 @@ import * as installer from './installer' import * as logger from './logger' import { State } from './state' +let state: State + export async function activate(context: vscode.ExtensionContext) { console.log('Argon activated') @@ -18,7 +20,7 @@ export async function activate(context: vscode.ExtensionContext) { } } - const state = new State(context) + state = new State(context) Object.values(commands).forEach((command) => { context.subscriptions.push(command(state)) @@ -27,4 +29,7 @@ export async function activate(context: vscode.ExtensionContext) { state.show() } -export function deactivate() {} +export function deactivate() { + console.log('Argon deactivating') + state.cleanup() +} diff --git a/src/menu/index.ts b/src/menu/index.ts index d49bd4d..6caea3c 100644 --- a/src/menu/index.ts +++ b/src/menu/index.ts @@ -92,7 +92,7 @@ export async function onDidAccept(action: string, state: State) { sourcemap.handler() break case 'stop': - stop.handler() + stop.handler(state) break case 'exec': diff --git a/src/menu/serve.ts b/src/menu/serve.ts index f527a4e..01314fa 100644 --- a/src/menu/serve.ts +++ b/src/menu/serve.ts @@ -4,6 +4,7 @@ import * as util from '../util' import * as init from './init' import { Item } from '.' import { State } from '../state' +import { Session } from '../session' export const item: Item = { label: '$(rss) Serve', @@ -72,7 +73,9 @@ function getAddress(): Promise<{ }) } -function getOptions(context: vscode.ExtensionContext): Promise { +function getOptions( + context: vscode.ExtensionContext, +): Promise<[string[], boolean]> { return new Promise((resolve, reject) => { const options = [ { @@ -115,26 +118,10 @@ function getOptions(context: vscode.ExtensionContext): Promise { ) }) - const selectedOptions = items - .filter((item) => item.flag !== undefined) - .map((item) => item.flag) - - if (items.find((item) => item.id === 'customAddress')) { - const address = await getAddress() - - if (address.host) { - selectedOptions.push('--host ' + address.host) - } - - if (address.port) { - selectedOptions.push('--port ' + address.port) - } - } - - resolve( - // @ts-ignore - selectedOptions, - ) + resolve([ + items.flatMap((item) => (item.flag ? [item.flag] : [])), + items.find((item) => item.id === 'customAddress') !== undefined, + ]) }) }) } @@ -146,7 +133,31 @@ export async function handler(state: State) { project = await init.handler(state.context) } - const options = await getOptions(state.context) + const [options, customAddress] = await getOptions(state.context) + let address = { + host: 'localhost', + port: '8000', + } + + if (customAddress) { + const custom = await getAddress() + + if (custom.host) { + options.push('--host ' + custom.host) + address.host = custom.host + } + if (custom.port) { + options.push('--port ' + custom.port) + address.port = custom.port + } + } + + let name = util.getProjectName(project) + let id = argon.serve(project, options) + + const session = new Session(name, project, id).withAddress( + `${address.host}:${address.port}`, + ) - let process = argon.serve(project, options) + state.addSession(session) } diff --git a/src/menu/stop.ts b/src/menu/stop.ts index a4e1a73..1862663 100644 --- a/src/menu/stop.ts +++ b/src/menu/stop.ts @@ -1,5 +1,7 @@ import * as vscode from 'vscode' +import * as argon from '../argon' import { Item } from '.' +import { State } from '../state' export const item: Item = { label: '$(stop) Stop', @@ -7,4 +9,38 @@ export const item: Item = { action: 'stop', } -export function handler() {} +export function handler(state: State) { + let items = state.getSessions().map((session) => { + return { label: session.project, id: session.id } + }) + + if (items.length === 0) { + return vscode.window.showQuickPick([], { + title: 'No sessions to stop', + }) + } + + items.push({ label: '$(x)Stop all', id: 0 }) + + vscode.window + .showQuickPick(items, { + title: 'Select a session to stop', + }) + .then((item) => { + if (!item) { + return + } + + if (item.id === 0) { + items.forEach((item) => { + if (item.id !== 0) { + state.removeSession(item.id) + argon.stop(item.id) + } + }) + } else { + state.removeSession(item.id) + argon.stop(item.id) + } + }) +} diff --git a/src/session.ts b/src/session.ts index 2b34286..39a1196 100644 --- a/src/session.ts +++ b/src/session.ts @@ -1,5 +1,23 @@ -export interface Session { - name: string - project: string - started: number +export class Session { + private started = Date.now() + + public name: string + public project: string + public id: number + public address: string | undefined + + public constructor(name: string, project: string, id: number) { + this.name = name + this.project = project + this.id = id + } + + public withAddress(address: string) { + this.address = address + return this + } + + public get duration() { + return Date.now() - this.started + } } diff --git a/src/state.ts b/src/state.ts index cc9f77f..a13451d 100644 --- a/src/state.ts +++ b/src/state.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode' +import * as argon from './argon' import { Session } from './session' export class State { @@ -21,9 +22,22 @@ export class State { this.item.show() } + public addSession(session: Session) { + this.sessions.push(session) + } + + public removeSession(id: number) { + this.sessions = this.sessions.filter((session) => session.id !== id) + } + + public getSessions() { + return [...this.sessions] + } + public cleanup() { this.sessions.forEach((session) => { - console.log(session) + console.log(`Stopping session ${session.id}...`) + argon.stop(session.id) }) } } diff --git a/src/util.ts b/src/util.ts index b69139d..069e1c3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -26,3 +26,19 @@ export function findProjects(dir?: string): string[] { fs.statSync(path.join(dir!, entry)).isFile(), ) } + +export function getProjectName(project: string): string { + if (!path.isAbsolute(project)) { + let dir = getCurrentDir() + + if (!dir) { + throw new Error( + 'Cannot get project name without a workspace folder open!', + ) + } + + project = path.join(dir, project) + } + + return JSON.parse(fs.readFileSync(project, 'utf8')).name +}