Skip to content
This repository was archived by the owner on Nov 25, 2021. It is now read-only.

Commit 4863e61

Browse files
committed
refactor: move dom options to hoverify()
1 parent d38b2c4 commit 4863e61

File tree

3 files changed

+72
-68
lines changed

3 files changed

+72
-68
lines changed

src/hoverifier.ts

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ interface HoverifierOptions {
6262

6363
hoverOverlayElements: Observable<HTMLElement | null>
6464

65-
dom: DOMFunctions
66-
6765
/**
6866
* Called for programmatic navigation (like `history.push()`)
6967
*/
@@ -102,28 +100,37 @@ export interface Hoverifier {
102100
unsubscribe(): void
103101
}
104102

105-
export interface HoverifyOptions {
103+
export interface PositionJump {
104+
/**
105+
* The position within the code view to jump to
106+
*/
107+
position: LineOrPositionOrRange
108+
/**
109+
* The code view
110+
*/
111+
codeView: HTMLElement
112+
/**
113+
* The element to scroll if the position is out of view
114+
*/
115+
scrollElement: HTMLElement
116+
}
117+
118+
/**
119+
* HoverifyOptions that need to be included internally with every event
120+
*/
121+
interface EventOptions {
122+
resolveContext: ContextResolver
123+
dom: DOMFunctions
124+
}
125+
126+
export interface HoverifyOptions extends EventOptions {
106127
positionEvents: Observable<PositionEvent>
107128

108129
/**
109130
* Emit on this Observable to trigger the overlay on a position in this code view.
110131
* This Observable is intended to be used to trigger a Hover after a URL change with a position.
111132
*/
112-
positionJumps: Observable<{
113-
/**
114-
* The position within the code view to jump to
115-
*/
116-
position: LineOrPositionOrRange
117-
/**
118-
* The code view
119-
*/
120-
codeView: HTMLElement
121-
/**
122-
* The element to scroll if the position is out of view
123-
*/
124-
scrollElement: HTMLElement
125-
}>
126-
resolveContext: ContextResolver
133+
positionJumps: Observable<PositionJump>
127134
}
128135

129136
/**
@@ -217,7 +224,6 @@ export const createHoverifier = ({
217224
fetchHover,
218225
fetchJumpURL,
219226
logTelemetryEvent,
220-
dom,
221227
}: HoverifierOptions): Hoverifier => {
222228
// Internal state that is not exposed to the caller
223229
// Shared between all hoverified code views
@@ -232,9 +238,7 @@ export const createHoverifier = ({
232238
selectedPosition: undefined,
233239
})
234240

235-
interface MouseEventTrigger extends PositionEvent {
236-
resolveContext: ContextResolver
237-
}
241+
interface MouseEventTrigger extends PositionEvent, EventOptions {}
238242

239243
// These Subjects aggregate all events from all hoverified code views
240244
const allPositionsFromEvents = new Subject<MouseEventTrigger>()
@@ -246,12 +250,7 @@ export const createHoverifier = ({
246250
const allCodeMouseOvers = allPositionsFromEvents.pipe(filter(isEventType('mouseover')))
247251
const allCodeClicks = allPositionsFromEvents.pipe(filter(isEventType('click')))
248252

249-
const allPositionJumps = new Subject<{
250-
position: LineOrPositionOrRange
251-
codeView: HTMLElement
252-
scrollElement: HTMLElement
253-
resolveContext: ContextResolver
254-
}>()
253+
const allPositionJumps = new Subject<PositionJump & EventOptions>()
255254

256255
const subscription = new Subscription()
257256

@@ -314,7 +313,7 @@ export const createHoverifier = ({
314313
distinctUntilChanged((a, b) => isEqual(a, b)),
315314
// Ignore undefined or partial positions (e.g. line only)
316315
filter((jump): jump is typeof jump & { position: Position } => Position.is(jump.position)),
317-
map(({ position, codeView, ...rest }) => {
316+
map(({ position, codeView, dom, ...rest }) => {
318317
const cell = dom.getCodeElementFromLineNumber(codeView, position.line)
319318
if (!cell) {
320319
return undefined
@@ -325,7 +324,7 @@ export const createHoverifier = ({
325324
return undefined
326325
}
327326
const part = dom.getDiffCodePart && dom.getDiffCodePart(target)
328-
return { ...rest, eventType: 'jump' as 'jump', target, position: { ...position, part }, codeView }
327+
return { ...rest, eventType: 'jump' as 'jump', target, position: { ...position, part }, codeView, dom }
329328
}),
330329
filter(isDefined)
331330
)
@@ -364,9 +363,9 @@ export const createHoverifier = ({
364363
* This is a higher-order Observable (Observable that emits Observables).
365364
*/
366365
const hoverObservables = resolvedPositions.pipe(
367-
map(({ position, codeView }) => {
366+
map(({ position, ...rest }) => {
368367
if (!position) {
369-
return of({ codeView, hoverOrError: undefined })
368+
return of({ ...rest, hoverOrError: undefined })
370369
}
371370
// Fetch the hover for that position
372371
const hoverFetch = fetchHover(position).pipe(
@@ -388,33 +387,35 @@ export const createHoverifier = ({
388387
takeUntil(hoverFetch)
389388
),
390389
hoverFetch
391-
).pipe(map(hoverOrError => ({ hoverOrError, codeView })))
390+
).pipe(map(hoverOrError => ({ ...rest, hoverOrError })))
392391
}),
393392
share()
394393
)
395394
// Highlight the hover range returned by the language server
396395
subscription.add(
397-
hoverObservables.pipe(switchMap(hoverObservable => hoverObservable)).subscribe(({ hoverOrError, codeView }) => {
398-
container.update({
399-
hoverOrError,
400-
// Reset the hover position, it's gonna be repositioned after the hover was rendered
401-
hoverOverlayPosition: undefined,
396+
hoverObservables
397+
.pipe(switchMap(hoverObservable => hoverObservable))
398+
.subscribe(({ hoverOrError, codeView, dom }) => {
399+
container.update({
400+
hoverOrError,
401+
// Reset the hover position, it's gonna be repositioned after the hover was rendered
402+
hoverOverlayPosition: undefined,
403+
})
404+
const currentHighlighted = codeView!.querySelector('.selection-highlight')
405+
if (currentHighlighted) {
406+
currentHighlighted.classList.remove('selection-highlight')
407+
}
408+
if (!HoverMerged.is(hoverOrError) || !hoverOrError.range) {
409+
return
410+
}
411+
// LSP is 0-indexed, the code in the webapp currently is 1-indexed
412+
const { line, character } = hoverOrError.range.start
413+
const token = getTokenAtPosition(codeView, { line: line + 1, character: character + 1 }, dom)
414+
if (!token) {
415+
return
416+
}
417+
token.classList.add('selection-highlight')
402418
})
403-
const currentHighlighted = codeView!.querySelector('.selection-highlight')
404-
if (currentHighlighted) {
405-
currentHighlighted.classList.remove('selection-highlight')
406-
}
407-
if (!HoverMerged.is(hoverOrError) || !hoverOrError.range) {
408-
return
409-
}
410-
// LSP is 0-indexed, the code in the webapp currently is 1-indexed
411-
const { line, character } = hoverOrError.range.start
412-
const token = getTokenAtPosition(codeView!, { line: line + 1, character: character + 1 }, dom)
413-
if (!token) {
414-
return
415-
}
416-
token.classList.add('selection-highlight')
417-
})
418419
)
419420
// Telemetry for hovers
420421
subscription.add(
@@ -535,12 +536,12 @@ export const createHoverifier = ({
535536

536537
// LOCATION CHANGES
537538
subscription.add(
538-
allPositionJumps.subscribe(({ position, scrollElement, codeView }) => {
539+
allPositionJumps.subscribe(({ position, scrollElement, codeView, dom: { getCodeElementFromLineNumber } }) => {
539540
container.update({
540541
// Remember active position in state for blame and range expansion
541542
selectedPosition: position,
542543
})
543-
const rows = getCodeElementsInRange(codeView, { position, ...dom })
544+
const rows = getCodeElementsInRange({ codeView, position, getCodeElementFromLineNumber })
544545
for (const { element } of rows) {
545546
convertNode(element)
546547
}
@@ -573,15 +574,14 @@ export const createHoverifier = ({
573574
map(internalToExternalState),
574575
distinctUntilChanged((a, b) => isEqual(a, b))
575576
),
576-
hoverify({ positionEvents, positionJumps, resolveContext }: HoverifyOptions): Subscription {
577+
hoverify({ positionEvents, positionJumps, ...eventOptions }: HoverifyOptions): Subscription {
577578
const subscription = new Subscription()
578-
const eventWithContextResolver = map((event: PositionEvent) => ({
579-
...event,
580-
resolveContext,
581-
}))
579+
const eventWithOptions = map((event: PositionEvent) => ({ ...event, ...eventOptions }))
582580
// Broadcast all events from this code view
583-
subscription.add(positionEvents.pipe(eventWithContextResolver).subscribe(allPositionsFromEvents))
584-
subscription.add(positionJumps.pipe(map(jump => ({ ...jump, resolveContext }))).subscribe(allPositionJumps))
581+
subscription.add(positionEvents.pipe(eventWithOptions).subscribe(allPositionsFromEvents))
582+
subscription.add(
583+
positionJumps.pipe(map(jump => ({ ...jump, ...eventOptions }))).subscribe(allPositionJumps)
584+
)
585585
return subscription
586586
},
587587
unsubscribe(): void {

src/positions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { fromEvent, merge, Observable } from 'rxjs'
22
import { filter, map, switchMap, tap } from 'rxjs/operators'
33
import { Position } from 'vscode-languageserver-types'
44
import { convertCodeElementIdempotent, DOMFunctions, HoveredToken, locateTarget } from './token_position'
5+
56
export type SupportedMouseEvent = 'click' | 'mousemove' | 'mouseover'
67

78
export interface PositionEvent {
@@ -24,6 +25,7 @@ export interface PositionEvent {
2425
codeView: HTMLElement
2526
}
2627

28+
export { DOMFunctions }
2729
export const findPositionsFromEvents = (options: DOMFunctions) => (
2830
elements: Observable<HTMLElement>
2931
): Observable<PositionEvent> =>

src/token_position.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,16 @@ export function locateTarget(
281281
return { line }
282282
}
283283

284-
interface GetCodeElementsInRangeOptions extends DOMFunctions {
284+
interface GetCodeElementsInRangeOptions extends Pick<DOMFunctions, 'getCodeElementFromLineNumber'> {
285+
codeView: HTMLElement
285286
position?: LineOrPositionOrRange
286287
}
287288

288-
export const getCodeElementsInRange = (
289-
codeElement: HTMLElement,
290-
{ position, getCodeElementFromLineNumber }: GetCodeElementsInRangeOptions
291-
): {
289+
export const getCodeElementsInRange = ({
290+
codeView,
291+
position,
292+
getCodeElementFromLineNumber,
293+
}: GetCodeElementsInRangeOptions): {
292294
/** 1-indexed line number */
293295
line: number
294296
/** The element containing the code */
@@ -300,7 +302,7 @@ export const getCodeElementsInRange = (
300302

301303
const elements: { line: number; element: HTMLElement }[] = []
302304
for (let line = position.line; line <= (position.endLine || position.line); line++) {
303-
const element = getCodeElementFromLineNumber(codeElement, position.line)
305+
const element = getCodeElementFromLineNumber(codeView, position.line)
304306
if (!element) {
305307
break
306308
}

0 commit comments

Comments
 (0)