Skip to content

Commit

Permalink
[Console] Refactor and cleanup of public and server (#60513)
Browse files Browse the repository at this point in the history
* Clean up use of ace in autocomplete in public

Remove ace from lib/autocomplete.ts and set up hooking up of ace
in legacy_core_editor. Also remove use of ace mocks in tests.

* Added TODO in lib/kb (console public)

* Server-side cleanup

Refactored the loading of spec into a new SpecDefinitionsService.
In this way, state can be contained inside of the service as much
as possible. Also converted all JS spec to TS and updated the
Console plugin contract so that processors (which alter loaded
spec) happen at plugin "start" phase.

* Fix types

* Small refactor

- Updated naming of argument variable in registerAutocompleter
- Refactored the SpecDefinitionsService to handle binding of
it's own functions
  • Loading branch information
jloleysens authored Mar 19, 2020
1 parent d5ed93e commit 304b322
Show file tree
Hide file tree
Showing 37 changed files with 497 additions and 425 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@
*/

import ace from 'brace';
import { Editor as IAceEditor } from 'brace';
import { Editor as IAceEditor, IEditSession as IAceEditSession } from 'brace';
import $ from 'jquery';
import { CoreEditor, Position, Range, Token, TokensProvider, EditorEvent } from '../../../types';
import {
CoreEditor,
Position,
Range,
Token,
TokensProvider,
EditorEvent,
AutoCompleterFunction,
} from '../../../types';
import { AceTokensProvider } from '../../../lib/ace_token_provider';
import * as curl from '../sense_editor/curl';
import smartResize from './smart_resize';
Expand Down Expand Up @@ -354,4 +362,48 @@ export class LegacyCoreEditor implements CoreEditor {
}
}
}

