Skip to content

Commit

Permalink
feat: refactor Editor to use new FS
Browse files Browse the repository at this point in the history
  • Loading branch information
rahulyadav-57 committed Sep 2, 2024
1 parent edbd3e9 commit 3b8d1cc
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 49 deletions.
2 changes: 1 addition & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const nextConfig = withTM({
if (!options.isServer) {
config.plugins.push(
new MonacoWebpackPlugin({
languages: ["typescript"],
languages: ["typescript", "json"],
filename: "static/[name].worker.js",
}),
);
Expand Down
76 changes: 42 additions & 34 deletions src/components/workspace/Editor/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { useSettingAction } from '@/hooks/setting.hooks';
import { useWorkspaceActions } from '@/hooks/workspace.hooks';
import { ContractLanguage, Tree } from '@/interfaces/workspace.interface';
import EventEmitter from '@/utility/eventEmitter';
import { highlightCodeSnippets } from '@/utility/syntaxHighlighter';
import { fileTypeFromFileName } from '@/utility/utils';
import { delay, fileTypeFromFileName } from '@/utility/utils';
import EditorDefault, { loader } from '@monaco-editor/react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import { FC, useEffect, useRef, useState } from 'react';
// import { useLatest } from 'react-use';
import { useFile, useFileTab } from '@/hooks';
import { useProject } from '@/hooks/projectV2.hooks';
import { useLatest } from 'react-use';
import ReconnectingWebSocket from 'reconnecting-websocket';
import s from './Editor.module.scss';
import { editorOnMount } from './EditorOnMount';
type Monaco = typeof monaco;

interface Props {
file: Tree;
projectId: string;
className?: string;
}

const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
const { updateFileContent, getFileContent, updateOpenFile } =
useWorkspaceActions();
const Editor: FC<Props> = ({ className = '' }) => {
const { activeProject } = useProject();
const { getFile, saveFile: storeFileContent } = useFile();
const { fileTab } = useFileTab();

const { isFormatOnSave, getSettingStateByKey } = useSettingAction();

Expand All @@ -34,7 +35,7 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {

// Using this extra state to trigger save file from js event
const [saveFileCounter, setSaveFileCounter] = useState(1);
const latestFile = useLatest(file);
const latestFile = useLatest(fileTab.active);

const [initialFile, setInitialFile] = useState<Pick<
Tree,
Expand All @@ -53,17 +54,18 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {

const saveFile = async () => {
const fileContent = editorRef.current?.getValue() ?? '';
if (!fileContent) return;
if (!fileContent || !fileTab.active) return;
try {
if (isFormatOnSave()) {
editorRef.current?.trigger(
'editor',
'editor.action.formatDocument',
{},
);
await delay(200);
}
await updateFileContent(file.id, fileContent, projectId);
EventEmitter.emit('FILE_SAVED', { fileId: file.id });
await storeFileContent(fileTab.active, fileContent);
EventEmitter.emit('FILE_SAVED', { fileId: fileTab.active });
} catch (error) {
/* empty */
}
Expand All @@ -76,13 +78,16 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
window.MonacoEnvironment.getWorkerUrl = (_: string, label: string) => {
if (label === 'typescript') {
return '/_next/static/ts.worker.js';
} else if (label === 'json') {
return '/_next/static/json.worker.js';
}
return '/_next/static/editor.worker.js';
};
loader.config({ monaco });
if (!fileTab.active) return;
await highlightCodeSnippets(
loader,
fileTypeFromFileName(file.name) as ContractLanguage,
fileTypeFromFileName(fileTab.active) as ContractLanguage,
);
}

Expand Down Expand Up @@ -113,8 +118,10 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {

// If file is changed e.g. in case of build process then force update in editor
EventEmitter.on('FORCE_UPDATE_FILE', (filePath: string) => {
const latestFilePath = `/${activeProject}/${latestFile.current}`;

(async () => {
if (filePath !== latestFile.current.path) return;
if (filePath !== latestFilePath) return;
await fetchFileContent(true);
})().catch((error) => {
console.error('Error handling FORCE_UPDATE_FILE event:', error);
Expand All @@ -127,8 +134,10 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
}, [isLoaded]);

const fetchFileContent = async (force = false) => {
if ((!file.id || file.id === initialFile?.id) && !force) return;
let content = await getFileContent(file.id);
if (!fileTab.active) return;
if ((!fileTab.active || fileTab.active === initialFile?.id) && !force)
return;
let content = (await getFile(fileTab.active)) as string;
if (!editorRef.current) return;
let modelContent = editorRef.current.getValue();

Expand All @@ -141,25 +150,24 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
} else {
editorRef.current.setValue(content);
}
setInitialFile({ id: file.id, content });
setInitialFile({ id: fileTab.active, content });
editorRef.current.focus();
};

const markFileDirty = () => {
if (!editorRef.current) return;
const fileContent = editorRef.current.getValue();
if (
file.id !== initialFile?.id ||
!initialFile.content ||
initialFile.content === fileContent
) {
return;
}
if (!fileContent) {
return;
}

updateOpenFile(file.id, { isDirty: true }, projectId);
// if (!editorRef.current) return;
// const fileContent = editorRef.current.getValue();
// if (
// file.id !== initialFile?.id ||
// !initialFile.content ||
// initialFile.content === fileContent
// ) {
// return;
// }
// if (!fileContent) {
// return;
// }
// updateOpenFile(file.id, { isDirty: true }, projectId);
};

const initializeEditorMode = async () => {
Expand Down Expand Up @@ -192,7 +200,7 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
(async () => {
await fetchFileContent();
})().catch(() => {});
}, [file, isEditorInitialized]);
}, [fileTab.active, isEditorInitialized]);

useEffect(() => {
if (!monacoRef.current) {
Expand Down Expand Up @@ -229,12 +237,12 @@ const Editor: FC<Props> = ({ file, projectId, className = '' }) => {
</div>
<EditorDefault
className={s.editor}
path={file.id ? `${projectId}/${file.id}}` : ''}
path={fileTab.active ? `${activeProject}/${fileTab.active}` : ''}
theme="vs-theme-dark"
// height="90vh"
defaultLanguage={fileTypeFromFileName(file.name)}
defaultLanguage={fileTypeFromFileName(fileTab.active ?? '')}
// defaultLanguage={`func`}
defaultValue=""
defaultValue={undefined}
onChange={markFileDirty}
options={{
minimap: {
Expand Down
11 changes: 4 additions & 7 deletions src/components/workspace/WorkSpace/WorkSpace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { ProjectTemplate } from '@/components/template';
import { AppConfig } from '@/config/AppConfig';
import { useFileTab } from '@/hooks';
import { useLogActivity } from '@/hooks/logActivity.hooks';
import { useProject } from '@/hooks/projectV2.hooks';
import { useWorkspaceActions } from '@/hooks/workspace.hooks';
Expand Down Expand Up @@ -42,6 +43,7 @@ const WorkSpace: FC = () => {

const { tab } = router.query;
const { activeProject, newFileFolder } = useProject();
const { fileTab } = useFileTab();

const activeFile = workspaceAction.activeFile(activeProject as string);

Expand Down Expand Up @@ -205,13 +207,8 @@ const WorkSpace: FC = () => {
</div>

<div style={{ height: 'calc(100% - 43px)' }}>
{!activeProject && !activeFile && <ProjectTemplate />}
{activeFile && (
<Editor
file={activeFile as Tree}
projectId={activeProject as string}
/>
)}
{!fileTab.active && !activeFile && <ProjectTemplate />}
{fileTab.active && <Editor />}
</div>
</div>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const ManageProject: FC = () => {
deleteProject,
activeProject,
loadProjectFiles,
loadProjects,
} = useProject();

const projectHeader = () => (
Expand Down Expand Up @@ -104,6 +105,10 @@ const ManageProject: FC = () => {
openProject(activeProject as string).catch(() => {});
}, [activeProject]);

useEffect(() => {
loadProjects();
}, []);

return (
<div className={s.root}>
<div className={s.header}>
Expand Down
1 change: 1 addition & 0 deletions src/enum/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ export enum FileExtensionToFileType {
rs = FileType.Rust,
fc = FileType.FC,
tact = FileType.TACT,
json = FileType.JSON,
}
/* eslint-enable @typescript-eslint/prefer-literal-enum-member */
25 changes: 25 additions & 0 deletions src/hooks/file.hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import fileSystem from '@/lib/fs';
import { IDEContext } from '@/state/IDE.context';
import { useContext } from 'react';
import { baseProjectPath } from './projectV2.hooks';

const useFile = () => {
const { activeProject } = useContext(IDEContext);
const projectPath = `${baseProjectPath}${activeProject}`;
const getFile = async (filePath: string) => {
return fileSystem.readFile(`${projectPath}/${filePath}`);
};

const saveFile = async (filePath: string, content: string) => {
return fileSystem.writeFile(`${projectPath}/${filePath}`, content, {
overwrite: true,
});
};

return {
getFile,
saveFile,
};
};

export default useFile;
4 changes: 3 additions & 1 deletion src/hooks/fileTabs.hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fileSystem from '@/lib/fs';
import { IDEContext, IFileTab } from '@/state/IDE.context';
import EventEmitter from '@/utility/eventEmitter';
import { useContext } from 'react';

const useFileTab = () => {
Expand All @@ -20,7 +21,7 @@ const useFileTab = () => {
if (!(await fileSystem.exists(settingPath))) {
await fileSystem.writeFile(
settingPath,
JSON.stringify(defaultSetting, null, 2),
JSON.stringify(defaultSetting, null, 4),
{
overwrite: true,
},
Expand All @@ -47,6 +48,7 @@ const useFileTab = () => {
overwrite: true,
},
);
EventEmitter.emit('FORCE_UPDATE_FILE', settingPath);
} catch (error) {
console.error('Error syncing tab settings:', error);
}
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as useFile } from './file.hooks';
export { default as useFileTab } from './fileTabs.hooks';
10 changes: 4 additions & 6 deletions src/hooks/projectV2.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import fileSystem from '@/lib/fs';
import ZIP from '@/lib/zip';
import { RcFile } from 'antd/es/upload';
import cloneDeep from 'lodash.clonedeep';
import { useContext, useEffect } from 'react';
import { useContext } from 'react';
import { IDEContext } from '../state/IDE.context';

interface FileNode {
Expand All @@ -21,6 +21,8 @@ interface FileNode {
parent?: string;
}

export const baseProjectPath = '/';

export const useProject = () => {
const {
projects,
Expand All @@ -30,7 +32,6 @@ export const useProject = () => {
projectFiles,
setProjectFiles,
} = useContext(IDEContext);
const baseProjectPath = '/';

const loadProjects = async () => {
const projectCollection = await fileSystem.readdir(baseProjectPath, {
Expand Down Expand Up @@ -202,10 +203,6 @@ export const useProject = () => {
setActiveProject(projectName);
};

useEffect(() => {
loadProjects();
}, []);

return {
projects,
projectFiles,
Expand All @@ -218,6 +215,7 @@ export const useProject = () => {
renameProjectFile,
setActiveProject: updateActiveProject,
loadProjectFiles,
loadProjects,
};
};

Expand Down

0 comments on commit 3b8d1cc

Please sign in to comment.