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

Commit 976a71f

Browse files
authored
feat: add code view-specific tokenization settings (#401)
1 parent 6adb829 commit 976a71f

File tree

2 files changed

+95
-34
lines changed

2 files changed

+95
-34
lines changed

src/hoverifier.ts

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
getCodeElementsInRange,
4545
getTokenAtPositionOrRange,
4646
HoveredToken,
47+
shouldTokenize,
4748
} from './token_position'
4849
import { HoverAttachment, HoverOverlayProps, isPosition, LineOrPositionOrRange, DocumentHighlight } from './types'
4950
import { emitLoading, MaybeLoadingResult, LOADING } from './loading'
@@ -209,6 +210,14 @@ export interface EventOptions<C extends object> {
209210
* but a higher z-index than the code view, such as a sticky file header.
210211
*/
211212
scrollBoundaries?: HTMLElement[]
213+
214+
/**
215+
* Whether the specific code view should be tokenized. If defined, this is used over
216+
* the `tokenize` value passed to `createHoverifier`.
217+
*
218+
* Useful if some code views on a code host are already tokenized while other code views are not.
219+
*/
220+
overrideTokenize?: boolean
212221
}
213222

214223
/**
@@ -549,14 +558,18 @@ export function createHoverifier<C extends object, D, A>({
549558
// It's important to do this before filtering otherwise navigating from
550559
// a position, to a line-only position, back to the first position would get ignored
551560
distinctUntilChanged((a, b) => isEqual(a, b)),
552-
map(({ position, codeView, dom, ...rest }) => {
561+
map(({ position, codeView, dom, overrideTokenize, ...rest }) => {
553562
let cell: HTMLElement | null
554563
let target: HTMLElement | undefined
555564
let part: DiffPart | undefined
556565
if (isPosition(position)) {
557566
cell = dom.getCodeElementFromLineNumber(codeView, position.line, position.part)
558567
if (cell) {
559-
target = findElementWithOffset(cell, { offsetStart: position.character }, tokenize)
568+
target = findElementWithOffset(
569+
cell,
570+
{ offsetStart: position.character },
571+
shouldTokenize({ tokenize, overrideTokenize })
572+
)
560573
if (target) {
561574
part = dom.getDiffCodePart && dom.getDiffCodePart(target)
562575
} else {
@@ -571,6 +584,7 @@ export function createHoverifier<C extends object, D, A>({
571584
position: { ...position, part },
572585
codeView,
573586
dom,
587+
overrideTokenize,
574588
}
575589
})
576590
)
@@ -590,14 +604,15 @@ export function createHoverifier<C extends object, D, A>({
590604
map(
591605
([
592606
{ hoverOverlayElement, relativeElement },
593-
{ target, position, codeView, dom, adjustPosition, resolveContext },
607+
{ target, position, codeView, dom, adjustPosition, resolveContext, overrideTokenize, ...rest },
594608
]) => ({
595609
hoverOverlayElement,
596610
relativeElement,
597611
target,
598612
position,
599613
codeView,
600614
dom,
615+
overrideTokenize,
601616
adjustPosition,
602617
resolveContext,
603618
})
@@ -621,13 +636,19 @@ export function createHoverifier<C extends object, D, A>({
621636
}))
622637
)
623638
}),
624-
map(({ target, position, codeView, dom, ...rest }) => ({
639+
map(({ target, position, codeView, dom, overrideTokenize, ...rest }) => ({
625640
// We should ensure we have the correct dom element to place the overlay above. It is possible
626641
// that tokens span multiple elements meaning that it's possible for the hover overlay to be
627642
// placed in the middle of a token.
628643
target:
629644
position && isPosition(position)
630-
? getTokenAtPositionOrRange(codeView, position, dom, position.part, tokenize)
645+
? getTokenAtPositionOrRange(
646+
codeView,
647+
position,
648+
dom,
649+
position.part,
650+
shouldTokenize({ tokenize, overrideTokenize })
651+
)
631652
: target,
632653
...rest,
633654
})),
@@ -739,6 +760,7 @@ export function createHoverifier<C extends object, D, A>({
739760
const hoverObservables: Observable<Observable<{
740761
eventType: SupportedMouseEvent | 'jump'
741762
dom: DOMFunctions
763+
overrideTokenize?: boolean
742764
target: HTMLElement
743765
adjustPosition?: PositionAdjuster<C>
744766
codeView: HTMLElement
@@ -805,21 +827,38 @@ export function createHoverifier<C extends object, D, A>({
805827
map(position => ({ position, hoverOrError, codeView, part, ...rest }))
806828
)
807829
}),
808-
switchMap(({ scrollBoundaries, hoverOrError, position, codeView, codeViewId, dom, part }) => {
809-
const highlightedRange = getHighlightedRange({ hoverOrError, position })
810-
const hoveredTokenElement = highlightedRange
811-
? getTokenAtPositionOrRange(codeView, highlightedRange, dom, part, tokenize)
812-
: undefined
813-
return resetOnBoundaryIntersection({
830+
switchMap(
831+
({
814832
scrollBoundaries,
815-
codeViewId,
816-
codeView,
817-
highlightedRange,
818833
hoverOrError,
819-
hoveredTokenElement,
820-
hoverOverlayPosition: undefined,
821-
})
822-
})
834+
position,
835+
codeView,
836+
codeViewId,
837+
dom,
838+
part,
839+
overrideTokenize,
840+
}) => {
841+
const highlightedRange = getHighlightedRange({ hoverOrError, position })
842+
const hoveredTokenElement = highlightedRange
843+
? getTokenAtPositionOrRange(
844+
codeView,
845+
highlightedRange,
846+
dom,
847+
part,
848+
shouldTokenize({ tokenize, overrideTokenize })
849+
)
850+
: undefined
851+
return resetOnBoundaryIntersection({
852+
scrollBoundaries,
853+
codeViewId,
854+
codeView,
855+
highlightedRange,
856+
hoverOrError,
857+
hoveredTokenElement,
858+
hoverOverlayPosition: undefined,
859+
})
860+
}
861+
)
823862
)
824863
.subscribe(({ codeView, highlightedRange, hoveredTokenElement, ...rest }) => {
825864
container.update({
@@ -846,6 +885,7 @@ export function createHoverifier<C extends object, D, A>({
846885
const documentHighlightObservables: Observable<Observable<{
847886
eventType: SupportedMouseEvent | 'jump'
848887
dom: DOMFunctions
888+
overrideTokenize?: boolean
849889
target: HTMLElement
850890
adjustPosition?: PositionAdjuster<C>
851891
codeView: HTMLElement
@@ -929,11 +969,17 @@ export function createHoverifier<C extends object, D, A>({
929969
),
930970
}
931971
),
932-
mergeMap(({ positions, codeView, dom, part }) =>
972+
mergeMap(({ positions, codeView, dom, part, overrideTokenize }) =>
933973
positions.pipe(
934974
map(highlightedRanges =>
935975
highlightedRanges.map(highlightedRange =>
936-
getTokenAtPositionOrRange(codeView, highlightedRange, dom, part, tokenize)
976+
getTokenAtPositionOrRange(
977+
codeView,
978+
highlightedRange,
979+
dom,
980+
part,
981+
shouldTokenize({ tokenize, overrideTokenize })
982+
)
937983
)
938984
),
939985
map(elements => ({ elements, codeView, dom, part }))
@@ -1053,22 +1099,24 @@ export function createHoverifier<C extends object, D, A>({
10531099

10541100
// LOCATION CHANGES
10551101
subscription.add(
1056-
allPositionJumps.subscribe(({ position, scrollElement, codeView, dom: { getCodeElementFromLineNumber } }) => {
1057-
container.update({
1058-
// Remember active position in state for blame and range expansion
1059-
selectedPosition: position,
1060-
})
1061-
const codeElements = getCodeElementsInRange({ codeView, position, getCodeElementFromLineNumber })
1062-
if (tokenize) {
1063-
for (const { element } of codeElements) {
1064-
convertNode(element)
1102+
allPositionJumps.subscribe(
1103+
({ position, scrollElement, codeView, dom: { getCodeElementFromLineNumber }, overrideTokenize }) => {
1104+
container.update({
1105+
// Remember active position in state for blame and range expansion
1106+
selectedPosition: position,
1107+
})
1108+
const codeElements = getCodeElementsInRange({ codeView, position, getCodeElementFromLineNumber })
1109+
if (shouldTokenize({ tokenize, overrideTokenize })) {
1110+
for (const { element } of codeElements) {
1111+
convertNode(element)
1112+
}
1113+
}
1114+
// Scroll into view
1115+
if (codeElements.length > 0) {
1116+
scrollIntoCenterIfNeeded(scrollElement, codeView, codeElements[0].element)
10651117
}
10661118
}
1067-
// Scroll into view
1068-
if (codeElements.length > 0) {
1069-
scrollIntoCenterIfNeeded(scrollElement, codeView, codeElements[0].element)
1070-
}
1071-
})
1119+
)
10721120
)
10731121
subscription.add(
10741122
resolvedPositions.subscribe(({ position }) => {

src/token_position.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ export function convertCodeElementIdempotent(element: HTMLElement): void {
6565
}
6666
}
6767

68+
/**
69+
* Helper function to determine whether the code view should be tokenized.
70+
*/
71+
export function shouldTokenize({
72+
tokenize,
73+
overrideTokenize,
74+
}: {
75+
tokenize: boolean
76+
overrideTokenize: boolean | undefined
77+
}): boolean {
78+
return typeof overrideTokenize === 'boolean' ? overrideTokenize : tokenize
79+
}
80+
6881
/**
6982
* convertNode modifies a DOM node so that we can identify precisely token a user has clicked or hovered over.
7083
* On a code view, source code is typically wrapped in a HTML table cell. It may look like this:

0 commit comments

Comments
 (0)