diff --git a/services/web/frontend/js/features/source-editor/commands/ranges.ts b/services/web/frontend/js/features/source-editor/commands/ranges.ts index 04859d2a77..09d3b1ad2f 100644 --- a/services/web/frontend/js/features/source-editor/commands/ranges.ts +++ b/services/web/frontend/js/features/source-editor/commands/ranges.ts @@ -1,5 +1,10 @@ import { EditorView } from '@codemirror/view' -import { EditorSelection, EditorState, SelectionRange } from '@codemirror/state' +import { + EditorSelection, + EditorState, + SelectionRange, + TransactionSpec, +} from '@codemirror/state' import { ensureSyntaxTree, foldedRanges, @@ -408,7 +413,10 @@ function bubbleUpRange( return range } -export function toggleRanges(command: string) { +export function toggleRanges( + command: string, + annotations?: TransactionSpec['annotations'] +) { /* There are a number of situations we need to handle in this function. * In the following examples, the selection range is marked within <> @@ -745,7 +753,7 @@ export function toggleRanges(command: string) { // Shouldn't happen, but default to just wrapping the content return wrapRangeInCommand(view.state, range, command) }), - { scrollIntoView: true } + { scrollIntoView: true, annotations } ) return true } 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 7cf7257165..0621f58db4 100644 --- a/services/web/frontend/js/features/source-editor/extensions/index.ts +++ b/services/web/frontend/js/features/source-editor/extensions/index.ts @@ -49,6 +49,7 @@ import { toolbarPanel } from './toolbar/toolbar-panel' import { geometryChangeEvent } from './geometry-change-event' import { isSplitTestEnabled } from '../../../utils/splitTestUtils' import { completionLogger } from './completion-logger' +import { shortcutLogger } from './shortcut-logger' const moduleExtensions: Array<() => Extension> = importOverleafModules( 'sourceEditorExtensions' @@ -130,6 +131,7 @@ export const createExtensions = (options: Record): Extension[] => [ highlightActiveLineGutter(), inlineBackground(options.visual.visual), completionLogger, + shortcutLogger, codemirrorDevTools(), exceptionLogger(), // CodeMirror extensions provided by modules diff --git a/services/web/frontend/js/features/source-editor/extensions/shortcut-logger.ts b/services/web/frontend/js/features/source-editor/extensions/shortcut-logger.ts new file mode 100644 index 0000000000..471e4326ec --- /dev/null +++ b/services/web/frontend/js/features/source-editor/extensions/shortcut-logger.ts @@ -0,0 +1,20 @@ +import { ViewPlugin } from '@codemirror/view' +import { emitShortcutEvent } from './toolbar/utils/analytics' +import { runShortcut } from '../languages/latex/shortcuts' + +/** + * A custom view plugin that watches for transactions with the `runShortcut` annotation, + * and logs the shortcut name for analytics. + */ +export const shortcutLogger = ViewPlugin.define(view => { + return { + update(update) { + for (const tr of update.transactions) { + const action = tr.annotation(runShortcut) + if (action) { + emitShortcutEvent(view, action) + } + } + }, + } +}) diff --git a/services/web/frontend/js/features/source-editor/extensions/toolbar/utils/analytics.ts b/services/web/frontend/js/features/source-editor/extensions/toolbar/utils/analytics.ts index c1519c7791..6a42045a7c 100644 --- a/services/web/frontend/js/features/source-editor/extensions/toolbar/utils/analytics.ts +++ b/services/web/frontend/js/features/source-editor/extensions/toolbar/utils/analytics.ts @@ -18,3 +18,7 @@ export function emitToolbarEvent(view: EditorView, command: string) { export function emitCompletionEvent(view: EditorView, command: string) { emitCommandEvent(view, 'codemirror-completion-event', command) } + +export function emitShortcutEvent(view: EditorView, command: string) { + emitCommandEvent(view, 'codemirror-shortcut-event', command) +} diff --git a/services/web/frontend/js/features/source-editor/languages/latex/shortcuts.ts b/services/web/frontend/js/features/source-editor/languages/latex/shortcuts.ts index 00859605d5..c09572643b 100644 --- a/services/web/frontend/js/features/source-editor/languages/latex/shortcuts.ts +++ b/services/web/frontend/js/features/source-editor/languages/latex/shortcuts.ts @@ -1,4 +1,4 @@ -import { Prec } from '@codemirror/state' +import { Annotation, Prec } from '@codemirror/state' import { keymap } from '@codemirror/view' import { toggleRanges } from '../../commands/ranges' @@ -9,14 +9,16 @@ export const shortcuts = () => { key: 'Ctrl-b', mac: 'Mod-b', preventDefault: true, - run: toggleRanges('\\textbf'), + run: toggleRanges('\\textbf', runShortcut.of('toggle-bold')), }, { key: 'Ctrl-i', mac: 'Mod-i', preventDefault: true, - run: toggleRanges('\\textit'), + run: toggleRanges('\\textit', runShortcut.of('toggle-italic')), }, ]) ) } + +export const runShortcut = Annotation.define()