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

Commit 0151c73

Browse files
committed
feat: remove hover rendering, only keep hover attachment
Removes the contents from hovers and only uses the hover object to position the tooltip, not to render any content.
1 parent 85c8612 commit 0151c73

File tree

10 files changed

+91
-361
lines changed

10 files changed

+91
-361
lines changed

package-lock.json

Lines changed: 41 additions & 143 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,9 @@
3131
"dependencies": {
3232
"@sourcegraph/event-positions": "^1.0.0",
3333
"@sourcegraph/react-loading-spinner": "0.0.7",
34-
"highlight.js": "^9.12.0",
3534
"lodash": "^4.17.10",
36-
"marked": "^0.4.0 || ^0.5.0",
3735
"mdi-react": "^5.1.0",
3836
"rxjs": "^6.3.3",
39-
"sanitize-html": "^1.18.2",
4037
"ts-key-enum": "^2.0.0",
4138
"vscode-languageserver-types": "^3.8.2"
4239
},
@@ -51,15 +48,12 @@
5148
"@sourcegraph/tslint-config": "^12.0.0",
5249
"@types/chai": "^4.1.4",
5350
"@types/fs-extra": "^5.0.3",
54-
"@types/highlight.js": "^9.12.3",
5551
"@types/karma": "^3.0.0",
5652
"@types/karma-webpack": "^2.0.4",
5753
"@types/lodash": "^4.14.110",
58-
"@types/marked": "^0.4.0",
5954
"@types/mocha": "^5.2.3",
6055
"@types/node": "^10.5.0",
6156
"@types/react": "^16.7.13",
62-
"@types/sanitize-html": "^1.14.0",
6357
"@types/sinon": "^5.0.1",
6458
"@types/webpack": "^4.4.4",
6559
"@types/webpack-env": "^1.13.6",

src/HoverOverlay.tsx

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { LoadingSpinner } from '@sourcegraph/react-loading-spinner'
2-
import { castArray, upperFirst } from 'lodash'
2+
import { upperFirst } from 'lodash'
33
import AlertCircleOutlineIcon from 'mdi-react/AlertCircleOutlineIcon'
44
import CloseIcon from 'mdi-react/CloseIcon'
55
import InformationOutlineIcon from 'mdi-react/InformationOutlineIcon'
66
import * as React from 'react'
7-
import { MarkedString, MarkupContent, MarkupKind } from 'vscode-languageserver-types'
8-
import { asError, ErrorLike, isErrorLike } from './errors'
9-
import { highlightCodeSafe, renderMarkdown, toNativeEvent } from './helpers'
7+
import { ErrorLike, isErrorLike } from './errors'
8+
import { toNativeEvent } from './helpers'
109
import { HoveredToken } from './token_position'
11-
import { HoverMerged, LOADING } from './types'
10+
import { HoverAttachment, LOADING } from './types'
1211

