From a05c20165298cd7430a7fc1f703831730b562733 Mon Sep 17 00:00:00 2001 From: Domagoj Kriskovic Date: Wed, 31 May 2023 10:04:27 +0200 Subject: [PATCH] [cm6] indent figure modal generated code (#13213) * [cm6] indent figure modal generated code * fix: prettier * fix indenting issues * add licence on top * fix cypress tests GitOrigin-RevId: 8f74be537f19c2a29de3c742a9bbabe43b1ce40d --- .../components/figure-modal/figure-modal.tsx | 32 +++++++++++++----- .../extensions/toolbar/commands.ts | 3 +- .../source-editor/utils/prepare-lines.ts | 33 +++++++++++++++++++ .../components/figure-modal.spec.tsx | 10 +++--- 4 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 services/web/frontend/js/features/source-editor/utils/prepare-lines.ts diff --git a/services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx b/services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx index 146c8fd0df..95d973564b 100644 --- a/services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx +++ b/services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx @@ -21,6 +21,7 @@ import { import { ensureEmptyLine } from '../../extensions/toolbar/commands' import { useTranslation } from 'react-i18next' import useEventListener from '../../../../shared/hooks/use-event-listener' +import { prepareLines } from '../../utils/prepare-lines' export const FigureModal = memo(function FigureModal() { return ( @@ -138,8 +139,8 @@ const FigureModalContent = () => { dispatch({ error: String(error) }) return } - const labelCommand = includeLabel ? '\n\\label{fig:enter-label}' : '' - const captionCommand = includeCaption ? '\n\\caption{Enter Caption}' : '' + const labelCommand = includeLabel ? '\\label{fig:enter-label}' : '' + const captionCommand = includeCaption ? '\\caption{Enter Caption}' : '' if (figure) { // Updating existing figure @@ -150,14 +151,19 @@ const FigureModalContent = () => { // We should insert a caption changes.push({ from: figure.graphicsCommand.to, - insert: captionCommand, + insert: prepareLines( + ['', captionCommand], + view.state, + figure.graphicsCommand.to + ), }) } if (!hadLabelBefore && includeLabel) { + const from = figure.caption?.to ?? figure.graphicsCommand.to // We should insert a label changes.push({ - from: figure.caption?.to ?? figure.graphicsCommand.to, - insert: labelCommand, + from, + insert: prepareLines(['', labelCommand], view.state, from), }) } if (hadCaptionBefore && !includeCaption) { @@ -203,11 +209,19 @@ const FigureModalContent = () => { const { pos, suffix } = ensureEmptyLine(view.state, range) const widthArgument = width !== undefined ? `[width=${width}\\linewidth]` : '' - const graphicxCommand = `\\includegraphics${widthArgument}{${path}}` const changes: ChangeSpec = view.state.changes({ - insert: `\\begin{figure}\n\\centering\n${graphicxCommand}${captionCommand}${labelCommand}${ - labelCommand || captionCommand ? '\n' : '' // Add an extra newline if we've added a caption or label - }\\end{figure}${suffix}`, + insert: prepareLines( + [ + '\\begin{figure}', + '\t\\centering', + `\t\\includegraphics${widthArgument}{${path}}`, + `\t${captionCommand}` || null, + `\t${labelCommand}` || null, + `\\end{figure}${suffix}`, + ], + view.state, + pos + ), from: pos, }) diff --git a/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts b/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts index 067e29c68d..50b8ade9b6 100644 --- a/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts +++ b/services/web/frontend/js/features/source-editor/extensions/toolbar/commands.ts @@ -33,7 +33,8 @@ export const ensureEmptyLine = (state: EditorState, range: SelectionRange) => { let suffix = '' const line = state.doc.lineAt(pos) - if (line.length) { + + if (line.text.trim().length) { pos = Math.min(line.to + 1, state.doc.length) const nextLine = state.doc.lineAt(pos) diff --git a/services/web/frontend/js/features/source-editor/utils/prepare-lines.ts b/services/web/frontend/js/features/source-editor/utils/prepare-lines.ts new file mode 100644 index 0000000000..aa4d916906 --- /dev/null +++ b/services/web/frontend/js/features/source-editor/utils/prepare-lines.ts @@ -0,0 +1,33 @@ +/** + * Adapted from CodeMirror 6 (@codemirror/autocomplete), licensed under the MIT license: + * https://github.com/codemirror/autocomplete/blob/08f63add9f470a032d3802a4599caa86c75de5cb/src/snippet.ts#L29-L45 + */ + +import { indentUnit } from '@codemirror/language' +import { EditorState } from '@codemirror/state' + +// apply correct indentation to passed lines +export function prepareLines( + lines: (string | null)[], + state: EditorState, + pos: number +) { + const text = [] + const lineStart = [pos] + const lineObj = state.doc.lineAt(pos) + const baseIndent = /^\s*/.exec(lineObj.text)![0] + for (let line of lines) { + if (line === null) continue + if (text.length) { + let indent = baseIndent + const tabs = /^\t*/.exec(line)![0].length + for (let i = 0; i < tabs; i++) indent += state.facet(indentUnit) + lineStart.push(pos + indent.length - tabs) + line = indent + line.slice(tabs) + } + text.push(line) + pos += line.length + 1 + } + + return text.join('\n') +} diff --git a/services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx b/services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx index b4d30c7f9f..34e0e2c0b4 100644 --- a/services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx +++ b/services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx @@ -94,7 +94,7 @@ describe('', function () { cy.get('.cm-content').should( 'have.text', - '\\begin{figure}\\centeringEnter Caption🏷fig:enter-label\\end{figure}' + '\\begin{figure} \\centering Enter Caption 🏷fig:enter-label\\end{figure}' ) }) @@ -140,7 +140,7 @@ describe('', function () { cy.findByText('Insert figure').click() cy.get('.cm-content').should( 'have.text', - '\\begin{figure}\\centeringEnter Caption🏷fig:enter-label\\end{figure}' + '\\begin{figure} \\centering Enter Caption 🏷fig:enter-label\\end{figure}' ) }) }) @@ -214,7 +214,7 @@ describe('', function () { cy.get('.cm-content').should( 'have.text', - '\\begin{figure}\\centeringEnter Caption🏷fig:enter-label\\end{figure}' + '\\begin{figure} \\centering Enter Caption 🏷fig:enter-label\\end{figure}' ) }) @@ -242,7 +242,7 @@ describe('', function () { cy.get('.cm-content').should( 'have.text', - '\\begin{figure}\\centeringEnter Caption🏷fig:enter-label\\end{figure}' + '\\begin{figure} \\centering Enter Caption 🏷fig:enter-label\\end{figure}' ) }) }) @@ -292,7 +292,7 @@ describe('', function () { cy.get('.cm-content').should( 'have.text', - '\\begin{figure}\\centeringEnter Caption🏷fig:enter-label\\end{figure}' + '\\begin{figure} \\centering Enter Caption 🏷fig:enter-label\\end{figure}' ) }) })