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

Commit e4ab20c

Browse files
committed
feat: accept Subscribable interface instead of Observable class
This allows passing Observables from different versions of rxjs, or from an npm linked version.
1 parent a6c7133 commit e4ab20c

File tree

2 files changed

+70
-42
lines changed

2 files changed

+70
-42
lines changed

src/hoverifier.ts

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import { isEqual, noop } from 'lodash'
2-
import { combineLatest, concat, EMPTY, fromEvent, merge, Observable, of, Subject, Subscription, zip } from 'rxjs'
2+
import {
3+
combineLatest,
4+
concat,
5+
EMPTY,
6+
from,
7+
fromEvent,
8+
merge,
9+
Observable,
10+
of,
11+
Subject,
12+
Subscribable,
13+
SubscribableOrPromise,
14+
Subscription,
15+
zip,
16+
} from 'rxjs'
317
import {
418
catchError,
519
debounceTime,
@@ -38,7 +52,7 @@ export interface HoverifierOptions {
3852
/**
3953
* Emit the HoverOverlay element on this after it was rerendered when its content changed and it needs to be repositioned.
4054
*/
41-
hoverOverlayRerenders: Observable<{
55+
hoverOverlayRerenders: Subscribable<{
4256
/**
4357
* The HoverOverlay element
4458
*/
@@ -53,14 +67,14 @@ export interface HoverifierOptions {
5367
/**
5468
* Emit on this Observable when the Go-To-Definition button in the HoverOverlay was clicked
5569
*/
56-
goToDefinitionClicks: Observable<MouseEvent>
70+
goToDefinitionClicks: Subscribable<MouseEvent>
5771

5872
/**
5973
* Emit on this Observable when the close button in the HoverOverlay was clicked
6074
*/
61-
closeButtonClicks: Observable<MouseEvent>
75+
closeButtonClicks: Subscribable<MouseEvent>
6276

63-
hoverOverlayElements: Observable<HTMLElement | null>
77+
hoverOverlayElements: Subscribable<HTMLElement | null>
6478

6579
/**
6680
* Called for programmatic navigation (like `history.push()`)
@@ -138,7 +152,7 @@ export interface AdjustPositionProps {
138152
* Function to adjust positions coming into and out of hoverifier. It can be used to correct the position used in HoverFetcher and
139153
* JumpURLFetcher requests and the position of th etoken to highlight in the code view. This is useful for code hosts that convert whitespace.
140154
*/
141-
export type PositionAdjuster = (props: AdjustPositionProps) => Observable<Position>
155+
export type PositionAdjuster = (props: AdjustPositionProps) => SubscribableOrPromise<Position>
142156

143157
/**
144158
* HoverifyOptions that need to be included internally with every event
@@ -150,13 +164,13 @@ export interface EventOptions {
150164
}
151165

152166
export interface HoverifyOptions extends EventOptions {
153-
positionEvents: Observable<PositionEvent>
167+
positionEvents: Subscribable<PositionEvent>
154168

155169
/**
156170
* Emit on this Observable to trigger the overlay on a position in this code view.
157171
* This Observable is intended to be used to trigger a Hover after a URL change with a position.
158172
*/
159-
positionJumps?: Observable<PositionJump>
173+
positionJumps?: Subscribable<PositionJump>
160174
}
161175

162176
/**
@@ -236,8 +250,8 @@ export const LOADER_DELAY = 300
236250
/** The time in ms after the mouse has stopped moving in which to show the tooltip */
237251
export const TOOLTIP_DISPLAY_DELAY = 100
238252

239-
export type HoverFetcher = (position: HoveredToken & HoveredTokenContext) => Observable<HoverMerged | null>
240-
export type JumpURLFetcher = (position: HoveredToken & HoveredTokenContext) => Observable<string | null>
253+
export type HoverFetcher = (position: HoveredToken & HoveredTokenContext) => SubscribableOrPromise<HoverMerged | null>
254+
export type JumpURLFetcher = (position: HoveredToken & HoveredTokenContext) => SubscribableOrPromise<string | null>
241255

242256
/**
243257
* Function responsible for resolving the position of a hovered token
@@ -325,11 +339,13 @@ export const createHoverifier = ({
325339
switchMap(
326340
({ adjustPosition, codeView, resolveContext, position, ...rest }) =>
327341
adjustPosition && position
328-
? adjustPosition({
329-
codeView,
330-
position: { ...position, ...resolveContext(position) },
331-
direction: AdjustmentDirection.CodeViewToActual,
332-
}).pipe(
342+
? from(
343+
adjustPosition({
344+
codeView,
345+
position: { ...position, ...resolveContext(position) },
346+
direction: AdjustmentDirection.CodeViewToActual,
347+
})
348+
).pipe(
333349
map(({ line, character }) => ({
334350
codeView,
335351
resolveContext,
@@ -352,11 +368,13 @@ export const createHoverifier = ({
352368
switchMap(
353369
({ adjustPosition, codeView, resolveContext, position, ...rest }) =>
354370
adjustPosition && position
355-
? adjustPosition({
356-
codeView,
357-
position: { ...position, ...resolveContext(position) },
358-
direction: AdjustmentDirection.CodeViewToActual,
359-
}).pipe(
371+
? from(
372+
adjustPosition({
373+
codeView,
374+
position: { ...position, ...resolveContext(position) },
375+
direction: AdjustmentDirection.CodeViewToActual,
376+
})
377+
).pipe(
360378
map(({ line, character }) => ({
361379
codeView,
362380
resolveContext,
@@ -403,7 +421,7 @@ export const createHoverifier = ({
403421
// latest hover target by the time componentDidUpdate is triggered from the setState() in the second chain
404422
subscription.add(
405423
// Take every rerender
406-
hoverOverlayRerenders
424+
from(hoverOverlayRerenders)
407425
.pipe(
408426
// with the latest target that came from either a mouseover, click or location change (whatever was the most recent)
409427
withLatestFrom(merge(codeMouseOverTargets, codeClickTargets, jumpTargets)),
@@ -427,11 +445,13 @@ export const createHoverifier = ({
427445
return of({ position, codeView, ...rest })
428446
}
429447

430-
return adjustPosition({
431-
position: { ...position, ...resolveContext(position) },
432-
codeView,
433-
direction: AdjustmentDirection.ActualToCodeView,
434-
}).pipe(
448+
return from(
449+
adjustPosition({
450+
position: { ...position, ...resolveContext(position) },
451+
codeView,
452+
direction: AdjustmentDirection.ActualToCodeView,
453+
})
454+
).pipe(
435455
map(({ line, character }) => ({
436456
position: { ...position, line, character },
437457
codeView,
@@ -489,7 +509,7 @@ export const createHoverifier = ({
489509
return of({ hoverOrError: null, position: undefined, part: undefined, ...rest })
490510
}
491511
// Fetch the hover for that position
492-
const hoverFetch = fetchHover(position).pipe(
512+
const hoverFetch = from(fetchHover(position)).pipe(
493513
// Some language servers don't conform to the LSP specification
494514
// (e.g. Python LS sometimes returns an empty object). For the
495515
// convenience of consumers of codeintellify, we'll handle this
@@ -549,14 +569,16 @@ export const createHoverifier = ({
549569
pos = { line: line + 1, character: character + 1, ...pos }
550570

551571
const adjustingPosition = adjustPosition
552-
? adjustPosition({
553-
codeView: rest.codeView,
554-
direction: AdjustmentDirection.ActualToCodeView,
555-
position: {
556-
...pos,
557-
part: rest.part,
558-
},
559-
})
572+
? from(
573+
adjustPosition({
574+
codeView: rest.codeView,
575+
direction: AdjustmentDirection.ActualToCodeView,
576+
position: {
577+
...pos,
578+
part: rest.part,
579+
},
580+
})
581+
)
560582
: of(pos)
561583

562584
return adjustingPosition.pipe(map(position => ({ position, hoverOrError, ...rest })))
@@ -608,7 +630,7 @@ export const createHoverifier = ({
608630
}
609631
return concat(
610632
[LOADING],
611-
fetchJumpURL(position).pipe(
633+
from(fetchJumpURL(position)).pipe(
612634
map(url => (url !== null ? { jumpURL: url } : null)),
613635
catchError(error => [asError(error)])
614636
)
@@ -749,9 +771,15 @@ export const createHoverifier = ({
749771
const subscription = new Subscription()
750772
const eventWithOptions = map((event: PositionEvent) => ({ ...event, ...eventOptions }))
751773
// Broadcast all events from this code view
752-
subscription.add(positionEvents.pipe(eventWithOptions).subscribe(allPositionsFromEvents))
753774
subscription.add(
754-
positionJumps.pipe(map(jump => ({ ...jump, ...eventOptions }))).subscribe(allPositionJumps)
775+
from(positionEvents)
776+
.pipe(eventWithOptions)
777+
.subscribe(allPositionsFromEvents)
778+
)
779+
subscription.add(
780+
from(positionJumps)
781+
.pipe(map(jump => ({ ...jump, ...eventOptions })))
782+
.subscribe(allPositionJumps)
755783
)
756784
return subscription
757785
},

src/positions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fromEvent, merge, Observable } from 'rxjs'
1+
import { from, fromEvent, merge, Observable, Subscribable } from 'rxjs'
22
import { filter, map, switchMap, tap } from 'rxjs/operators'
33
import { Position } from 'vscode-languageserver-types'
44
import { convertCodeElementIdempotent, DiffPart, DOMFunctions, HoveredToken, locateTarget } from './token_position'
@@ -27,10 +27,10 @@ export interface PositionEvent {
2727

2828
export { DOMFunctions, DiffPart }
2929
export const findPositionsFromEvents = (options: DOMFunctions) => (
30-
elements: Observable<HTMLElement>
30+
elements: Subscribable<HTMLElement>
3131
): Observable<PositionEvent> =>
3232
merge(
33-
elements.pipe(
33+
from(elements).pipe(
3434
switchMap(element => fromEvent<MouseEvent>(element, 'mouseover')),
3535
map(event => ({ event, eventType: 'mouseover' as 'mouseover' })),
3636
filter(({ event }) => event.currentTarget !== null),
@@ -50,7 +50,7 @@ export const findPositionsFromEvents = (options: DOMFunctions) => (
5050
}
5151
})
5252
),
53-
elements.pipe(
53+
from(elements).pipe(
5454
switchMap(element => fromEvent<MouseEvent>(element, 'click')),
5555
map(event => ({ event, eventType: 'click' as 'click' })),
5656
// ignore click events caused by the user selecting text.

0 commit comments

Comments
 (0)