Revert "[web] workspace/editor: vim mode (#1384)"

This reverts commit 73d7aaf522.
This commit is contained in:
Yangshun 2025-04-22 13:07:59 +08:00
parent f1f3fbaaa6
commit 4d4e553141
10 changed files with 43 additions and 171 deletions

View File

@ -106,7 +106,6 @@
"mitt": "^3.0.0",
"monaco-editor": "^0.40.0",
"monaco-themes": "^0.4.3",
"monaco-vim": "^0.4.2",
"negotiator": "^0.6.3",
"next": "14.2.15",
"next-contentlayer": "^0.3.4",

View File

@ -12,7 +12,6 @@ import { cdnUrl } from '~/utils/cdnUrl';
import { getErrorMessage } from '~/utils/getErrorMessage';
import getLanguageFromFilePath from './getLanguageFromFilePath';
import useMonacoEditorVimMode from './hooks/useMonacoEditorVimMode';
import useMonacoEditorAddActions from './useMonacoEditorAddActions';
import useMonacoEditorAddFormatter from './useMonacoEditorAddFormatter';
import useMonacoEditorOnShown from './useMonacoEditorOnShown';
@ -38,7 +37,6 @@ type Props = Readonly<
className?: string;
filePath?: string;
height?: React.ComponentProps<typeof MonacoEditor>['height'];
isVimModeEnabled?: boolean;
keepCurrentModel?: boolean;
language?: string;
onFocus?: () => void;
@ -95,14 +93,12 @@ export default function MonacoCodeEditor({
wordWrap = false,
readOnly = false,
keepCurrentModel = true,
isVimModeEnabled = false,
options,
}: Props) {
const intl = useIntl();
const monaco = useMonaco();
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const editorContainerRef = useRef<HTMLDivElement | null>(null);
const vimStatusBarRef = useRef<HTMLDivElement | null>(null);
const themeKey = useMonacoEditorTheme();
useEffect(() => {
@ -119,57 +115,46 @@ export default function MonacoCodeEditor({
useMonacoEditorAddActions(monaco, editorRef.current);
useMonacoEditorAddFormatter(monaco, editorRef.current, languageExt?.ext);
useMonacoEditorOnShown(editorContainerRef.current, onFocus);
useMonacoEditorVimMode(
editorRef.current,
isVimModeEnabled,
vimStatusBarRef.current,
);
return (
<>
<div
ref={vimStatusBarRef}
className="h-6 w-full px-3 font-mono text-sm/6 [&_input:focus]:outline-0 [&_input:focus]:ring-0 [&_input]:h-full [&_input]:border-0 [&_input]:bg-transparent [&_input]:text-sm/6"
<div
ref={editorContainerRef}
className={clsx(className, 'size-full')}
onFocus={onFocus}>
<MonacoEditor
height={height}
keepCurrentModel={keepCurrentModel}
language={language ?? languageExt?.language ?? undefined}
loading={
<EmptyState
iconClassName="animate-bounce"
size="sm"
title={intl.formatMessage({
defaultMessage: 'Loading editor',
description: 'Loading code editor',
id: 'AFsv0q',
})}
variant="editor_loading"
/>
}
options={{
fixedOverflowWidgets: true,
minimap: {
enabled: false,
},
readOnly,
wordWrap: wordWrap ? 'on' : 'off',
...options,
}}
path={filePath}
theme={themeKey}
value={value ?? ''}
onChange={(val) => onChange?.(val ?? '')}
onMount={(editorInstance) => {
editorRef.current = editorInstance;
onMount?.(editorInstance);
}}
/>
<div
ref={editorContainerRef}
className={clsx(className, 'size-full')}
onFocus={onFocus}>
<MonacoEditor
height={height}
keepCurrentModel={keepCurrentModel}
language={language ?? languageExt?.language ?? undefined}
loading={
<EmptyState
iconClassName="animate-bounce"
size="sm"
title={intl.formatMessage({
defaultMessage: 'Loading editor',
description: 'Loading code editor',
id: 'AFsv0q',
})}
variant="editor_loading"
/>
}
options={{
fixedOverflowWidgets: true,
minimap: {
enabled: false,
},
readOnly,
wordWrap: wordWrap ? 'on' : 'off',
...options,
}}
path={filePath}
theme={themeKey}
value={value ?? ''}
onChange={(val) => onChange?.(val ?? '')}
onMount={(editorInstance) => {
editorRef.current = editorInstance;
onMount?.(editorInstance);
}}
/>
</div>
</>
</div>
);
}

View File

@ -1,33 +0,0 @@
import type { editor } from 'monaco-editor';
// @ts-expect-error monaco-vim is not typed.
import { initVimMode } from 'monaco-vim';
import { useEffect, useRef } from 'react';
export default function useMonacoEditorVimMode(
editorInstance: editor.IStandaloneCodeEditor | null,
enabled: boolean,
vimStatusBar: HTMLDivElement | null,
) {
// AnyIntentional as monaco-vim is not typed.
const vimModeRef = useRef<AnyIntentional>(null);
useEffect(() => {
if (!editorInstance) {
return;
}
if (enabled && !vimModeRef.current) {
vimModeRef.current = initVimMode(editorInstance, vimStatusBar);
} else if (!enabled && vimModeRef.current) {
vimModeRef.current.dispose();
vimModeRef.current = null;
}
return () => {
if (vimModeRef.current) {
vimModeRef.current.dispose();
vimModeRef.current = null;
}
};
}, [editorInstance, enabled, vimStatusBar]);
}

View File

@ -1,17 +0,0 @@
import { useCallback } from 'react';
import { useLocalStorage } from 'usehooks-ts';
const VIM_MODE_LOCAL_STORAGE_KEY = 'gfe-vim-mode-enabled';
export function useVimMode() {
const [isVimModeEnabled, setIsVimModeEnabled] = useLocalStorage<boolean>(
VIM_MODE_LOCAL_STORAGE_KEY,
false,
);
const toggleVimMode = useCallback(() => {
setIsVimModeEnabled((prev) => !prev);
}, [setIsVimModeEnabled]);
return { isVimModeEnabled, toggleVimMode };
}

View File

@ -2,7 +2,7 @@
import { useState } from 'react';
import { RiArrowGoBackLine, RiPlayLine, RiSettings2Line } from 'react-icons/ri';
import { VscLayout, VscTerminal } from 'react-icons/vsc';
import { VscLayout } from 'react-icons/vsc';
import QuestionProgressAction from '~/components/interviews/questions/common/QuestionProgressAction';
import QuestionReportIssueButton from '~/components/interviews/questions/common/QuestionReportIssueButton';
@ -10,7 +10,6 @@ import type { QuestionMetadata } from '~/components/interviews/questions/common/
import { useIntl } from '~/components/intl';
import Button from '~/components/ui/Button';
import DropdownMenu from '~/components/ui/DropdownMenu';
import { useVimMode } from '~/components/workspace/common/editor/hooks/useVimMode';
import logEvent from '~/logging/logEvent';
@ -36,7 +35,6 @@ export default function JavaScriptCodingWorkspaceBottomBar({
const { status, runTests, submit, resetToDefaultCode } =
useCodingWorkspaceContext();
const [isLayoutDialogOpen, setIsLayoutDialogOpen] = useState(false);
const { isVimModeEnabled, toggleVimMode } = useVimMode();
const rightPostElements = (
<>
@ -155,24 +153,6 @@ export default function JavaScriptCodingWorkspaceBottomBar({
},
value: 'layout',
},
{
icon: VscTerminal,
label: isVimModeEnabled
? intl.formatMessage({
defaultMessage: 'Disable Vim Mode',
description:
'Button label to disable vim mode in editor',
id: 'I7qnG/',
})
: intl.formatMessage({
defaultMessage: 'Enable Vim Mode',
description:
'Button label to enable vim mode in editor',
id: 'ILCBgB',
}),
onClick: toggleVimMode,
value: 'vim-mode',
},
{
icon: RiArrowGoBackLine,
label: intl.formatMessage({

View File

@ -8,7 +8,6 @@ import { themeBorderColor } from '~/components/ui/theme';
import CodingWorkspaceEditorShortcutsButton from '~/components/workspace/common/editor/CodingWorkspaceEditorShortcutsButton';
import CodingWorkspaceResetButton from '~/components/workspace/common/editor/CodingWorkspaceResetButton';
import CodingWorkspaceThemeSelect from '~/components/workspace/common/editor/CodingWorkspaceThemeSelect';
import { useVimMode } from '~/components/workspace/common/editor/hooks/useVimMode';
import JavaScriptCodingWorkspaceWorkingLanguageSelect from '~/components/workspace/javascript/JavaScriptCodingWorkspaceWorkingLanguageSelect';
import { useJavaScriptCodingWorkspaceContext } from './JavaScriptCodingWorkspaceContext';
@ -37,7 +36,6 @@ export default function JavaScriptCodingWorkspaceCodeEditor({
useJavaScriptCodingWorkspaceContext();
const { sandpack } = useSandpack();
const intl = useIntl();
const { isVimModeEnabled } = useVimMode();
const isMounted = useIsMounted();
const { files, updateFile } = sandpack;
@ -120,7 +118,6 @@ export default function JavaScriptCodingWorkspaceCodeEditor({
)}
<MonacoCodeEditor
filePath={filePath}
isVimModeEnabled={isVimModeEnabled}
value={files[filePath].code}
onChange={(val) => {
updateFile(filePath, val ?? '');

View File

@ -18,7 +18,6 @@ import TextArea from '~/components/ui/TextArea';
import TextInput from '~/components/ui/TextInput';
import JavaScriptCodingWorkspaceWorkingLanguageSelect from './JavaScriptCodingWorkspaceWorkingLanguageSelect';
import { useVimMode } from '../common/editor/hooks/useVimMode';
import MonacoCodeEditor from '../common/editor/MonacoCodeEditor';
type Props = Readonly<{
@ -38,8 +37,6 @@ function JavaScriptCodingWorkspaceCommunitySolutionCreateTabImpl({
const intl = useIntl();
const trpcUtils = trpc.useUtils();
const { isVimModeEnabled } = useVimMode();
const { isLoading, mutateAsync: addSolution } =
trpc.questionCommunitySolution.javaScriptAdd.useMutation({
onSuccess: () => {
@ -161,11 +158,7 @@ function JavaScriptCodingWorkspaceCommunitySolutionCreateTabImpl({
name="code"
render={({ field: { ref: _, ...field } }) => (
<div className="flex flex-1 flex-col">
<MonacoCodeEditor
filePath="community-solution.ts"
isVimModeEnabled={isVimModeEnabled}
{...field}
/>
<MonacoCodeEditor filePath="community-solution.ts" {...field} />
{formState.isDirty && formState.errors.code?.message && (
<Text color="error" size="body2" weight="medium">
{formState.errors.code?.message}

View File

@ -2,7 +2,7 @@
import { useState } from 'react';
import { RiArrowGoBackLine, RiSettings2Line } from 'react-icons/ri';
import { VscLayout, VscTerminal } from 'react-icons/vsc';
import { VscLayout } from 'react-icons/vsc';
import { useShowAuthSignupDialogOnMaxPoints } from '~/components/auth/auth-points';
import QuestionProgressAction from '~/components/interviews/questions/common/QuestionProgressAction';
@ -15,7 +15,6 @@ import type {
import type { QuestionUserInterfaceMode } from '~/components/interviews/questions/common/QuestionUserInterfacePath';
import { useIntl } from '~/components/intl';
import DropdownMenu from '~/components/ui/DropdownMenu';
import { useVimMode } from '~/components/workspace/common/editor/hooks/useVimMode';
import UserInterfaceCodingWorkspaceLayoutDialog from './UserInterfaceCodingWorkspaceLayoutDialog';
import UserInterfaceCodingWorkspaceSaveButton from './UserInterfaceCodingWorkspaceSaveButton';
@ -51,7 +50,6 @@ export default function UserInterfaceCodingWorkspaceBottomBar({
useShowAuthSignupDialogOnMaxPoints();
const [isLayoutDialogOpen, setIsLayoutDialogOpen] = useState(false);
const { isVimModeEnabled, toggleVimMode } = useVimMode();
const leftElements = (
<div className="hidden flex-1 items-center gap-x-2 sm:inline-flex">
@ -84,22 +82,6 @@ export default function UserInterfaceCodingWorkspaceBottomBar({
},
value: 'layout',
},
{
icon: VscTerminal,
label: isVimModeEnabled
? intl.formatMessage({
defaultMessage: 'Disable Vim Mode',
description: 'Button label to disable vim mode in editor',
id: 'I7qnG/',
})
: intl.formatMessage({
defaultMessage: 'Enable Vim Mode',
description: 'Button label to enable vim mode in editor',
id: 'ILCBgB',
}),
onClick: toggleVimMode,
value: 'vim-mode',
},
{
icon: RiArrowGoBackLine,
label: intl.formatMessage({

View File

@ -11,7 +11,6 @@ import { themeBorderColor } from '~/components/ui/theme';
import CodingWorkspaceEditorShortcutsButton from '~/components/workspace/common/editor/CodingWorkspaceEditorShortcutsButton';
import CodingWorkspaceResetButton from '~/components/workspace/common/editor/CodingWorkspaceResetButton';
import CodingWorkspaceThemeSelect from '~/components/workspace/common/editor/CodingWorkspaceThemeSelect';
import { useVimMode } from '~/components/workspace/common/editor/hooks/useVimMode';
import MonacoCodeEditor from '~/components/workspace/common/editor/MonacoCodeEditor';
import { useUserInterfaceCodingWorkspaceSavesContext } from './UserInterfaceCodingWorkspaceSaveContext';
@ -42,7 +41,6 @@ export default function UserInterfaceCodingWorkspaceCodeEditor({
setShowLoadedFilesFromLocalStorageMessage,
resetToDefaultCode,
} = useCodingWorkspaceContext();
const { isVimModeEnabled } = useVimMode();
const isMounted = useIsMounted();
const onFocus = useCallback(() => {
@ -212,7 +210,6 @@ export default function UserInterfaceCodingWorkspaceCodeEditor({
)}
<MonacoCodeEditor
filePath={filePath}
isVimModeEnabled={isVimModeEnabled}
value={files[filePath].code}
onChange={(val) => {
updateFile(filePath, val ?? '');

View File

@ -469,9 +469,6 @@ importers:
monaco-themes:
specifier: ^0.4.3
version: 0.4.4
monaco-vim:
specifier: ^0.4.2
version: 0.4.2(monaco-editor@0.40.0)
negotiator:
specifier: ^0.6.3
version: 0.6.3
@ -11361,7 +11358,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.7.2)
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.3.3)
debug: 3.2.7
eslint: 8.34.0
eslint-import-resolver-node: 0.3.9
@ -11402,7 +11399,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.7.2)
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.3.3)
array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2
@ -15249,14 +15246,6 @@ packages:
fast-plist: 0.1.3
dev: false
/monaco-vim@0.4.2(monaco-editor@0.40.0):
resolution: {integrity: sha512-rdbQC3O2rmpwX2Orzig/6gZjZfH7q7TIeB+uEl49sa+QyNm3jCKJOw5mwxBdFzTqbrPD+URfg6A2lEkuL5kymw==}
peerDependencies:
monaco-editor: '*'
dependencies:
monaco-editor: 0.40.0
dev: false
/mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}