mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
feat: making highlighting of errors more specific (#19963)
GitOrigin-RevId: 63bc147e18e80c1e070722bc70114f8fca8509ae
This commit is contained in:
parent
31bb5939a1
commit
607b3e3494
6 changed files with 68 additions and 12 deletions
|
@ -183,6 +183,7 @@ export function buildLogEntryAnnotations(entries, fileTreeData, rootDocId) {
|
|||
text: entry.message,
|
||||
source: 'compile', // NOTE: this is used in Ace for filtering the annotations
|
||||
ruleId: entry.ruleId,
|
||||
command: entry.command,
|
||||
}
|
||||
|
||||
// set firstOnLine for the first non-typesetting annotation on a line
|
||||
|
|
|
@ -2,17 +2,19 @@ import { EditorView, ViewUpdate } from '@codemirror/view'
|
|||
import { Diagnostic, linter, lintGutter } from '@codemirror/lint'
|
||||
import {
|
||||
Compartment,
|
||||
EditorState,
|
||||
Extension,
|
||||
Line,
|
||||
RangeSet,
|
||||
RangeValue,
|
||||
StateEffect,
|
||||
StateField,
|
||||
Text,
|
||||
} from '@codemirror/state'
|
||||
import { Annotation } from '../../../../../types/annotation'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { sendMB } from '@/infrastructure/event-tracking'
|
||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||
import { syntaxTree } from '@codemirror/language'
|
||||
|
||||
interface CompileLogDiagnostic extends Diagnostic {
|
||||
compile?: true
|
||||
|
@ -142,14 +144,17 @@ export const compileDiagnosticsState = StateField.define<
|
|||
},
|
||||
})
|
||||
|
||||
export const setAnnotations = (doc: Text, annotations: Annotation[]) => {
|
||||
export const setAnnotations = (
|
||||
state: EditorState,
|
||||
annotations: Annotation[]
|
||||
) => {
|
||||
const diagnostics: CompileLogDiagnostic[] = []
|
||||
|
||||
for (const annotation of annotations) {
|
||||
// ignore "whole document" (row: -1) annotations
|
||||
if (annotation.row !== -1) {
|
||||
try {
|
||||
diagnostics.push(convertAnnotationToDiagnostic(doc, annotation))
|
||||
diagnostics.push(...convertAnnotationToDiagnostic(state, annotation))
|
||||
} catch (error) {
|
||||
// ignore invalid annotations
|
||||
debugConsole.debug('invalid annotation position', error)
|
||||
|
@ -171,19 +176,60 @@ export const showCompileLogDiagnostics = (show: boolean) => {
|
|||
}
|
||||
}
|
||||
|
||||
const convertAnnotationToDiagnostic = (
|
||||
doc: Text,
|
||||
const commandRanges = (state: EditorState, line: Line, command: string) => {
|
||||
const ranges: { from: number; to: number }[] = []
|
||||
|
||||
syntaxTree(state).iterate({
|
||||
enter(nodeRef) {
|
||||
if (nodeRef.type.is('CtrlSeq')) {
|
||||
const { from, to } = nodeRef
|
||||
if (command === state.sliceDoc(from, to)) {
|
||||
ranges.push({ from, to })
|
||||
}
|
||||
}
|
||||
},
|
||||
from: line.from,
|
||||
to: line.to,
|
||||
})
|
||||
|
||||
return ranges.slice(0, 1) // NOTE: only highlighting the first match on a line, to avoid duplicate messages
|
||||
}
|
||||
|
||||
const chooseHighlightRanges = (
|
||||
state: EditorState,
|
||||
line: Line,
|
||||
annotation: Annotation
|
||||
): CompileLogDiagnostic => {
|
||||
) => {
|
||||
const ranges: { from: number; to: number }[] = []
|
||||
|
||||
if (annotation.command) {
|
||||
ranges.push(...commandRanges(state, line, annotation.command))
|
||||
}
|
||||
|
||||
// default to highlighting the whole line
|
||||
if (ranges.length === 0) {
|
||||
ranges.push(line)
|
||||
}
|
||||
|
||||
return ranges
|
||||
}
|
||||
|
||||
const convertAnnotationToDiagnostic = (
|
||||
state: EditorState,
|
||||
annotation: Annotation
|
||||
): CompileLogDiagnostic[] => {
|
||||
if (annotation.row < 0) {
|
||||
throw new Error(`Invalid annotation row ${annotation.row}`)
|
||||
}
|
||||
|
||||
const line = doc.line(annotation.row + 1)
|
||||
// NOTE: highlight whole line by default, as synctex doesn't output column number
|
||||
const line = state.doc.line(annotation.row + 1)
|
||||
|
||||
return {
|
||||
from: line.from,
|
||||
to: line.to, // NOTE: highlight whole line as synctex doesn't output column number
|
||||
const highlightRanges = chooseHighlightRanges(state, line, annotation)
|
||||
|
||||
return highlightRanges.map(location => ({
|
||||
from: location.from,
|
||||
to: location.to,
|
||||
severity: annotation.type,
|
||||
message: annotation.text,
|
||||
ruleId: annotation.ruleId,
|
||||
|
@ -192,7 +238,7 @@ const convertAnnotationToDiagnostic = (
|
|||
entryIndex: annotation.entryIndex,
|
||||
source: annotation.source,
|
||||
firstOnLine: annotation.firstOnLine,
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
export const renderMessage = (diagnostic: RenderedDiagnostic) => {
|
||||
|
|
|
@ -497,7 +497,7 @@ function useCodeMirrorScope(view: EditorView) {
|
|||
// dispatch in a timeout, so the dispatch isn't in the same cycle as the edit which caused it
|
||||
window.setTimeout(() => {
|
||||
view.dispatch(
|
||||
setAnnotations(view.state.doc, annotations || []),
|
||||
setAnnotations(view.state, annotations || []),
|
||||
// reconfigure the compile log lint source, so it runs once with the new data
|
||||
showCompileLogDiagnostics(enableCompileLogLinterRef.current)
|
||||
)
|
||||
|
|
|
@ -51,6 +51,10 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
if (entry.contentDetails && ruleDetails.highlightCommand) {
|
||||
entry.command = ruleDetails.highlightCommand(entry.contentDetails)
|
||||
}
|
||||
|
||||
// suppress any entries that are known to cascade from previous error types
|
||||
if (ruleDetails.cascadesFrom) {
|
||||
for (const type of ruleDetails.cascadesFrom) {
|
||||
|
|
|
@ -16,6 +16,7 @@ interface Rule {
|
|||
details?: [string]
|
||||
) => string | [string, JSX.Element]
|
||||
package?: string
|
||||
highlightCommand?: (contentDetails: string[]) => string | undefined
|
||||
}
|
||||
|
||||
const rules: Rule[] = [
|
||||
|
@ -78,6 +79,9 @@ const rules: Rule[] = [
|
|||
}
|
||||
return currentTitle
|
||||
},
|
||||
highlightCommand(contentDetails) {
|
||||
return contentDetails[0]
|
||||
},
|
||||
},
|
||||
{
|
||||
ruleId: 'hint_undefined_environment',
|
||||
|
|
|
@ -7,4 +7,5 @@ export type Annotation = {
|
|||
id: string
|
||||
entryIndex: number
|
||||
firstOnLine: boolean
|
||||
command?: string
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue