Skip to content

Commit

Permalink
Merge branch 'main' into 133550-replace-run-now
Browse files Browse the repository at this point in the history
  • Loading branch information
ersin-erdal authored Jun 27, 2022
2 parents 043533c + 6428f38 commit b4bcb8d
Show file tree
Hide file tree
Showing 72 changed files with 1,558 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,48 @@ export class LegacyCoreEditor implements CoreEditor {
destroy() {
this.editor.destroy();
}

/**
* Formats body of the request in the editor by removing the extra whitespaces at the beginning of lines,
* And adds the correct indentation for each line
* @param reqRange request range to indent
*/
autoIndent(reqRange: Range) {
const session = this.editor.getSession();
const mode = session.getMode();
const startRow = reqRange.start.lineNumber;
const endRow = reqRange.end.lineNumber;
const tab = session.getTabString();

for (let row = startRow; row <= endRow; row++) {
let prevLineState = '';
let prevLineIndent = '';
if (row > 0) {
prevLineState = session.getState(row - 1);
const prevLine = session.getLine(row - 1);
prevLineIndent = mode.getNextLineIndent(prevLineState, prevLine, tab);
}

const line = session.getLine(row);
// @ts-ignore
// Brace does not expose type definition for mode.$getIndent, though we have access to this method provided by the underlying Ace editor.
// See https://github.com/ajaxorg/ace/blob/87ce087ed1cf20eeabe56fb0894e048d9bc9c481/lib/ace/mode/text.js#L259
const currLineIndent = mode.$getIndent(line);
if (prevLineIndent !== currLineIndent) {
if (currLineIndent.length > 0) {
// If current line has indentation, remove it.
// Next we will add the correct indentation by looking at the previous line
const range = new _AceRange(row, 0, row, currLineIndent.length);
session.remove(range);
}
if (prevLineIndent.length > 0) {
// If previous line has indentation, add indentation at the current line
session.insert({ row, column: 0 }, prevLineIndent);
}
}

// Lastly outdent any closing braces
mode.autoOutdent(prevLineState, session, row);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function InputHighlightRules() {
start: mergeTokens(
[
{ token: 'warning', regex: '#!.*$' },
{ token: 'comment', regex: /^#.*$/ },
{ include: 'comments' },
{ token: 'paren.lparen', regex: '{', next: 'json', push: true },
],
addEOL(['method'], /([a-zA-Z]+)/, 'start', 'method_sep'),
Expand Down Expand Up @@ -88,9 +88,46 @@ export function InputHighlightRules() {
addEOL(['url.param'], /([^&=]+)/, 'start-sql'),
addEOL(['url.amp'], /(&)/, 'start-sql')
),
/**
* Each key in this.$rules considered to be a state in state machine. Regular expressions define the tokens for the current state, as well as the transitions into another state.
* See for more details https://cloud9-sdk.readme.io/docs/highlighting-rules#section-defining-states
* *
* Define a state for comments, these comment rules then can be included in other states. E.g. in 'start' and 'json' states by including { include: 'comments' }
* This will avoid duplicating the same rules in other states
*/
comments: [
{
// Capture a line comment, indicated by #
token: ['comment.punctuation', 'comment.line'],
regex: /(#)(.*$)/,
},
{
// Begin capturing a block comment, indicated by /*
token: 'comment.punctuation',
regex: /\/\*/,
push: [
{
// Finish capturing a block comment, indicated by */
token: 'comment.punctuation',
regex: /\*\//,
next: 'pop',
},
{
defaultToken: 'comment.block',
},
],
},
{
// Capture a line comment, indicated by //
token: ['comment.punctuation', 'comment.line'],
regex: /(\/\/)(.*$)/,
},
],
};

addXJsonToRules(this);
// Add comment rules to json rule set
this.$rules.json.unshift({ include: 'comments' });

if (this.constructor === InputHighlightRules) {
this.normalizeRules();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1901,8 +1901,8 @@ ace.define(
reset(i + upTo.length);
return text.substring(currentAt, i);
},
peek = function (c) {
return text.substr(at, c.length) === c; // nocommit - double check
peek = function (offset) {
return text.charAt(at + offset);
},
number = function () {
let number,
Expand Down Expand Up @@ -1948,7 +1948,8 @@ ace.define(
uffff;

if (ch === '"') {
if (peek('""')) {
let c = '""';
if (text.substring(at, c.length) === c) {
// literal
next('"');
next('"');
Expand Down Expand Up @@ -1984,8 +1985,31 @@ ace.define(
error('Bad string');
},
white = function () {
while (ch && ch <= ' ') {
next();
while (ch) {
// Skip whitespace.
while (ch && ch <= ' ') {
next();
}
// if the current char in iteration is '#' or the char and the next char is equal to '//'
// we are on the single line comment
if (ch === '#' || ch === '/' && peek(0) === '/') {
// Until we are on the new line, skip to the next char
while (ch && ch !== '\n') {
next();
}
} else if (ch === '/' && peek(0) === '*') {
// If the chars starts with '/*', we are on the multiline comment
next();
next();
while (ch && !(ch === '*' && peek(0) === '/')) {
// Until we have closing tags '*/', skip to the next char
next();
}
if (ch) {
next();
next();
}
} else break;
}
},
strictWhite = function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ export class SenseEditor {
return;
}

if (parsedReq.data.some((doc) => utils.hasComments(doc))) {
/**
* Comments require different approach for indentation and do not have condensed format
* We need to delegate indentation logic to coreEditor since it has access to session and other methods used for formatting and indenting the comments
*/
this.coreEditor.autoIndent(parsedReq.range);
return;
}

if (parsedReq.data && parsedReq.data.length > 0) {
let indent = parsedReq.data.length === 1; // unindent multi docs by default
let formattedData = utils.formatRequestBodyDoc(parsedReq.data, indent);
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/console/public/lib/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,9 @@ export default function ({
case 'paren.rparen':
case 'punctuation.colon':
case 'punctuation.comma':
case 'comment.line':
case 'comment.punctuation':
case 'comment.block':
case 'UNKNOWN':
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/console/public/lib/row_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default class RowParser {
return MODE.IN_REQUEST;
}
let line = (this.editor.getLineValue(lineNumber) || '').trim();
if (!line || line[0] === '#') {
if (!line || line.startsWith('#') || line.startsWith('//') || line.startsWith('/*')) {
return MODE.BETWEEN_REQUESTS;
} // empty line or a comment waiting for a new req to start

Expand Down
6 changes: 6 additions & 0 deletions src/plugins/console/public/lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ export function formatRequestBodyDoc(data: string[], indent: boolean) {
};
}

export function hasComments(data: string) {
// matches single line and multiline comments
const re = /(\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)|(\/\/.*)|(#.*)/;
return re.test(data);
}

export function extractWarningMessages(warnings: string) {
// pattern for valid warning header
const re =
Expand Down
91 changes: 91 additions & 0 deletions src/plugins/console/public/lib/utils/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,95 @@ describe('Utils class', () => {
'e", f"',
]);
});

describe('formatRequestBodyDoc', function () {
const tests = [
{
source: ['{\n "test": {}\n}'],
indent: false,
assert: ['{"test":{}}'],
},
{
source: ['{"test":{}}'],
indent: true,
assert: ['{\n "test": {}\n}'],
},
{
source: ['{\n "test": """a\n b"""\n}'],
indent: false,
assert: ['{"test":"a\\n b"}'],
},
{
source: ['{"test":"a\\n b"}'],
indent: true,
assert: ['{\n "test": """a\n b"""\n}'],
},
];

tests.forEach(({ source, indent, assert }, id) => {
test(`Test ${id}`, () => {
const formattedData = utils.formatRequestBodyDoc(source, indent);
expect(formattedData.data).toEqual(assert);
});
});
});

describe('hasComments', function () {
const runCommentTests = (tests) => {
tests.forEach(({ source, assert }) => {
test(`\n${source}`, () => {
const hasComments = utils.hasComments(source);
expect(hasComments).toEqual(assert);
});
});
};

describe('match single line comments', () => {
runCommentTests([
{ source: '{\n "test": {\n // "f": {}\n "a": "b"\n }\n}', assert: true },
{
source: '{\n "test": {\n "a": "b",\n "f": {\n # "b": {}\n }\n }\n}',
assert: true,
},
]);
});

describe('match multiline comments', () => {
runCommentTests([
{ source: '{\n /* "test": {\n "a": "b"\n } */\n}', assert: true },
{
source:
'{\n "test": {\n "a": "b",\n /* "f": {\n "b": {}\n } */\n "c": 1\n }\n}',
assert: true,
},
]);
});

describe('ignore non-comment tokens', () => {
runCommentTests([
{ source: '{"test":{"a":"b","f":{"b":{"c":{}}}}}', assert: false },
{
source: '{\n "test": {\n "a": "b",\n "f": {\n "b": {}\n }\n }\n}',
assert: false,
},
{ source: '{\n "test": {\n "f": {}\n }\n}', assert: false },
]);
});

describe.skip('ignore comment tokens as values', () => {
runCommentTests([
{ source: '{\n "test": {\n "f": "//"\n }\n}', assert: false },
{ source: '{\n "test": {\n "f": "/* */"\n }\n}', assert: false },
{ source: '{\n "test": {\n "f": "#"\n }\n}', assert: false },
]);
});

describe.skip('ignore comment tokens as field names', () => {
runCommentTests([
{ source: '{\n "#": {\n "f": {}\n }\n}', assert: false },
{ source: '{\n "//": {\n "f": {}\n }\n}', assert: false },
{ source: '{\n "/* */": {\n "f": {}\n }\n}', assert: false },
]);
});
});
});
5 changes: 5 additions & 0 deletions src/plugins/console/public/types/core_editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,9 @@ export interface CoreEditor {
* Release any resources in use by the editor.
*/
destroy(): void;

/**
* Indent document within request range
*/
autoIndent(reqRange: Range): void;
}
Loading

0 comments on commit b4bcb8d

Please sign in to comment.