registerAutocompleter(autocompleter: AutoCompleterFunction): void {
// Hook into Ace

// disable standard context based autocompletion.
// @ts-ignore
ace.define('ace/autocomplete/text_completer', ['require', 'exports', 'module'], function(
require: any,
exports: any
) {
exports.getCompletions = function(
innerEditor: any,
session: any,
pos: any,
prefix: any,
callback: any
) {
callback(null, []);
};
});

const langTools = ace.acequire('ace/ext/language_tools');

langTools.setCompleters([
{
identifierRegexps: [
/[a-zA-Z_0-9\.\$\-\u00A2-\uFFFF]/, // adds support for dot character
],
getCompletions: (
DO_NOT_USE_1: IAceEditor,
DO_NOT_USE_2: IAceEditSession,
pos: { row: number; column: number },
prefix: string,
callback: (...args: any[]) => void
) => {
const position: Position = {
lineNumber: pos.row + 1,
column: pos.column + 1,
};
autocompleter(position, prefix, callback);
},
},
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,93 +84,90 @@ describe('Integration', () => {
changeListener: function() {},
}; // mimic auto complete

senseEditor.autocomplete._test.getCompletions(
senseEditor,
null,
{ row: cursor.lineNumber - 1, column: cursor.column - 1 },
'',
function(err, terms) {
if (testToRun.assertThrows) {
done();
return;
}
senseEditor.autocomplete._test.getCompletions(senseEditor, null, cursor, '', function(
err,
terms
) {
if (testToRun.assertThrows) {
done();
return;
}

if (err) {
throw err;
}
if (err) {
throw err;
}

if (testToRun.no_context) {
expect(!terms || terms.length === 0).toBeTruthy();
} else {
expect(terms).not.toBeNull();
expect(terms.length).toBeGreaterThan(0);
}
if (testToRun.no_context) {
expect(!terms || terms.length === 0).toBeTruthy();
} else {
expect(terms).not.toBeNull();
expect(terms.length).toBeGreaterThan(0);
}

if (!terms || terms.length === 0) {
done();
return;
}
if (!terms || terms.length === 0) {
done();
return;
}

if (testToRun.autoCompleteSet) {
const expectedTerms = _.map(testToRun.autoCompleteSet, function(t) {
if (typeof t !== 'object') {
t = { name: t };
}
return t;
});
if (terms.length !== expectedTerms.length) {
expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name'));
} else {
const filteredActualTerms = _.map(terms, function(actualTerm, i) {
const expectedTerm = expectedTerms[i];
const filteredTerm = {};
_.each(expectedTerm, function(v, p) {
filteredTerm[p] = actualTerm[p];
});
return filteredTerm;
});
expect(filteredActualTerms).toEqual(expectedTerms);
if (testToRun.autoCompleteSet) {
const expectedTerms = _.map(testToRun.autoCompleteSet, function(t) {
if (typeof t !== 'object') {
t = { name: t };
}
return t;
});
if (terms.length !== expectedTerms.length) {
expect(_.pluck(terms, 'name')).toEqual(_.pluck(expectedTerms, 'name'));
} else {
const filteredActualTerms = _.map(terms, function(actualTerm, i) {
const expectedTerm = expectedTerms[i];
const filteredTerm = {};
_.each(expectedTerm, function(v, p) {
filteredTerm[p] = actualTerm[p];
});
return filteredTerm;
});
expect(filteredActualTerms).toEqual(expectedTerms);
}
}

const context = terms[0].context;
const {
cursor: { lineNumber, column },
} = testToRun;
senseEditor.autocomplete._test.addReplacementInfoToContext(
context,
{ lineNumber, column },
terms[0].value
);
const context = terms[0].context;
const {
cursor: { lineNumber, column },
} = testToRun;
senseEditor.autocomplete._test.addReplacementInfoToContext(
context,
{ lineNumber, column },
terms[0].value
);

function ac(prop, propTest) {
if (typeof testToRun[prop] !== 'undefined') {
if (propTest) {
propTest(context[prop], testToRun[prop], prop);
} else {
expect(context[prop]).toEqual(testToRun[prop]);
}
function ac(prop, propTest) {
if (typeof testToRun[prop] !== 'undefined') {
if (propTest) {
propTest(context[prop], testToRun[prop], prop);
} else {
expect(context[prop]).toEqual(testToRun[prop]);
}
}
}

function posCompare(actual, expected) {
expect(actual.lineNumber).toEqual(expected.lineNumber + lineOffset);
expect(actual.column).toEqual(expected.column);
}

function rangeCompare(actual, expected, name) {
posCompare(actual.start, expected.start, name + '.start');
posCompare(actual.end, expected.end, name + '.end');
}
function posCompare(actual, expected) {
expect(actual.lineNumber).toEqual(expected.lineNumber + lineOffset);
expect(actual.column).toEqual(expected.column);
}

ac('prefixToAdd');
ac('suffixToAdd');
ac('addTemplate');
ac('textBoxPosition', posCompare);
ac('rangeToReplace', rangeCompare);
done();
function rangeCompare(actual, expected, name) {
posCompare(actual.start, expected.start, name + '.start');
posCompare(actual.end, expected.end, name + '.end');
}
);

ac('prefixToAdd');
ac('suffixToAdd');
ac('addTemplate');
ac('textBoxPosition', posCompare);
ac('rangeToReplace', rangeCompare);
done();
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export class SenseEditor {
coreEditor,
parser: this.parser,
});
this.coreEditor.registerAutocompleter(this.autocomplete.getCompletions);
this.coreEditor.on(
'tokenizerUpdate',
this.highlightCurrentRequestsAndUpdateActionBar.bind(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import '../../../application/models/sense_editor/sense_editor.test.mocks';

const _ = require('lodash');
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
import '../../../application/models/sense_editor/sense_editor.test.mocks';
import 'brace';
import 'brace/mode/javascript';
import 'brace/mode/json';
const _ = require('lodash');
import { UrlParams } from '../../autocomplete/url_params';
import { populateContext } from '../../autocomplete/engine';
Expand Down
71 changes: 17 additions & 54 deletions src/plugins/console/public/lib/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
*/

import _ from 'lodash';
import ace, { Editor as AceEditor, IEditSession } from 'brace';
import { i18n } from '@kbn/i18n';

// TODO: All of these imports need to be moved to the core editor so that it can inject components from there.
import {
getTopLevelUrlCompleteComponents,
getEndpointBodyCompleteComponents,
Expand All @@ -39,7 +39,7 @@ import { createTokenIterator } from '../../application/factories';

import { Position, Token, Range, CoreEditor } from '../../types';

let LAST_EVALUATED_TOKEN: any = null;
let lastEvaluatedToken: any = null;

function isUrlParamsToken(token: any) {
switch ((token || {}).type) {
Expand Down Expand Up @@ -889,7 +889,7 @@ export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor

if (!currentToken) {
if (pos.lineNumber === 1) {
LAST_EVALUATED_TOKEN = null;
lastEvaluatedToken = null;
return;
}
currentToken = { position: { column: 0, lineNumber: 0 }, value: '', type: '' }; // empty row
Expand All @@ -902,26 +902,26 @@ export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor
if (parser.isEmptyToken(nextToken)) {
// Empty line, or we're not on the edge of current token. Save the current position as base
currentToken.position.column = pos.column;
LAST_EVALUATED_TOKEN = currentToken;
lastEvaluatedToken = currentToken;
} else {
nextToken.position.lineNumber = pos.lineNumber;
LAST_EVALUATED_TOKEN = nextToken;
lastEvaluatedToken = nextToken;
}
return;
}

if (!LAST_EVALUATED_TOKEN) {
LAST_EVALUATED_TOKEN = currentToken;
if (!lastEvaluatedToken) {
lastEvaluatedToken = currentToken;
return; // wait for the next typing.
}

if (
LAST_EVALUATED_TOKEN.position.column !== currentToken.position.column ||
LAST_EVALUATED_TOKEN.position.lineNumber !== currentToken.position.lineNumber ||
LAST_EVALUATED_TOKEN.value === currentToken.value
lastEvaluatedToken.position.column !== currentToken.position.column ||
lastEvaluatedToken.position.lineNumber !== currentToken.position.lineNumber ||
lastEvaluatedToken.value === currentToken.value
) {
// not on the same place or nothing changed, cache and wait for the next time
LAST_EVALUATED_TOKEN = currentToken;
lastEvaluatedToken = currentToken;
return;
}

Expand All @@ -935,7 +935,7 @@ export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor
return;
}

LAST_EVALUATED_TOKEN = currentToken;
lastEvaluatedToken = currentToken;
editor.execCommand('startAutocomplete');
},
100);
Expand All @@ -947,17 +947,7 @@ export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor
}
}

function getCompletions(
DO_NOT_USE: AceEditor,
DO_NOT_USE_SESSION: IEditSession,
pos: { row: number; column: number },
prefix: string,
callback: (...args: any[]) => void
) {
const position: Position = {
lineNumber: pos.row + 1,
column: pos.column + 1,
};
function getCompletions(position: Position, prefix: string, callback: (...args: any[]) => void) {
try {
const context = getAutoCompleteContext(editor, position);
if (!context) {
Expand Down Expand Up @@ -1028,39 +1018,12 @@ export default function({ coreEditor: editor, parser }: { coreEditor: CoreEditor

editor.on('changeSelection', editorChangeListener);

// Hook into Ace

// disable standard context based autocompletion.
// @ts-ignore
ace.define('ace/autocomplete/text_completer', ['require', 'exports', 'module'], function(
require: any,
exports: any
) {
exports.getCompletions = function(
innerEditor: any,
session: any,
pos: any,
prefix: any,
callback: any
) {
callback(null, []);
};
});

const langTools = ace.acequire('ace/ext/language_tools');

langTools.setCompleters([
{
identifierRegexps: [
/[a-zA-Z_0-9\.\$\-\u00A2-\uFFFF]/, // adds support for dot character
],
getCompletions,
},
]);

return {
getCompletions,
// TODO: This needs to be cleaned up
_test: {
getCompletions,
getCompletions: (_editor: any, _editSession: any, pos: any, prefix: any, callback: any) =>
getCompletions(pos, prefix, callback),
addReplacementInfoToContext,
addChangeListener: () => editor.on('changeSelection', editorChangeListener),
removeChangeListener: () => editor.off('changeSelection', editorChangeListener),
Expand Down
Loading

0 comments on commit 304b322

Please sign in to comment.