diff --git a/services/web/frontend/js/features/source-editor/extensions/exception-logger.ts b/services/web/frontend/js/features/source-editor/extensions/exception-logger.ts deleted file mode 100644 index c36d318315..0000000000 --- a/services/web/frontend/js/features/source-editor/extensions/exception-logger.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Extension } from '@codemirror/state' -import { EditorView } from '@codemirror/view' -import { captureException } from '../../../infrastructure/error-reporter' - -/** - * A custom extension which configures the EditorView.exceptionSink facet - * so that exceptions are sent to Sentry with a `cm6-exception` tag. - */ -export const exceptionLogger = (): Extension => { - return EditorView.exceptionSink.of(exception => { - captureException(exception, { - tags: { handler: 'cm6-exception' }, - }) - }) -} diff --git a/services/web/frontend/js/features/source-editor/extensions/index.ts b/services/web/frontend/js/features/source-editor/extensions/index.ts index 87b11ad263..1462b2a191 100644 --- a/services/web/frontend/js/features/source-editor/extensions/index.ts +++ b/services/web/frontend/js/features/source-editor/extensions/index.ts @@ -29,7 +29,6 @@ import { filterCharacters } from './filter-characters' import { keybindings } from './keybindings' import { bracketMatching, bracketSelection } from './bracket-matching' import { verticalOverflow } from './vertical-overflow' -import { exceptionLogger } from './exception-logger' import { thirdPartyExtensions } from './third-party-extensions' import { lineNumbers } from './line-numbers' import { highlightActiveLine } from './highlight-active-line' @@ -132,7 +131,8 @@ export const createExtensions = (options: Record): Extension[] => [ highlightActiveLineGutter(), inlineBackground(options.visual.visual), codemirrorDevTools(), - exceptionLogger(), + // Send exceptions to Sentry + EditorView.exceptionSink.of(options.handleException), // CodeMirror extensions provided by modules moduleExtensions.map(extension => extension()), thirdPartyExtensions(), diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index 5346553e6f..6ac5849491 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts @@ -54,6 +54,8 @@ import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree- import { useUserSettingsContext } from '@/shared/context/user-settings-context' import { setDocName } from '@/features/source-editor/extensions/doc-name' import isValidTexFile from '@/main/is-valid-tex-file' +import { captureException } from '@/infrastructure/error-reporter' +import grammarlyExtensionPresent from '@/shared/utils/grammarly' function useCodeMirrorScope(view: EditorView) { const ide = useIdeContext() @@ -241,13 +243,31 @@ function useCodeMirrorScope(view: EditorView) { const { previewByPath } = useFileTreePathContext() + const showVisual = visual && isValidTexFile(docName) + const visualRef = useRef({ previewByPath, - visual, + visual: showVisual, }) const handleError = useErrorHandler() + const handleException = useCallback((exception: any) => { + captureException(exception, { + tags: { + handler: 'cm6-exception', + // which editor mode is active ('visual' | 'code') + ol_editor_mode: visualRef.current.visual ? 'visual' : 'code', + // which editor keybindings are active ('default' | 'vim' | 'emacs') + ol_editor_keybindings: settingsRef.current.mode, + // whether Writefull is present ('extension' | 'integration') + ol_extensions_writefull: window.writefull?.type, + // whether Grammarly is present + ol_extensions_grammarly: grammarlyExtensionPresent(), + }, + }) + }, []) + // create a new state when currentDoc changes useEffect(() => { @@ -268,6 +288,7 @@ function useCodeMirrorScope(view: EditorView) { visual: visualRef.current, changeManager: createChangeManager(view, currentDoc), handleError, + handleException, }), }) view.setState(state) @@ -297,7 +318,7 @@ function useCodeMirrorScope(view: EditorView) { } // IMPORTANT: This effect must not depend on anything variable apart from currentDoc, // as the editor state is recreated when the effect runs. - }, [view, currentDoc, handleError]) + }, [view, currentDoc, handleError, handleException]) useEffect(() => { if (docName) { @@ -314,8 +335,6 @@ function useCodeMirrorScope(view: EditorView) { } }, [view, docName]) - const showVisual = visual && isValidTexFile(docName) - useEffect(() => { visualRef.current.visual = showVisual view.dispatch(setVisual(visualRef.current))