Skip to content

Commit

Permalink
use prettier command to format code
Browse files Browse the repository at this point in the history
  • Loading branch information
swk777 committed Sep 5, 2024
1 parent 6793ebb commit 24d57ac
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 24 deletions.
59 changes: 45 additions & 14 deletions packages/api/server/ws.mts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
removeCell,
updateCodeCellFilename,
addCell,
formatAndUpdateCodeCell,
} from '../session.mjs';
import { getSecrets } from '../config.mjs';
import type { SessionType } from '../types.mjs';
Expand All @@ -25,6 +26,7 @@ import type {
DepsValidatePayloadType,
CellStopPayloadType,
CellUpdatePayloadType,
CellFormatPayloadType,
TsServerStartPayloadType,
TsServerStopPayloadType,
CellDeletePayloadType,
Expand All @@ -41,6 +43,7 @@ import {
CellUpdatedPayloadSchema,
CellRenamePayloadSchema,
CellDeletePayloadSchema,
CellFormatPayloadSchema,
CellExecPayloadSchema,
CellStopPayloadSchema,
AiGenerateCellPayloadSchema,
Expand Down Expand Up @@ -413,6 +416,31 @@ async function cellFixDiagnostics(payload: AiFixDiagnosticsPayloadType) {
});
}

async function cellFormat(payload: CellFormatPayloadType) {
const session = await findSession(payload.sessionId);
console.log('in');
if (!session) {
throw new Error(`No session exists for session '${payload.sessionId}'`);
}
const cellBeforeUpdate = findCell(session, payload.cellId);

if (!cellBeforeUpdate || cellBeforeUpdate.type !== 'code') {
throw new Error(
`No cell exists or not a code cell for session '${payload.sessionId}' and cell '${payload.cellId}'`,
);
}
const result = await formatAndUpdateCodeCell(session, cellBeforeUpdate);
if (!result.success) {
return sendCellUpdateError(session, payload.cellId, result.errors);
}

const cell = result.cell as CodeCellType;

wss.broadcast(`session:${session.id}`, 'cell:updated', { cell });

refreshCodeCellDiagnostics(session, cell);
}

async function cellUpdate(payload: CellUpdatePayloadType) {
const session = await findSession(payload.sessionId);

Expand All @@ -427,7 +455,6 @@ async function cellUpdate(payload: CellUpdatePayloadType) {
`No cell exists for session '${payload.sessionId}' and cell '${payload.cellId}'`,
);
}

const result = await updateCell(session, cellBeforeUpdate, payload.updates);

if (!result.success) {
Expand All @@ -436,19 +463,7 @@ async function cellUpdate(payload: CellUpdatePayloadType) {

const cell = result.cell as CodeCellType;

if (session.language === 'typescript' && cell.type === 'code' && tsservers.has(session.id)) {
const tsserver = tsservers.get(session.id);

// This isn't intended for renaming, so the filenames
// and their resulting paths are expected to be the same
reopenFileInTsServer(tsserver, session, {
openFilename: cell.filename,
closeFilename: cell.filename,
source: cell.source,
});

requestAllDiagnostics(tsserver, session);
}
refreshCodeCellDiagnostics(session, cell);
}

async function cellRename(payload: CellRenamePayloadType) {
Expand Down Expand Up @@ -682,6 +697,21 @@ async function tsconfigUpdate(payload: TsConfigUpdatePayloadType) {
});
}

function refreshCodeCellDiagnostics(session: SessionType, cell: CodeCellType) {
if (session.language === 'typescript' && cell.type === 'code' && tsservers.has(session.id)) {
const tsserver = tsservers.get(session.id);

// This isn't intended for renaming, so the filenames
// and their resulting paths are expected to be the same
reopenFileInTsServer(tsserver, session, {
openFilename: cell.filename,
closeFilename: cell.filename,
source: cell.source,
});

requestAllDiagnostics(tsserver, session);
}
}
wss
.channel('session:*')
.incoming('cell:exec', CellExecPayloadSchema, cellExec)
Expand All @@ -690,6 +720,7 @@ wss
.incoming('cell:update', CellUpdatePayloadSchema, cellUpdate)
.incoming('cell:rename', CellRenamePayloadSchema, cellRename)
.incoming('cell:delete', CellDeletePayloadSchema, cellDelete)
.incoming('cell:format', CellFormatPayloadSchema, cellFormat)
.incoming('ai:generate', AiGenerateCellPayloadSchema, cellGenerate)
.incoming('ai:fix_diagnostics', AiFixDiagnosticsPayloadSchema, cellFixDiagnostics)
.incoming('deps:install', DepsInstallPayloadSchema, depsInstall)
Expand Down
31 changes: 31 additions & 0 deletions packages/api/session.mts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
import { fileExists } from './fs-utils.mjs';
import { validFilename } from '@srcbook/shared';
import { pathToCodeFile } from './srcbook/path.mjs';
import { exec } from 'node:child_process';

