diff --git a/services/web/frontend/js/features/pdf-preview/util/output-files.js b/services/web/frontend/js/features/pdf-preview/util/output-files.js index ce4a037444..64fe101b3f 100644 --- a/services/web/frontend/js/features/pdf-preview/util/output-files.js +++ b/services/web/frontend/js/features/pdf-preview/util/output-files.js @@ -155,6 +155,7 @@ export function buildLogEntryAnnotations(entries, fileTreeData, rootDocId) { type: entry.level === 'error' ? 'error' : 'warning', text: entry.message, source: 'compile', // NOTE: this is used in Ace for filtering the annotations + ruleId: entry.ruleId, }) } } diff --git a/services/web/frontend/js/features/source-editor/extensions/annotations.ts b/services/web/frontend/js/features/source-editor/extensions/annotations.ts index d99ef399d3..b0a13c3ddb 100644 --- a/services/web/frontend/js/features/source-editor/extensions/annotations.ts +++ b/services/web/frontend/js/features/source-editor/extensions/annotations.ts @@ -11,6 +11,7 @@ import { } from '@codemirror/state' import { Annotation } from '../../../../../types/annotation' import { debugConsole } from '@/utils/debugging' +import { sendMB } from '@/infrastructure/event-tracking' const compileLintSourceConf = new Compartment() @@ -56,29 +57,36 @@ const compileLogLintSource = (): Extension => const items: Diagnostic[] = [] const cursor = view.state.field(compileDiagnosticsState).iter() while (cursor.value !== null) { + const { diagnostic } = cursor.value items.push({ - ...cursor.value.diagnostic, + ...diagnostic, from: cursor.from, to: cursor.to, + renderMessage: () => renderMessage(diagnostic), }) cursor.next() } return items }, lintSourceConfig) -class DiagnosticRangeValue extends RangeValue { - constructor(public diagnostic: Diagnostic) { +interface CompileLogDiagnostic extends Diagnostic { + compile?: true + ruleId?: string +} + +class CompileLogDiagnosticRangeValue extends RangeValue { + constructor(public diagnostic: CompileLogDiagnostic) { super() } } -const setCompileDiagnosticsEffect = StateEffect.define() +const setCompileDiagnosticsEffect = StateEffect.define() /** * A state field for the compile log diagnostics */ export const compileDiagnosticsState = StateField.define< - RangeSet + RangeSet >({ create() { return RangeSet.empty @@ -88,7 +96,7 @@ export const compileDiagnosticsState = StateField.define< if (effect.is(setCompileDiagnosticsEffect)) { return RangeSet.of( effect.value.map(diagnostic => - new DiagnosticRangeValue(diagnostic).range( + new CompileLogDiagnosticRangeValue(diagnostic).range( diagnostic.from, diagnostic.to ) @@ -138,7 +146,7 @@ export const showCompileLogDiagnostics = (show: boolean) => { const convertAnnotationToDiagnostic = ( doc: Text, annotation: Annotation -): Diagnostic => { +): CompileLogDiagnostic => { if (annotation.row < 0) { throw new Error(`Invalid annotation row ${annotation.row}`) } @@ -150,6 +158,27 @@ const convertAnnotationToDiagnostic = ( to: line.to, // NOTE: highlight whole line as synctex doesn't output column number severity: annotation.type, message: annotation.text, - // source: annotation.source, // NOTE: the source is displayed in the tooltip + ruleId: annotation.ruleId, + compile: true, } } + +export const renderMessage = ( + diagnostic: Pick< + CompileLogDiagnostic, + 'message' | 'severity' | 'ruleId' | 'compile' + > +) => { + const { message, severity, ruleId, compile = false } = diagnostic + + const div = document.createElement('div') + div.textContent = message + + window.setTimeout(() => { + if (div.isConnected) { + sendMB('lint-gutter-marker-view', { severity, ruleId, compile }) + } + }, 500) // 500ms delay to indicate intention, rather than accidental hover + + return div +} diff --git a/services/web/frontend/js/features/source-editor/languages/latex/linter/errors-to-diagnostics.ts b/services/web/frontend/js/features/source-editor/languages/latex/linter/errors-to-diagnostics.ts index f3e095c52c..c2e9646bf5 100644 --- a/services/web/frontend/js/features/source-editor/languages/latex/linter/errors-to-diagnostics.ts +++ b/services/web/frontend/js/features/source-editor/languages/latex/linter/errors-to-diagnostics.ts @@ -1,5 +1,6 @@ import { Diagnostic } from '@codemirror/lint' import { Range } from '../../../utils/range' +import { renderMessage } from '@/features/source-editor/extensions/annotations' export type LintError = { startPos: number @@ -78,12 +79,17 @@ export const errorsToDiagnostics = ( const newStart = movableStart ? cursorPosition : errorRange.from const newEnd = movableEnd ? cursorPosition : errorRange.to - // Create the diagnostic - diagnostics.push({ + const diagnostic: Diagnostic = { from: newStart, to: newEnd, severity: error.type, message: error.text, + } + + // Create the diagnostic + diagnostics.push({ + ...diagnostic, + renderMessage: () => renderMessage(diagnostic), }) } diff --git a/services/web/types/annotation.ts b/services/web/types/annotation.ts index bae368b7c5..9d5f974b6f 100644 --- a/services/web/types/annotation.ts +++ b/services/web/types/annotation.ts @@ -3,4 +3,5 @@ export type Annotation = { type: 'info' | 'warning' | 'error' text: string source?: string + ruleId?: string }