Skip to content

Commit

Permalink
[Code] show multiple definition results in panel (#43249)
Browse files Browse the repository at this point in the history
* [Code] show multiple definition results in panel
  • Loading branch information
Yulong authored Aug 15, 2019
1 parent 4432b91 commit 676f4d2
Show file tree
Hide file tree
Showing 9 changed files with 402 additions and 164 deletions.
18 changes: 11 additions & 7 deletions x-pack/legacy/plugins/code/public/actions/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import { Range } from 'monaco-editor';
import { createAction } from 'redux-actions';
import { Hover, Position, TextDocumentPositionParams } from 'vscode-languageserver';

export interface ReferenceResults {
repos: GroupedRepoReferences[];
export interface PanelResults {
repos: GroupedRepoResults[];
title: string;
}

export interface GroupedRepoReferences {
export interface GroupedRepoResults {
repo: string;
files: GroupedFileReferences[];
files: GroupedFileResults[];
}

export interface GroupedFileReferences {
export interface GroupedFileResults {
uri: string;
file: string;
language: string;
Expand All @@ -30,8 +30,12 @@ export interface GroupedFileReferences {
}

export const findReferences = createAction<TextDocumentPositionParams>('FIND REFERENCES');
export const findReferencesSuccess = createAction<ReferenceResults>('FIND REFERENCES SUCCESS');
export const findReferencesSuccess = createAction<PanelResults>('FIND REFERENCES SUCCESS');
export const findReferencesFailed = createAction<Error>('FIND REFERENCES ERROR');
export const closeReferences = createAction<boolean>('CLOSE REFERENCES');
export const closePanel = createAction<boolean>('CLOSE PANEL');
export const hoverResult = createAction<Hover>('HOVER RESULT');
export const revealPosition = createAction<Position | undefined>('REVEAL POSITION');

export const findDefinitions = createAction<TextDocumentPositionParams>('FIND DEFINITIONS');
export const findDefinitionsSuccess = createAction<PanelResults>('FIND DEFINITIONS SUCCESS');
export const findDefinitionsFailed = createAction<Error>('FIND DEFINITIONS ERROR');
36 changes: 17 additions & 19 deletions x-pack/legacy/plugins/code/public/components/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { editor as editorInterfaces, IDisposable } from 'monaco-editor';
import React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { Hover, Position, TextDocumentPositionParams } from 'vscode-languageserver-protocol';
import { Hover, Position } from 'vscode-languageserver-protocol';
import { GitBlame } from '../../../common/git_blame';
import { closeReferences, FetchFileResponse, findReferences, hoverResult } from '../../actions';
import { closePanel, FetchFileResponse, hoverResult } from '../../actions';
import { MainRouteParams } from '../../common/types';
import { BlameWidget } from '../../monaco/blame/blame_widget';
import { monaco } from '../../monaco/monaco';
Expand All @@ -24,19 +24,18 @@ import { ReferencesPanel } from './references_panel';
import { encodeRevisionString } from '../../../common/uri_util';

export interface EditorActions {
closeReferences(changeUrl: boolean): void;
findReferences(params: TextDocumentPositionParams): void;
closePanel(changeUrl: boolean): void;
hoverResult(hover: Hover): void;
}

interface Props {
hidden?: boolean;
file?: FetchFileResponse;
revealPosition?: Position;
isReferencesOpen: boolean;
isReferencesLoading: boolean;
references: any[];
referencesTitle: string;
panelShowing: boolean;
isPanelLoading: boolean;
panelContents: any[];
panelTitle: string;
hover?: Hover;
refUrl?: string;
blames: GitBlame[];
Expand Down Expand Up @@ -237,12 +236,12 @@ export class EditorComponent extends React.Component<IProps> {

private renderReferences() {
return (
this.props.isReferencesOpen && (
this.props.panelShowing && (
<ReferencesPanel
onClose={() => this.props.closeReferences(true)}
references={this.props.references}
isLoading={this.props.isReferencesLoading}
title={this.props.referencesTitle}
onClose={() => this.props.closePanel(true)}
references={this.props.panelContents}
isLoading={this.props.isPanelLoading}
title={this.props.panelTitle}
refUrl={this.props.refUrl}
/>
)
Expand All @@ -252,19 +251,18 @@ export class EditorComponent extends React.Component<IProps> {

const mapStateToProps = (state: RootState) => ({
file: state.file.file,
isReferencesOpen: state.editor.showing,
isReferencesLoading: state.editor.loading,
references: state.editor.references,
referencesTitle: state.editor.referencesTitle,
panelShowing: state.editor.panelShowing,
isPanelLoading: state.editor.loading,
panelContents: state.editor.panelContents,
panelTitle: state.editor.panelTitle,
hover: state.editor.hover,
refUrl: refUrlSelector(state),
revealPosition: state.editor.revealPosition,
blames: state.blame.blames,
});

const mapDispatchToProps = {
closeReferences,
findReferences,
closePanel,
hoverResult,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import { IPosition } from 'monaco-editor';
import queryString from 'querystring';
import React from 'react';
import { parseSchema } from '../../../common/uri_util';
import { GroupedFileReferences, GroupedRepoReferences } from '../../actions';
import { GroupedFileResults, GroupedRepoResults } from '../../actions';
import { history } from '../../utils/url';
import { CodeBlock } from '../codeblock/codeblock';

interface Props {
isLoading: boolean;
title: string;
references: GroupedRepoReferences[];
references: GroupedRepoResults[];
refUrl?: string;
onClose(): void;
}
Expand Down Expand Up @@ -85,12 +85,12 @@ export class ReferencesPanel extends React.Component<Props, State> {
}

private renderGroupByRepo() {
return this.props.references.map((ref: GroupedRepoReferences) => {
return this.props.references.map((ref: GroupedRepoResults) => {
return this.renderReferenceRepo(ref);
});
}

private renderReferenceRepo({ repo, files }: GroupedRepoReferences) {
private renderReferenceRepo({ repo, files }: GroupedRepoResults) {
const [org, name] = repo.split('/').slice(1);
const buttonContent = (
<span>
Expand All @@ -112,7 +112,7 @@ export class ReferencesPanel extends React.Component<Props, State> {
);
}

private renderReference(file: GroupedFileReferences) {
private renderReference(file: GroupedFileResults) {
const key = `${file.uri}`;
const lineNumberFn = (l: number) => {
return file.lineNumbers[l - 1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import url from 'url';
import queryString from 'querystring';
import { DetailSymbolInformation } from '@elastic/lsp-extension';

import { npStart } from 'ui/new_platform';
import { Location } from 'vscode-languageserver-types';
import { monaco } from '../monaco';
import { LspRestClient, TextDocumentMethods } from '../../../common/lsp_client';
import { parseSchema } from '../../../common/uri_util';
import { history } from '../../utils/url';

export const definitionProvider: monaco.languages.DefinitionProvider = {
async provideDefinition(
Expand Down Expand Up @@ -41,6 +45,20 @@ export const definitionProvider: monaco.languages.DefinitionProvider = {
return [];
}

function openDefinitionsPanel() {
if (model && position) {
const { uri } = parseSchema(model.uri.toString());
const refUrl = `git:/${uri}!L${position.lineNumber - 1}:${position.column - 1}`;
const queries = url.parse(history.location.search, true).query;
const query = queryString.stringify({
...queries,
tab: 'definitions',
refUrl,
});
history.push(`${uri}?${query}`);
}
}

const result = await lspMethods.edefinition.send({
position: {
line: position.lineNumber - 1,
Expand All @@ -52,20 +70,19 @@ export const definitionProvider: monaco.languages.DefinitionProvider = {
});

if (result) {
const locations = result.filter(l => l.location !== undefined).map(l => l.location!);
if (locations.length > 0) {
return locations.map(handleLocation);
if (result.length > 1) {
openDefinitionsPanel();
return [];
} else {
let qnameResults: monaco.languages.Location[] = [];
for (const l of result) {
if (l.qname) {
qnameResults = qnameResults.concat(await handleQname(l.qname));
}
const l = result[0];
const location = l.location;
if (location) {
return [handleLocation(location)];
} else if (l.qname) {
return await handleQname(l.qname);
}
return qnameResults;
}
}

return [];
},
};
99 changes: 63 additions & 36 deletions x-pack/legacy/plugins/code/public/reducers/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,100 @@ import produce from 'immer';
import { handleActions, Action } from 'redux-actions';
import { Hover, TextDocumentPositionParams } from 'vscode-languageserver';
import {
closeReferences,
closePanel,
findReferences,
findReferencesFailed,
findReferencesSuccess,
GroupedRepoReferences,
GroupedRepoResults,
hoverResult,
revealPosition,
ReferenceResults,
PanelResults,
findDefinitions,
findDefinitionsSuccess,
findDefinitionsFailed,
} from '../actions';

export interface EditorState {
loading: boolean;
showing: boolean;
references: GroupedRepoReferences[];
panelShowing: 'references' | 'definitions' | undefined;
panelContents: GroupedRepoResults[];
hover?: Hover;
currentHover?: Hover;
refPayload?: TextDocumentPositionParams;
revealPosition?: Position;
referencesTitle: string;
panelTitle: string;
}
const initialState: EditorState = {
loading: false,
showing: false,
references: [],
referencesTitle: '',
panelShowing: undefined,
panelContents: [],
panelTitle: '',
};

type EditorPayload = ReferenceResults & Hover & TextDocumentPositionParams & Position & string;
type EditorPayload = PanelResults & Hover & TextDocumentPositionParams & Position & string;

function panelInit(draft: EditorState, action: Action<TextDocumentPositionParams>) {
draft.refPayload = action.payload!;
draft.loading = true;
draft.panelContents = initialState.panelContents;
draft.panelTitle = initialState.panelTitle;
}

function panelSuccess(draft: EditorState, action: Action<PanelResults>) {
const { title, repos } = action.payload!;
draft.panelContents = repos;
draft.panelTitle = title;
draft.loading = false;
}
function panelFailed(draft: EditorState) {
draft.panelContents = [];
draft.loading = false;
delete draft.refPayload;
}

export const editor = handleActions<EditorState, EditorPayload>(
{
[String(findReferences)]: (state, action: Action<TextDocumentPositionParams>) =>
produce<EditorState>(state, draft => {
draft.refPayload = action.payload;
draft.showing = true;
draft.loading = true;
draft.references = initialState.references;
draft.hover = state.currentHover;
draft.referencesTitle = initialState.referencesTitle;
produce<EditorState>(state, (draft: EditorState) => {
panelInit(draft, action);
draft.panelShowing = 'references';
}),
[String(findReferencesSuccess)]: (state, action: any) =>
produce<EditorState>(state, draft => {
const { title, repos } = action.payload;
draft.references = repos;
draft.referencesTitle = title;
draft.loading = false;
[String(findReferencesSuccess)]: (state, action: Action<PanelResults>) =>
produce<EditorState>(state, (draft: EditorState) => {
panelSuccess(draft, action);
}),
[String(findReferencesFailed)]: state =>
produce<EditorState>(state, draft => {
draft.references = [];
draft.loading = false;
draft.refPayload = undefined;
produce<EditorState>(state, (draft: EditorState) => {
panelFailed(draft);
}),
[String(findDefinitions)]: (state, action: Action<TextDocumentPositionParams>) =>
produce<EditorState>(state, (draft: EditorState) => {
panelInit(draft, action);
draft.panelShowing = 'definitions';
}),
[String(findDefinitionsSuccess)]: (state, action: Action<PanelResults>) =>
produce<EditorState>(state, (draft: EditorState) => {
panelSuccess(draft, action);
}),
[String(findDefinitionsFailed)]: state =>
produce<EditorState>(state, (draft: EditorState) => {
panelFailed(draft);
}),
[String(closeReferences)]: state =>
produce<EditorState>(state, draft => {
draft.showing = false;
[String(closePanel)]: state =>
produce<EditorState>(state, (draft: EditorState) => {
draft.panelShowing = undefined;
draft.loading = false;
draft.refPayload = undefined;
draft.references = [];
delete draft.refPayload;
draft.panelContents = [];
draft.panelTitle = '';
}),
[String(hoverResult)]: (state, action: Action<Hover>) =>
produce<EditorState>(state, draft => {
draft.currentHover = action.payload;
produce<EditorState>(state, (draft: EditorState) => {
draft.currentHover = action.payload!;
}),
[String(revealPosition)]: (state, action: Action<Position>) =>
produce<EditorState>(state, draft => {
draft.revealPosition = action.payload;
produce<EditorState>(state, (draft: EditorState) => {
draft.revealPosition = action.payload!;
}),
},
initialState
Expand Down
Loading

0 comments on commit 676f4d2

Please sign in to comment.