@@ -23,8 +23,10 @@ import { lspViaAPIXlang } from '../../shared/backend/lsp'
2323import { ButtonProps , CodeViewToolbar } from '../../shared/components/CodeViewToolbar'
2424import { eventLogger , sourcegraphUrl } from '../../shared/util/context'
2525import { githubCodeHost } from '../github/code_intelligence'
26+ import { gitlabCodeHost } from '../gitlab/code_intelligence'
2627import { phabricatorCodeHost } from '../phabricator/code_intelligence'
2728import { findCodeViews } from './code_views'
29+ import { initSearch , SearchFeature } from './search'
2830
2931/**
3032 * Defines a type of code view a given code host can have. It tells us how to
@@ -64,13 +66,24 @@ export interface CodeViewResolver {
6466 resolveCodeView : ( elem : HTMLElement ) => CodeViewWithOutSelector
6567}
6668
69+ interface OverlayPosition {
70+ top : number
71+ left : number
72+ }
73+
6774/** Information for adding code intelligence to code views on arbitrary code hosts. */
6875export interface CodeHost {
6976 /**
7077 * The name of the code host. This will be added as a className to the overlay mount.
7178 */
7279 name : string
7380
81+ /**
82+ * Checks to see if the current context the code is running in is within
83+ * the given code host.
84+ */
85+ check : ( ) => Promise < boolean > | boolean
86+
7487 /**
7588 * The list of types of code views to try to annotate.
7689 */
@@ -83,10 +96,16 @@ export interface CodeHost {
8396 codeViewResolver ?: CodeViewResolver
8497
8598 /**
86- * Checks to see if the current context the code is running in is within
87- * the given code host.
99+ * Adjust the position of the hover overlay. Useful for fixed headers or other
100+ * elements that throw off the position of the tooltip within the relative
101+ * element.
88102 */
89- check : ( ) => Promise < boolean > | boolean
103+ adjustOverlayPosition ?: ( position : OverlayPosition ) => OverlayPosition
104+
105+ /**
106+ * Implementation of the search feature for a code host.
107+ */
108+ search ?: SearchFeature
90109}
91110
92111export interface FileInfo {
@@ -150,11 +169,19 @@ function initCodeIntelligence(codeHost: CodeHost): { hoverifier: Hoverifier } {
150169 const hoverOverlayElements = new Subject < HTMLElement | null > ( )
151170 const nextOverlayElement = ( element : HTMLElement | null ) => hoverOverlayElements . next ( element )
152171
153- const overlayMount = document . createElement ( 'div' )
154- overlayMount . style . height = '0px'
155- overlayMount . classList . add ( 'hover-overlay-mount' )
156- overlayMount . classList . add ( `hover-overlay-mount__${ codeHost . name } ` )
157- document . body . appendChild ( overlayMount )
172+ const classNames = [ 'hover-overlay-mount' , `hover-overlay-mount__${ codeHost . name } ` ]
173+
174+ const createMount = ( ) => {
175+ const overlayMount = document . createElement ( 'div' )
176+ overlayMount . style . height = '0px'
177+ for ( const className of classNames ) {
178+ overlayMount . classList . add ( className )
179+ }
180+ document . body . appendChild ( overlayMount )
181+ return overlayMount
182+ }
183+
184+ const overlayMount = document . querySelector ( `.${ classNames . join ( '.' ) } ` ) || createMount ( )
158185
159186 const relativeElement = document . body
160187
@@ -201,9 +228,10 @@ function initCodeIntelligence(codeHost: CodeHost): { hoverifier: Hoverifier } {
201228 containerComponentUpdates . next ( )
202229 }
203230 public render ( ) : JSX . Element | null {
204- return this . state . hoverOverlayProps ? (
231+ const hoverOverlayProps = this . getHoverOverlayProps ( )
232+ return hoverOverlayProps ? (
205233 < HoverOverlay
206- { ...this . state . hoverOverlayProps }
234+ { ...hoverOverlayProps }
207235 linkComponent = { Link }
208236 logTelemetryEvent = { this . log }
209237 hoverRef = { nextOverlayElement }
@@ -213,6 +241,21 @@ function initCodeIntelligence(codeHost: CodeHost): { hoverifier: Hoverifier } {
213241 ) : null
214242 }
215243 private log = ( ) => eventLogger . logCodeIntelligenceEvent ( )
244+ private getHoverOverlayProps ( ) : HoverState [ 'hoverOverlayProps' ] {
245+ if ( ! this . state . hoverOverlayProps ) {
246+ return undefined
247+ }
248+
249+ let { overlayPosition, ...rest } = this . state . hoverOverlayProps
250+ if ( overlayPosition && codeHost . adjustOverlayPosition ) {
251+ overlayPosition = codeHost . adjustOverlayPosition ( overlayPosition )
252+ }
253+
254+ return {
255+ ...rest ,
256+ overlayPosition,
257+ }
258+ }
216259 }
217260
218261 render ( < HoverOverlayContainer /> , overlayMount )
@@ -230,6 +273,10 @@ export interface ResolvedCodeView extends CodeViewWithOutSelector {
230273}
231274
232275function handleCodeHost ( codeHost : CodeHost ) : Subscription {
276+ if ( codeHost . search ) {
277+ initSearch ( codeHost . search )
278+ }
279+
233280 const { hoverifier } = initCodeIntelligence ( codeHost )
234281
235282 const subscriptions = new Subscription ( )
@@ -247,7 +294,7 @@ function handleCodeHost(codeHost: CodeHost): Subscription {
247294 const resolveContext : ContextResolver = ( { part } ) => ( {
248295 repoPath : part === 'base' ? info . baseRepoPath || info . repoPath : info . repoPath ,
249296 commitID : part === 'base' ? info . baseCommitID ! : info . commitID ,
250- filePath : part === 'base' ? info . baseFilePath ! : info . filePath ,
297+ filePath : part === 'base' ? info . baseFilePath || info . filePath : info . filePath ,
251298 rev : part === 'base' ? info . baseRev || info . baseCommitID ! : info . rev || info . commitID ,
252299 } )
253300
@@ -308,7 +355,7 @@ async function injectCodeIntelligenceToCodeHosts(codeHosts: CodeHost[]): Promise
308355 * incomplete setup requests.
309356 */
310357export async function injectCodeIntelligence ( ) : Promise < Subscription > {
311- const codeHosts : CodeHost [ ] = [ githubCodeHost , phabricatorCodeHost ]
358+ const codeHosts : CodeHost [ ] = [ githubCodeHost , gitlabCodeHost , phabricatorCodeHost ]
312359
313360 return await injectCodeIntelligenceToCodeHosts ( codeHosts )
314361}
0 commit comments