Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions x-pack/plugins/code/public/actions/structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SymbolInformation } from 'vscode-languageserver-types/lib/esm/main';
export interface SymbolsPayload {
path: string;
data: SymbolInformation[];
structureTree: any;
}

export const loadStructure = createAction<string>('LOAD STRUCTURE');
Expand Down
81 changes: 2 additions & 79 deletions x-pack/plugins/code/public/reducers/symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,11 @@ import {
} from '../actions';
import { languageServerInitializing } from '../actions/language_server';

const SPECIAL_SYMBOL_NAME = '{...}';
const SPECIAL_CONTAINER_NAME = '';

export interface SymbolWithMembers extends SymbolInformation {
members?: SymbolWithMembers[];
path?: string;
}

type Container = SymbolWithMembers | undefined;

export interface SymbolState {
symbols: { [key: string]: SymbolInformation[] };
structureTree: { [key: string]: SymbolWithMembers[] };
Expand All @@ -47,78 +42,6 @@ const initialState: SymbolState = {
languageServerInitializing: false,
};

const sortSymbol = (a: SymbolWithMembers, b: SymbolWithMembers) => {
const lineDiff = a.location.range.start.line - b.location.range.start.line;
if (lineDiff === 0) {
return a.location.range.start.character - b.location.range.start.character;
} else {
return lineDiff;
}
};

const generateStructureTree: (symbols: SymbolInformation[]) => any = symbols => {
const structureTree: SymbolWithMembers[] = [];

function findContainer(
tree: SymbolWithMembers[],
containerName?: string
): SymbolInformation | undefined {
if (containerName === undefined) {
return undefined;
}
const regex = new RegExp(`^${containerName}[<(]?.*[>)]?$`);
const result = tree.find((s: SymbolInformation) => {
return regex.test(s.name);
});
if (result) {
return result;
} else {
// TODO: Use Array.flat once supported
const subTree = tree.reduce(
(s, t) => (t.members ? s.concat(t.members) : s),
[] as SymbolWithMembers[]
);
if (subTree.length > 0) {
return findContainer(subTree, containerName);
} else {
return undefined;
}
}
}

symbols
.sort(sortSymbol)
.forEach((s: SymbolInformation, index: number, arr: SymbolInformation[]) => {
let container: Container;
/**
* For Enum class in Java, the container name and symbol name that LSP gives are special.
* For more information, see https://github.com/elastic/codesearch/issues/580
*/
if (s.containerName === SPECIAL_CONTAINER_NAME) {
container = _.findLast(
arr.slice(0, index),
(sy: SymbolInformation) => sy.name === SPECIAL_SYMBOL_NAME
);
} else {
container = findContainer(structureTree, s.containerName);
}
if (container) {
if (!container.path) {
container.path = container.name;
}
if (container.members) {
container.members.push({ ...s, path: `${container.path}/${s.name}` });
} else {
container.members = [{ ...s, path: `${container.path}/${s.name}` }];
}
} else {
structureTree.push({ ...s, path: s.name });
}
});

return structureTree;
};

export const symbol = handleActions(
{
[String(loadStructure)]: (state: SymbolState, action: Action<any>) =>
Expand All @@ -129,8 +52,8 @@ export const symbol = handleActions(
[String(loadStructureSuccess)]: (state: SymbolState, action: Action<SymbolsPayload>) =>
produce<SymbolState>(state, (draft: SymbolState) => {
draft.loading = false;
const { path, data } = action.payload!;
draft.structureTree[path] = generateStructureTree(data);
const { path, data, structureTree } = action.payload!;
draft.structureTree[path] = structureTree;
draft.symbols = {
...state.symbols,
[path]: data,
Expand Down
82 changes: 81 additions & 1 deletion x-pack/plugins/code/public/sagas/structure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,92 @@
import { Action } from 'redux-actions';
import { delay } from 'redux-saga';
import { call, put, takeEvery, cancel, take, fork } from 'redux-saga/effects';
import { SymbolInformation } from 'vscode-languageserver-types/lib/esm/main';
import { LspRestClient, TextDocumentMethods } from '../../common/lsp_client';
import { loadStructure, loadStructureFailed, loadStructureSuccess } from '../actions';
import { ServerNotInitialized } from '../../common/lsp_error_codes';
import { languageServerInitializing } from '../actions/language_server';
import { SymbolWithMembers } from '../reducers/symbol';

const STRUCTURE_TREE_POLLING_INTERVAL_SEC = 3;

type Container = SymbolWithMembers | undefined;

const SPECIAL_SYMBOL_NAME = '{...}';
const SPECIAL_CONTAINER_NAME = '';

const sortSymbol = (a: SymbolWithMembers, b: SymbolWithMembers) => {
const lineDiff = a.location.range.start.line - b.location.range.start.line;
if (lineDiff === 0) {
return a.location.range.start.character - b.location.range.start.character;
} else {
return lineDiff;
}
};

const generateStructureTree: (symbols: SymbolInformation[]) => any = symbols => {
const structureTree: SymbolWithMembers[] = [];

function findContainer(
tree: SymbolWithMembers[],
containerName?: string
): SymbolInformation | undefined {
if (containerName === undefined) {
return undefined;
}
const regex = new RegExp(`^${containerName}[<(]?.*[>)]?$`);
const result = tree.find((s: SymbolInformation) => {
return regex.test(s.name);
});
if (result) {
return result;
} else {
// TODO: Use Array.flat once supported
const subTree = tree.reduce(
(s, t) => (t.members ? s.concat(t.members) : s),
[] as SymbolWithMembers[]
);
if (subTree.length > 0) {
return findContainer(subTree, containerName);
} else {
return undefined;
}
}
}

symbols
.sort(sortSymbol)
.forEach((s: SymbolInformation, index: number, arr: SymbolInformation[]) => {
let container: Container;
/**
* For Enum class in Java, the container name and symbol name that LSP gives are special.
* For more information, see https://github.com/elastic/codesearch/issues/580
*/
if (s.containerName === SPECIAL_CONTAINER_NAME) {
container = _.findLast(
arr.slice(0, index),
(sy: SymbolInformation) => sy.name === SPECIAL_SYMBOL_NAME
);
} else {
container = findContainer(structureTree, s.containerName);
}
if (container) {
if (!container.path) {
container.path = container.name;
}
if (container.members) {
container.members.push({ ...s, path: `${container.path}/${s.name}` });
} else {
container.members = [{ ...s, path: `${container.path}/${s.name}` }];
}
} else {
structureTree.push({ ...s, path: s.name });
}
});

return structureTree;
};

function requestStructure(uri?: string) {
const lspClient = new LspRestClient('/api/code/lsp');
const lspMethods = new TextDocumentMethods(lspClient);
Expand Down Expand Up @@ -42,7 +121,8 @@ function* pollingSaga(action: Action<string>) {
while (true) {
try {
const data = yield call(requestStructure, `git:/${action.payload}`);
yield put(loadStructureSuccess({ path: action.payload!, data }));
const structureTree = generateStructureTree(data);
yield put(loadStructureSuccess({ path: action.payload!, data, structureTree }));
} catch (e) {
if (e.code && e.code === ServerNotInitialized) {
yield put(languageServerInitializing());
Expand Down