Merge pull request #12884 from overleaf/td-history-diff-line-highlights

History migration: Add line and gutter highlights for changes in diff viewer

GitOrigin-RevId: 11d637647d147210f63e5111305adfe1d285ba3e
This commit is contained in:
Tim Down 2023-05-17 11:53:13 +01:00 committed by Copybot
parent c870bd5f53
commit 6b78c3025a
3 changed files with 101 additions and 6 deletions

View file

@ -32,7 +32,7 @@ function calculateHighlightLocations(view: EditorView): HighlightLocations {
let previous
const highlights =
view.state.field(highlightDecorationsField).highlights || []
view.state.field(highlightDecorationsField)?.highlights || []
if (highlights.length === 0) {
return { before: 0, after: 0 }

View file

@ -11,6 +11,9 @@ import {
DecorationSet,
EditorView,
showTooltip,
gutter,
gutterLineClass,
GutterMarker,
Tooltip,
ViewPlugin,
WidgetType,
@ -97,6 +100,20 @@ const theme = EditorView.baseTheme({
'.ol-cm-empty-line-addition-marker': {
padding: 'var(--half-leading) 2px',
},
'.ol-cm-changed-line': {
backgroundColor: 'rgba(0, 0, 0, 0.03)',
},
'.ol-cm-change-gutter': {
width: '3px',
paddingLeft: '1px',
},
'.ol-cm-changed-line-gutter': {
backgroundColor: 'hsl(var(--hue), 70%, 40%)',
height: '100%',
},
'.ol-cm-highlighted-line-gutter': {
backgroundColor: 'rgba(0, 0, 0, 0.03)',
},
})
function createHighlightTooltip(pos: number, highlight: Highlight) {
@ -272,10 +289,61 @@ function createEmptyLineHighlightMarkers(lineStatuses: LineStatuses) {
return RangeSet.of(markers)
}
class ChangeGutterMarker extends GutterMarker {
constructor(readonly hue: number) {
super()
}
toDOM(view: EditorView) {
const el = document.createElement('div')
el.className = 'ol-cm-changed-line-gutter'
el.style.setProperty('--hue', this.hue.toString())
return el
}
}
function createGutterMarkers(lineStatuses: LineStatuses) {
const gutterMarkers: Range<GutterMarker>[] = []
for (const lineStatus of lineStatuses.values()) {
gutterMarkers.push(
new ChangeGutterMarker(lineStatus.highlights[0].hue).range(
lineStatus.line.from
)
)
}
return RangeSet.of(gutterMarkers)
}
const lineHighlight = Decoration.line({ class: 'ol-cm-changed-line' })
function createLineHighlights(lineStatuses: LineStatuses) {
const lineHighlights: Range<Decoration>[] = []
for (const lineStatus of lineStatuses.values()) {
lineHighlights.push(lineHighlight.range(lineStatus.line.from))
}
return RangeSet.of(lineHighlights)
}
const changeLineGutterMarker = new (class extends GutterMarker {
elementClass = 'ol-cm-highlighted-line-gutter'
})()
function createGutterHighlights(lineStatuses: LineStatuses) {
const gutterMarkers: Range<GutterMarker>[] = []
for (const lineStatus of lineStatuses.values()) {
gutterMarkers.push(changeLineGutterMarker.range(lineStatus.line.from))
}
return RangeSet.of(gutterMarkers, true)
}
type HighlightDecorations = {
highlights: Highlight[]
highlightMarkers: DecorationSet
emptyLineHighlightMarkers: DecorationSet
lineHighlights: DecorationSet
gutterMarkers: RangeSet<GutterMarker>
gutterHighlights: RangeSet<GutterMarker>
}
export const highlightDecorationsField =
@ -285,9 +353,12 @@ export const highlightDecorationsField =
highlights: [],
highlightMarkers: Decoration.none,
emptyLineHighlightMarkers: Decoration.none,
lineHighlights: Decoration.none,
gutterMarkers: RangeSet.empty,
gutterHighlights: RangeSet.empty,
}
},
update(highlightMarkers, tr) {
update(highlightDecorations, tr) {
for (const effect of tr.effects) {
if (effect.is(setHighlightsEffect)) {
const highlights = effect.value
@ -295,14 +366,20 @@ export const highlightDecorationsField =
const highlightMarkers = createMarkers(highlights)
const emptyLineHighlightMarkers =
createEmptyLineHighlightMarkers(lineStatuses)
const lineHighlights = createLineHighlights(lineStatuses)
const gutterMarkers = createGutterMarkers(lineStatuses)
const gutterHighlights = createGutterHighlights(lineStatuses)
return {
highlights,
highlightMarkers,
emptyLineHighlightMarkers,
lineHighlights,
gutterMarkers,
gutterHighlights,
}
}
}
return highlightMarkers
return highlightDecorations
},
provide: field => [
EditorView.decorations.from(field, value => value.highlightMarkers),
@ -310,11 +387,23 @@ export const highlightDecorationsField =
field,
value => value.emptyLineHighlightMarkers
),
EditorView.decorations.from(field, value => value.lineHighlights),
theme,
highlightTooltipPlugin,
],
})
const changeGutter = gutter({
class: 'ol-cm-change-gutter',
markers: view => view.state.field(highlightDecorationsField).gutterMarkers,
renderEmptyElements: false,
})
const gutterHighlighter = gutterLineClass.from(
highlightDecorationsField,
value => value.gutterHighlights
)
export function highlights() {
return highlightDecorationsField
return [highlightDecorationsField, changeGutter, gutterHighlighter]
}

View file

@ -13,8 +13,8 @@ const highlights: Highlight[] = [
{
type: 'deletion',
range: { from: 15, to: 25 },
hue: 200,
label: 'Deleted by Wombat on Monday',
hue: 62,
label: 'Deleted by Duck on Monday',
},
{
type: 'addition',
@ -22,6 +22,12 @@ const highlights: Highlight[] = [
hue: 200,
label: 'Added by Wombat on Friday',
},
{
type: 'deletion',
range: { from: 564, to: 565 },
hue: 200,
label: 'Deleted by Wombat on Friday',
},
{
type: 'addition',
range: { from: 1770, to: 1780 },