const sessions: Record<string, SessionType> = {};

Expand Down Expand Up @@ -293,6 +294,36 @@ export function updateCell(session: SessionType, cell: CellType, updates: CellUp
}
}

export async function formatCode(filePath: string) {
try {
const command = `npx prettier --no-error-on-unmatched-pattern ${filePath}`;

return new Promise((resolve, reject) => {
exec(command, async (error, stdout) => {
if (error) {
console.error(`exec error: ${error}`);
reject(error);
return;
}
resolve(stdout);
});
});
} catch (error) {
console.error('Formatting error:', error);
throw error;
}
}
export async function formatAndUpdateCodeCell(session: SessionType, cell: CodeCellType) {
try {
const formattedCode = await formatCode(pathToCodeFile(session.dir, cell.filename));
return updateCodeCell(session, cell, { source: formattedCode } as { source: string });
} catch (error) {
return Promise.resolve({
success: false,
errors: [{ message: 'An error occurred formatting the code.', attribute: 'formatting' }],
} as UpdateResultType);
}
}
export function sessionToResponse(session: SessionType) {
const result: Pick<SessionType, 'id' | 'cells' | 'language' | 'tsconfig.json' | 'openedAt'> = {
id: session.id,
Expand Down
5 changes: 4 additions & 1 deletion packages/api/srcbook/config.mts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export function buildJSPackageJson() {
return {
type: 'module',
dependencies: {},
dependencies: {
prettier: 'latest',
},
};
}

Expand All @@ -12,6 +14,7 @@ export function buildTSPackageJson() {
tsx: 'latest',
typescript: 'latest',
'@types/node': 'latest',
prettier: 'latest',
},
};
}
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/schemas/websockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export const CellUpdatePayloadSchema = z.object({
updates: CellUpdateAttrsSchema,
});

export const CellFormatPayloadSchema = z.object({
sessionId: z.string(),
cellId: z.string(),
});