1312
/** The component used to render a link */
1413
export type LinkComponent = React.ComponentType<{ to: string } & React.HTMLAttributes<HTMLElement>>
@@ -34,7 +33,7 @@ const ButtonOrLink: React.StatelessComponent<
3433
*/
3534
export interface HoverOverlayProps<C = {}> {
3635
/** What to show as contents */
37-
hoverOrError?: typeof LOADING | HoverMerged | null | ErrorLike // TODO disallow null and undefined
36+
hoverOrError?: typeof LOADING | HoverAttachment | null | ErrorLike // TODO disallow null and undefined
3837

3938
/**
4039
* The URL to jump to on go to definition.
@@ -82,7 +81,6 @@ const transformMouseEvent = (handler: (event: MouseEvent) => void) => (event: Re
8281

8382
export const HoverOverlay: <C>(props: HoverOverlayProps<C>) => React.ReactElement<any> = ({
8483
definitionURLOrError,
85-
hoveredToken,
8684
hoverOrError,
8785
hoverRef,
8886
linkComponent,
@@ -133,46 +131,8 @@ export const HoverOverlay: <C>(props: HoverOverlayProps<C>) => React.ReactElemen
133131
</h4>
134132
{upperFirst(hoverOrError.message)}
135133
</div>
136-
) : (
137-
// tslint:disable-next-line deprecation We want to handle the deprecated MarkedString
138-
castArray<MarkedString | MarkupContent>(hoverOrError.contents)
139-
.map(value => (typeof value === 'string' ? { kind: MarkupKind.Markdown, value } : value))
140-
.map((content, i) => {
141-
if (MarkupContent.is(content)) {
142-
if (content.kind === MarkupKind.Markdown) {
143-
try {
144-
return (
145-
<div
146-
className="hover-overlay__content hover-overlay__row e2e-tooltip-content"
147-
key={i}
148-
dangerouslySetInnerHTML={{ __html: renderMarkdown(content.value) }}
149-
/>
150-
)
151-
} catch (err) {
152-
return (
153-
<div className="hover-overlay__row alert alert-danger">
154-
<strong>
155-
<AlertCircleOutlineIcon className="icon-inline" /> Error rendering
156-
hover content
157-
</strong>{' '}
158-
{upperFirst(asError(err).message)}
159-
</div>
160-
)
161-
}
162-
}
163-
return content.value
164-
}
165-
return (
166-
<code
167-
className="hover-overlay__content hover-overlay__row e2e-tooltip-content"
168-
key={i}
169-
dangerouslySetInnerHTML={{
170-
__html: highlightCodeSafe(content.value, content.language),
171-
}}
172-
/>
173-
)
174-
})
175-
)}
134+
) : null // hover content
135+
}
176136
</div>
177137
)}
178138

src/helpers.test.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/helpers.ts

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import { highlight, highlightAuto } from 'highlight.js/lib/highlight'
2-
import marked from 'marked'
31
import * as React from 'react'
4-
import sanitize from 'sanitize-html'
5-
import { MarkupContent } from 'vscode-languageserver-types'
6-
import { HoverOverlayProps, isJumpURL } from './HoverOverlay'
7-
import { HoverMerged } from './types'
82

93
/**
104
* Returns true if `val` is not `null` or `undefined`
@@ -21,19 +15,6 @@ export const propertyIsDefined = <T extends object, K extends keyof T>(key: K) =
2115
): val is K extends any ? ({ [k in Exclude<keyof T, K>]: T[k] } & { [k in K]: NonNullable<T[k]> }) : never =>
2216
isDefined(val[key])
2317

24-
const isEmptyHover = (hover: HoverMerged | null): boolean =>
25-
!hover ||
26-
!hover.contents ||
27-
(Array.isArray(hover.contents) && hover.contents.length === 0) ||
28-
(MarkupContent.is(hover.contents) && !hover.contents.value)
29-
30-
/**
31-
* Returns true if the HoverOverlay would have anything to show according to the given hover and definition states.
32-
*/
33-
export const overlayUIHasContent = (state: Pick<HoverOverlayProps, 'hoverOrError' | 'definitionURLOrError'>): boolean =>
34-
(!!state.hoverOrError && !(HoverMerged.is(state.hoverOrError) && isEmptyHover(state.hoverOrError))) ||
35-
isJumpURL(state.definitionURLOrError)
36-
3718
/**
3819
* Scrolls an element to the center if it is out of view.
3920
* Does nothing if the element is in view.
@@ -54,63 +35,6 @@ export const scrollIntoCenterIfNeeded = (container: HTMLElement, content: HTMLEl
5435
}
5536
}
5637

57-
/**
58-
* Escapes HTML by replacing characters like `<` with their HTML escape sequences like `&lt;`
59-
*/
60-
const escapeHTML = (html: string): string => {
61-
const span = document.createElement('span')
62-
span.textContent = html
63-
return span.innerHTML
64-
}
65-
66-
/**
67-
* Attempts to syntax-highlight the given code.
68-
* If the language is not given, it is auto-detected.
69-
* If an error occurs, the code is returned as plain text with escaped HTML entities
70-
*
71-
* @param code The code to highlight
72-
* @param language The language of the code, if known
73-
* @return Safe HTML
74-
*/
75-
export const highlightCodeSafe = (code: string, language?: string): string => {
76-
try {
77-
if (language === 'plaintext' || language === 'text') {
78-
return escapeHTML(code)
79-
}
80-
if (language) {
81-
return highlight(language, code, true).value
82-
}
83-
return highlightAuto(code).value
84-
} catch (err) {
85-
console.warn('Error syntax-highlighting hover markdown code block', err)
86-
return escapeHTML(code)
87-
}
88-
}
89-
90-
/**
91-
* Renders the given markdown to HTML, highlighting code and sanitizing dangerous HTML.
92-
* Can throw an exception on parse errors.
93-
*/
94-
export const renderMarkdown = (markdown: string): string => {
95-
const rendered = marked(markdown, {
96-
gfm: true,
97-
breaks: true,
98-
sanitize: false,
99-
highlight: (code, language) => highlightCodeSafe(code, language),
100-
})
101-
return sanitize(rendered, {
102-
// Allow highligh.js styles, e.g.
103-
// <span class="hljs-keyword">
104-
// <code class="language-javascript">
105-
allowedTags: [...sanitize.defaults.allowedTags, 'span', 'details', 'summary'],
106-
allowedAttributes: {
107-
span: ['class'],
108-
code: ['class'],
109-
a: ['href'],
110-
},
111-
})
112-
}
113-
11438
/**
11539
* Converts a synthetic React event to a persisted, native Event object.
11640
*

src/hoverifier.test.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { HoverOverlayProps } from './HoverOverlay'
1919
import { findPositionsFromEvents, SupportedMouseEvent } from './positions'
2020
import { CodeViewProps, DOM } from './testutils/dom'
21-
import { createHoverMerged, createStubHoverFetcher, createStubJumpURLFetcher } from './testutils/lsp'
21+
import { createHoverAttachment, createStubHoverFetcher, createStubJumpURLFetcher } from './testutils/lsp'
2222
import { dispatchMouseEventAtPositionImpure } from './testutils/mouse'
2323
import { LOADING } from './types'
2424

@@ -48,7 +48,6 @@ describe('Hoverifier', () => {
4848
fetchHover: createStubHoverFetcher({ range: hoverRange }, LOADER_DELAY + delayTime),
4949
fetchJumpURL: () => of(null),
5050
pushHistory: noop,
51-
getReferencesURL: () => null,
5251
})
5352

5453
const positionJumps = new Subject<PositionJump>()
@@ -113,7 +112,6 @@ describe('Hoverifier', () => {
113112
fetchHover: createStubHoverFetcher(hover, delayTime),
114113
fetchJumpURL: createStubJumpURLFetcher(defURL, delayTime),
115114
pushHistory: noop,
116-
getReferencesURL: () => null,
117115
})
118116

119117
const positionJumps = new Subject<PositionJump>()
@@ -360,7 +358,6 @@ describe('Hoverifier', () => {
360358
fetchHover: createStubHoverFetcher(hover, delayTime),
361359
fetchJumpURL: createStubJumpURLFetcher(defURL, delayTime),
362360
pushHistory: noop,
363-
getReferencesURL: () => null,
364361
})
365362

366363
const positionJumps = new Subject<PositionJump>()
@@ -406,7 +403,7 @@ describe('Hoverifier', () => {
406403
[key: string]: Pick<HoverOverlayProps, 'hoverOrError' | 'definitionURLOrError'>
407404
} = {
408405
a: { hoverOrError: LOADING, definitionURLOrError: undefined }, // def url is undefined when it is loading
409-
b: { hoverOrError: createHoverMerged(hover), definitionURLOrError: { jumpURL: defURL } },
406+
b: { hoverOrError: createHoverAttachment(hover), definitionURLOrError: { jumpURL: defURL } },
410407
}
411408

412409
// Click https://sourcegraph.sgdev.org/github.com/gorilla/mux@cb4698366aa625048f3b815af6a0dea8aef9280a/-/blob/mux.go#L24:6
@@ -438,7 +435,6 @@ describe('Hoverifier', () => {
438435
fetchHover: createStubHoverFetcher(hover),
439436
fetchJumpURL: createStubJumpURLFetcher(defURL),
440437
pushHistory: noop,
441-
getReferencesURL: () => null,
442438
})
443439

444440
const positionJumps = new Subject<PositionJump>()
@@ -503,7 +499,6 @@ describe('Hoverifier', () => {
503499
fetchHover: createStubHoverFetcher(hover),
504500
fetchJumpURL: createStubJumpURLFetcher(defURL),
505501
pushHistory: noop,
506-
getReferencesURL: () => null,
507502
})
508503

509504
const positionJumps = new Subject<PositionJump>()
@@ -588,7 +583,6 @@ describe('Hoverifier', () => {
588583
fetchHover,
589584
fetchJumpURL,
590585
pushHistory: noop,
591-
getReferencesURL: () => null,
592586
})
593587

594588
const positionJumps = new Subject<PositionJump>()

0 commit comments

Comments
 (0)