export const AiGenerateCellPayloadSchema = z.object({
sessionId: z.string(),
cellId: z.string(),
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/types/websockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CellCreatePayloadSchema,
CellUpdatePayloadSchema,
CellUpdatedPayloadSchema,
CellFormatPayloadSchema,
CellRenamePayloadSchema,
CellDeletePayloadSchema,
AiGenerateCellPayloadSchema,
Expand All @@ -28,6 +29,7 @@ export type CellExecPayloadType = z.infer<typeof CellExecPayloadSchema>;
export type CellStopPayloadType = z.infer<typeof CellStopPayloadSchema>;
export type CellCreatePayloadType = z.infer<typeof CellCreatePayloadSchema>;
export type CellUpdatePayloadType = z.infer<typeof CellUpdatePayloadSchema>;
export type CellFormatPayloadType = z.infer<typeof CellFormatPayloadSchema>;
export type CellUpdatedPayloadType = z.infer<typeof CellUpdatedPayloadSchema>;
export type CellRenamePayloadType = z.infer<typeof CellRenamePayloadSchema>;
export type CellDeletePayloadType = z.infer<typeof CellDeletePayloadSchema>;
Expand Down
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"codemirror": "^6.0.1",
"lucide-react": "^0.378.0",
"lucide-react": "^0.380.0",
"marked": "catalog:",
"marked-react": "^2.0.0",
"react": "^18.2.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/web/src/clients/websocket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
AiGenerateCellPayloadSchema,
AiGeneratedCellPayloadSchema,
CellUpdatedPayloadSchema,
CellFormatPayloadSchema,
DepsValidateResponsePayloadSchema,
CellExecPayloadSchema,
CellStopPayloadSchema,
Expand Down Expand Up @@ -47,6 +48,7 @@ const OutgoingSessionEvents = {
'cell:update': CellUpdatePayloadSchema,
'cell:rename': CellRenamePayloadSchema,
'cell:delete': CellDeletePayloadSchema,
'cell:format': CellFormatPayloadSchema,
'ai:generate': AiGenerateCellPayloadSchema,
'ai:fix_diagnostics': AiFixDiagnosticsPayloadSchema,
'deps:install': DepsInstallPayloadSchema,
Expand Down
53 changes: 50 additions & 3 deletions packages/web/src/components/cells/code.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
LoaderCircle,
Maximize,
Minimize,
PaintbrushVertical,
} from 'lucide-react';
import TextareaAutosize from 'react-textarea-autosize';
import AiGenerateTipsDialog from '@/components/ai-generate-tips-dialog';
Expand All @@ -43,6 +44,7 @@ import { EditorView } from 'codemirror';
import { EditorState } from '@codemirror/state';
import { unifiedMergeView } from '@codemirror/merge';
import { type Diagnostic, linter } from '@codemirror/lint';
import { toast } from 'sonner';

const DEBOUNCE_DELAY = 500;
type CellModeType = 'off' | 'generating' | 'reviewing' | 'prompting' | 'fixing';
Expand All @@ -62,9 +64,7 @@ export default function CodeCell(props: {
const [prompt, setPrompt] = useState('');
const [newSource, setNewSource] = useState('');
const [fullscreen, setFullscreen] = useState(false);

const { aiEnabled } = useSettings();

useHotkeys(
'mod+enter',
() => {
Expand Down Expand Up @@ -97,6 +97,7 @@ export default function CodeCell(props: {

useEffect(() => {
function callback(payload: CellErrorPayloadType) {
console.log(payload);
if (payload.cellId !== cell.id) {
return;
}
Expand All @@ -106,6 +107,11 @@ export default function CodeCell(props: {
if (filenameError) {
setFilenameError(filenameError.message);
}

const formattingError = payload.errors.find((e) => e.attribute === 'formatting');
if (formattingError) {
toast.error(formattingError.message);
}
}

channel.on('cell:error', callback);
Expand Down Expand Up @@ -186,6 +192,12 @@ export default function CodeCell(props: {
setCellMode('off');
}

function formatCell() {
channel.push('cell:format', {
sessionId: session.id,
cellId: cell.id,
});
}
return (
<div id={`cell-${props.cell.id}`}>
<Dialog open={fullscreen} onOpenChange={setFullscreen}>
Expand Down Expand Up @@ -220,6 +232,7 @@ export default function CodeCell(props: {
setShowStdio={setShowStdio}
onAccept={onAcceptDiff}
onRevert={onRevertDiff}
formatCell={formatCell}
/>

{cellMode === 'reviewing' ? (
Expand All @@ -231,6 +244,7 @@ export default function CodeCell(props: {
<CodeEditor
cell={cell}
runCell={runCell}
formatCell={formatCell}
updateCellOnServer={updateCellOnServer}
readOnly={['generating', 'prompting', 'fixing'].includes(cellMode)}
/>
Expand Down Expand Up @@ -285,6 +299,7 @@ export default function CodeCell(props: {
setShowStdio={setShowStdio}
onAccept={onAcceptDiff}
onRevert={onRevertDiff}
formatCell={formatCell}
/>

{cellMode === 'reviewing' ? (
Expand All @@ -295,6 +310,7 @@ export default function CodeCell(props: {
<CodeEditor
cell={cell}
runCell={runCell}
formatCell={formatCell}
updateCellOnServer={updateCellOnServer}
readOnly={['generating', 'prompting'].includes(cellMode)}
/>
Expand Down Expand Up @@ -334,6 +350,7 @@ function Header(props: {
stopCell: () => void;
onAccept: () => void;
onRevert: () => void;
formatCell: () => void;
}) {
const {
cell,
Expand All @@ -351,6 +368,7 @@ function Header(props: {
prompt,
setPrompt,
stopCell,
formatCell,
} = props;

const { aiEnabled } = useSettings();
Expand Down Expand Up @@ -396,6 +414,22 @@ function Header(props: {
)}
>
<div className="flex items-center gap-1">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="icon"
size="icon"
disabled={cellMode !== 'off'}
onClick={formatCell}
tabIndex={1}
>
<PaintbrushVertical size={16} />
</Button>
</TooltipTrigger>
<TooltipContent>Format</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -626,11 +660,13 @@ function tsLinter(
function CodeEditor({
cell,
runCell,
formatCell,
updateCellOnServer,
readOnly,
}: {
cell: CodeCellType;
runCell: () => void;
formatCell: () => void;
updateCellOnServer: (cell: CodeCellType, attrs: CodeCellUpdateAttrsType) => void;
readOnly: boolean;
}) {
Expand All @@ -652,7 +688,18 @@ function CodeEditor({
javascript({ typescript: true }),
// wordHoverExtension,
tsLinter(cell, getTsServerDiagnostics, getTsServerSuggestions),
Prec.highest(keymap.of([{ key: 'Mod-Enter', run: evaluateModEnter }])),
Prec.highest(
keymap.of([
{ key: 'Mod-Enter', run: evaluateModEnter },
{
key: 'Mod-Shift-f',
run: () => {
formatCell();
return true;
},
},
]),
),
];
if (readOnly) {
extensions = extensions.concat([EditorView.editable.of(false), EditorState.readOnly.of(true)]);
Expand Down
Loading

0 comments on commit 24d57ac

Please sign in to comment.