editor.getEngulfingRequestsRange = onceDoneTokenizing(function (range, cb) { if (_.isUndefined(cb)) { cb = range; range = null; } range = range || editor.getSelectionRange(); var session = editor.getSession(); var startRow = range.start.row; var endRow = range.end.row; var maxLine = Math.max(0, session.getLength() - 1); // move start row to the previous request start if in body, o.w. forward if (editor.parser.isInBetweenRequestsRow(startRow)) { //for (; startRow <= endRow; startRow++) { // if (editor.parser.isStartRequestRow(startRow)) { // break; // } //} } else { for (; startRow >= 0; startRow--) { if (editor.parser.isStartRequestRow(startRow)) { break; } } } if (startRow < 0 || startRow > endRow) { cb(null); return; } // move end row to the previous request end if between requests, o.w. walk forward if (editor.parser.isInBetweenRequestsRow(endRow)) { for (; endRow >= startRow; endRow--) { if (editor.parser.isEndRequestRow(endRow)) { break; } } } else { for (; endRow <= maxLine; endRow++) { if (editor.parser.isEndRequestRow(endRow)) { break; } } } if (endRow < startRow || endRow > maxLine) { cb(null); return; } var endColumn = (session.getLine(endRow) || "").replace(/\s+$/, "").length; cb(new (ace.require("ace/range").Range)(startRow, 0, endRow, endColumn)); });
editor.getRequestInRange = onceDoneTokenizing(function (range, cb) { var request = { method: "", data: [], url: null, range: range }; var pos = range.start; var tokenIter = editor.iterForPosition(pos.row, pos.column, editor); var t = tokenIter.getCurrentToken(); if (editor.parser.isEmptyToken(t)) { // if the row starts with some spaces, skip them. t = editor.parser.nextNonEmptyToken(tokenIter); } request.method = t.value; t = editor.parser.nextNonEmptyToken(tokenIter); if (!t || t.type == "method") { return null; } request.url = ""; while (t && t.type && t.type.indexOf("url") == 0) { request.url += t.value; t = tokenIter.stepForward(); } if (editor.parser.isEmptyToken(t)) { // if the url row ends with some spaces, skip them. t = editor.parser.nextNonEmptyToken(tokenIter); } var bodyStartRow = (t ? 0 : 1) + tokenIter.getCurrentTokenRow(); // artificially increase end of docs. var dataEndPos; while (bodyStartRow < range.end.row || ( bodyStartRow == range.end.row && 0 < range.end.column )) { dataEndPos = editor.nextDataDocEnd({ row: bodyStartRow, column: 0 }); var bodyRange = new (ace.require("ace/range").Range)( bodyStartRow, 0, dataEndPos.row, dataEndPos.column ); var data = editor.getSession().getTextRange(bodyRange); request.data.push(data.trim()); bodyStartRow = dataEndPos.row + 1; } cb(request); });
editor.getRequestRange = onceDoneTokenizing(function (row, cb) { if (_.isUndefined(cb)) { cb = row; row = null; } if (typeof cb !== 'function') { return; } if (editor.parser.isInBetweenRequestsRow(row)) { cb(null); return } var reqStart = editor.prevRequestStart(row, editor); var reqEnd = editor.nextRequestEnd(reqStart, editor); cb(new (ace.require("ace/range").Range)( reqStart.row, reqStart.column, reqEnd.row, reqEnd.column )); });
import _ from 'lodash'; import ace from 'ace'; import pythonCompleter from './python-completer'; const Autocomplete = ace.require('ace/autocomplete').Autocomplete, langTools = ace.require('ace/ext/language_tools'); let dynamicSettingMap; dynamicSettingMap = { disabled: function (instance, value) { instance.textInput.getElement().disabled = value; }, fontSize: function (instance, value) { instance.setFontSize(value); }, keyBindings: function (instance, value) { instance.setKeyboardHandler(value === 'default' ? null : value); }, highlightLine: function (instance, value) { instance.setHighlightActiveLine(value); }, mode: function (instance, value) { instance.getSession().setMode('ace/mode/' + value); }, readOnly: function (instance, value) { instance.setReadOnly(value); }, tabSize: function (instance, value) { instance.getSession().setTabSize(value); }, theme: function (instance, value) {
module.exports = function (editor) { function isSeparatorToken(token) { switch ((token || {}).type) { case "url.slash": case "url.comma": case "url.questionmark": case "paren.lparen": case "paren.rparen": case "punctuation.colon": case "punctuation.comma": case "whitespace": return true; default: // standing on white space, quotes or another punctuation - no replacing return false; } } function isUrlPathToken(token) { switch ((token || {}).type) { case "url.slash": case "url.comma": case "url.part": return true; default: return false; } } function isUrlParamsToken(token) { switch ((token || {}).type) { case "url.param": case "url.equal": case "url.value": case "url.questionmark": case "url.amp": return true; default: return false; } } function getAutoCompleteValueFromToken(token) { switch ((token || {}).type) { case "variable": case "string": case "text": case "constant.numeric": case "constant.language.boolean": return token.value.replace(/"/g, ''); case "method": case "url.part": return token.value; default: // standing on white space, quotes or another punctuation - no replacing return ""; } } function addMetaToTermsList(list, meta, template) { return _.map(list, function (t) { if (typeof t !== "object") { t = { name: t }; } return _.defaults(t, { meta: meta, template: template }); }); } function termToFilterRegex(term, prefix, suffix) { if (!prefix) { prefix = ""; } if (!suffix) { suffix = ""; } return new RegExp(prefix + term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + suffix, 'i'); } function applyTerm(term) { var session = editor.getSession(); var context = term.context; // make sure we get up to date replacement info. addReplacementInfoToContext(context, editor.getCursorPosition(), term.insert_value); var termAsString; if (context.autoCompleteType == "body") { termAsString = typeof term.insert_value == "string" ? '"' + term.insert_value + '"' : term.insert_value + ""; if (term.insert_value === "[" || term.insert_value === "{") { termAsString = ""; } } else { termAsString = term.insert_value + ""; } var valueToInsert = termAsString; var templateInserted = false; if (context.addTemplate && !_.isUndefined(term.template) && !_.isNull(term.template)) { var indentedTemplateLines = utils.jsonToString(term.template, true).split("\n"); var currentIndentation = session.getLine(context.rangeToReplace.start.row); currentIndentation = currentIndentation.match(/^\s*/)[0]; for (var i = 1; i < indentedTemplateLines.length; i++) // skip first line indentedTemplateLines[i] = currentIndentation + indentedTemplateLines[i]; valueToInsert += ": " + indentedTemplateLines.join("\n"); templateInserted = true; } else { templateInserted = true; if (term.value === "[") { valueToInsert += "[]"; } else if (term.value == "{") { valueToInsert += "{}"; } else { templateInserted = false; } } valueToInsert = context.prefixToAdd + valueToInsert + context.suffixToAdd; // disable listening to the changes we are making. removeChangeListener(); if (context.rangeToReplace.start.column != context.rangeToReplace.end.column) { session.replace(context.rangeToReplace, valueToInsert); } else { editor.insert(valueToInsert); } editor.clearSelection(); // for some reason the above changes selection // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. var newPos = { row: context.rangeToReplace.start.row, column: context.rangeToReplace.start.column + termAsString.length + context.prefixToAdd.length + (templateInserted ? 0 : context.suffixToAdd.length) }; var tokenIter = editor.iterForPosition(newPos.row, newPos.column); if (context.autoCompleteType === "body") { // look for the next place stand, just after a comma, { var nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); switch (nonEmptyToken ? nonEmptyToken.type : "NOTOKEN") { case "paren.rparen": newPos = { row: tokenIter.getCurrentTokenRow(), column: tokenIter.getCurrentTokenColumn() }; break; case "punctuation.colon": nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); if ((nonEmptyToken || {}).type == "paren.lparen") { nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); newPos = { row: tokenIter.getCurrentTokenRow(), column: tokenIter.getCurrentTokenColumn() }; if (nonEmptyToken && nonEmptyToken.value.indexOf('"') === 0) { newPos.column++; } // don't stand on " } break; case "paren.lparen": case "punctuation.comma": tokenIter.stepForward(); newPos = { row: tokenIter.getCurrentTokenRow(), column: tokenIter.getCurrentTokenColumn() }; break; } editor.moveCursorToPosition(newPos); } // re-enable listening to typing addChangeListener(); } function getAutoCompleteContext(editor, session, pos) { // deduces all the parameters need to position and insert the auto complete var context = { autoCompleteSet: null, // instructions for what can be here endpoint: null, urlPath: null, method: null, activeScheme: null, editor: editor }; // context.updatedForToken = session.getTokenAt(pos.row, pos.column); // // if (!context.updatedForToken) // context.updatedForToken = { value: "", start: pos.column }; // empty line // // context.updatedForToken.row = pos.row; // extend context.autoCompleteType = getAutoCompleteType(pos); switch (context.autoCompleteType) { case "path": addPathAutoCompleteSetToContext(context, pos); break; case "url_params": addUrlParamsAutoCompleteSetToContext(context, pos); break; case "method": addMethodAutoCompleteSetToContext(context, pos); break; case "body": addBodyAutoCompleteSetToContext(context, pos); break; default: return null; } if (!context.autoCompleteSet) { return null; // nothing to do.. } addReplacementInfoToContext(context, pos); context.createdWithToken = _.clone(context.updatedForToken); return context; } function getAutoCompleteType(pos) { // return "method", "path" or "body" to determine auto complete type. var rowMode = editor.parser.getRowParseMode(pos.row); //noinspection JSBitwiseOperatorUsage if (rowMode & editor.parser.MODE.IN_REQUEST) { return "body"; } //noinspection JSBitwiseOperatorUsage if (rowMode & editor.parser.MODE.REQUEST_START) { // on url path, url params or method. var tokenIter = editor.iterForPosition(pos.row, pos.column); var t = tokenIter.getCurrentToken(); while (t.type == "url.comma") { t = tokenIter.stepBackward(); } switch (t.type) { case "method": return "method"; case "whitespace": t = editor.parser.prevNonEmptyToken(tokenIter); switch ((t || {}).type) { case "method": // we moved one back return "path"; break; default: if (isUrlPathToken(t)) { return "path"; } if (isUrlParamsToken(t)) { return "url_params"; } return null; } break; default: if (isUrlPathToken(t)) { return "path"; } if (isUrlParamsToken(t)) { return "url_params"; } return null; } } // after start to avoid single line url only requests //noinspection JSBitwiseOperatorUsage if (rowMode & editor.parser.MODE.REQUEST_END) { return "body" } // in between request on an empty if ((editor.getSession().getLine(pos.row) || "").trim() === "") { // check if the previous line is a single line begging of a new request rowMode = editor.parser.getRowParseMode(pos.row - 1); //noinspection JSBitwiseOperatorUsage if ((rowMode & editor.parser.MODE.REQUEST_START) && (rowMode & editor.parser.MODE.REQUEST_END)) { return "body"; } //o.w suggest a method return "method"; } return null; } function addReplacementInfoToContext(context, pos, replacingTerm) { // extract the initial value, rangeToReplace & textBoxPosition // Scenarios for current token: // - Nice token { "bla|" // - Broken text token { bla| // - No token : { | // - Broken scenario { , bla| // - Nice token, broken before: {, "bla" var session = editor.getSession(); var insertingRelativeToToken; context.updatedForToken = _.clone(session.getTokenAt(pos.row, pos.column)); if (!context.updatedForToken) { context.updatedForToken = { value: "", start: pos.column }; } // empty line var anchorToken = context.createdWithToken; if (!anchorToken) { anchorToken = context.updatedForToken; } switch (context.updatedForToken.type) { case "variable": case "string": case "text": case "constant.numeric": case "constant.language.boolean": case "method": case "url.index": case "url.type": case "url.id": case "url.method": case "url.endpoint": case "url.part": case "url.param": case "url.value": insertingRelativeToToken = 0; context.rangeToReplace = new AceRange( pos.row, anchorToken.start, pos.row, context.updatedForToken.start + context.updatedForToken.value.length ); context.replacingToken = true; break; default: if (replacingTerm && context.updatedForToken.value == replacingTerm) { insertingRelativeToToken = 0; context.rangeToReplace = new AceRange( pos.row, anchorToken.start, pos.row, context.updatedForToken.start + context.updatedForToken.value.length ); context.replacingToken = true; } else { // standing on white space, quotes or another punctuation - no replacing context.rangeToReplace = new AceRange( pos.row, pos.column, pos.row, pos.column ); context.replacingToken = false; } break; } context.textBoxPosition = { row: context.rangeToReplace.start.row, column: context.rangeToReplace.start.column }; switch (context.autoCompleteType) { case "path": addPathPrefixSuffixToContext(context); break; case "url_params": addUrlParamsPrefixSuffixToContext(context); break; case "method": addMethodPrefixSuffixToContext(context); break; case "body": addBodyPrefixSuffixToContext(context); break; } } function addBodyPrefixSuffixToContext(context) { // Figure out what happens next to the token to see whether it needs trailing commas etc. // Templates will be used if not destroying existing structure. // -> token : {} or token ]/} or token , but not token : SOMETHING ELSE context.prefixToAdd = ""; context.suffixToAdd = ""; var tokenIter = editor.iterForCurrentLoc(); var nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); switch (nonEmptyToken ? nonEmptyToken.type : "NOTOKEN") { case "NOTOKEN": case "paren.lparen": case "paren.rparen": case "punctuation.comma": context.addTemplate = true; break; case "punctuation.colon": // test if there is an empty object - if so we replace it context.addTemplate = false; nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); if (!(nonEmptyToken && nonEmptyToken.value == "{")) { break; } nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); if (!(nonEmptyToken && nonEmptyToken.value == "}")) { break; } context.addTemplate = true; // extend range to replace to include all up to token context.rangeToReplace.end.row = tokenIter.getCurrentTokenRow(); context.rangeToReplace.end.column = tokenIter.getCurrentTokenColumn() + nonEmptyToken.value.length; // move one more time to check if we need a trailing comma nonEmptyToken = editor.parser.nextNonEmptyToken(tokenIter); switch (nonEmptyToken ? nonEmptyToken.type : "NOTOKEN") { case "NOTOKEN": case "paren.rparen": case "punctuation.comma": case "punctuation.colon": break; default: context.suffixToAdd = ", " } break; default: context.addTemplate = true; context.suffixToAdd = ", "; break; // for now play safe and do nothing. May be made smarter. } // go back to see whether we have one of ( : { & [ do not require a comma. All the rest do. tokenIter = editor.iterForCurrentLoc(); nonEmptyToken = tokenIter.getCurrentToken(); var insertingRelativeToToken; // -1 is before token, 0 middle, +1 after token if (context.replacingToken) { insertingRelativeToToken = 0; } else { var pos = editor.getCursorPosition(); if (pos.column == context.updatedForToken.start) { insertingRelativeToToken = -1; } else if (pos.column < context.updatedForToken.start + context.updatedForToken.value.length) { insertingRelativeToToken = 0; } else { insertingRelativeToToken = 1; } } // we should actually look at what's happening before this token if (editor.parser.isEmptyToken(nonEmptyToken) || insertingRelativeToToken <= 0) { nonEmptyToken = editor.parser.prevNonEmptyToken(tokenIter); } switch (nonEmptyToken ? nonEmptyToken.type : "NOTOKEN") { case "NOTOKEN": case "paren.lparen": case "punctuation.comma": case "punctuation.colon": case "method": break; default: if (nonEmptyToken && nonEmptyToken.type.indexOf("url") < 0) { context.prefixToAdd = ", " } } return context; } function addUrlParamsPrefixSuffixToContext(context) { context.prefixToAdd = ""; context.suffixToAdd = ""; } function addMethodPrefixSuffixToContext(context) { context.prefixToAdd = ""; context.suffixToAdd = ""; var tokenIter = editor.iterForCurrentLoc(); var row = tokenIter.getCurrentTokenRow(); var t = editor.parser.nextNonEmptyToken(tokenIter); if (tokenIter.getCurrentTokenRow() != row || !t) { // we still have nothing next to the method, add a space.. context.suffixToAdd = " "; } } function addPathPrefixSuffixToContext(context) { context.prefixToAdd = ""; context.suffixToAdd = ""; } function addMethodAutoCompleteSetToContext(context, pos) { context.autoCompleteSet = _.map(["GET", "PUT", "POST", "DELETE", "HEAD"], function (m, i) { return { name: m, score: -i, meta: "method" } }) } function addPathAutoCompleteSetToContext(context, pos) { var ret = getCurrentMethodAndTokenPaths(pos); context.method = ret.method; context.token = ret.token; context.otherTokenValues = ret.otherTokenValues; context.urlTokenPath = ret.urlTokenPath; autocomplete_engine.populateContext(ret.urlTokenPath, context, editor, true, kb.getTopLevelUrlCompleteComponents()); context.autoCompleteSet = addMetaToTermsList(context.autoCompleteSet, "endpoint"); } function addUrlParamsAutoCompleteSetToContext(context, pos) { var ret = getCurrentMethodAndTokenPaths(pos); context.method = ret.method; context.otherTokenValues = ret.otherTokenValues; context.urlTokenPath = ret.urlTokenPath; if (!ret.urlTokenPath) { // zero length tokenPath is true console.log("Can't extract a valid url token path."); return context; } autocomplete_engine.populateContext(ret.urlTokenPath, context, editor, false, kb.getTopLevelUrlCompleteComponents()); if (!context.endpoint) { console.log("couldn't resolve an endpoint."); return context; } if (!ret.urlParamsTokenPath) { // zero length tokenPath is true console.log("Can't extract a valid urlParams token path."); return context; } var tokenPath = [], currentParam = ret.urlParamsTokenPath.pop(); if (currentParam) { tokenPath = Object.keys(currentParam); // single key object context.otherTokenValues = currentParam[tokenPath[0]]; } autocomplete_engine.populateContext(tokenPath, context, editor, true, context.endpoint.paramsAutocomplete.getTopLevelComponents()); return context; } function addBodyAutoCompleteSetToContext(context, pos) { var ret = getCurrentMethodAndTokenPaths(pos); context.method = ret.method; context.otherTokenValues = ret.otherTokenValues; context.urlTokenPath = ret.urlTokenPath; context.requestStartRow = ret.requestStartRow; if (!ret.urlTokenPath) { // zero length tokenPath is true console.log("Can't extract a valid url token path."); return context; } autocomplete_engine.populateContext(ret.urlTokenPath, context, editor, false, kb.getTopLevelUrlCompleteComponents()); context.bodyTokenPath = ret.bodyTokenPath; if (!ret.bodyTokenPath) { // zero length tokenPath is true console.log("Can't extract a valid body token path."); return context; } // needed for scope linking + global term resolving context.endpointComponentResolver = kb.getEndpointBodyCompleteComponents; context.globalComponentResolver = kb.getGlobalAutocompleteComponents; var components; if (context.endpoint) { components = context.endpoint.bodyAutocompleteRootComponents; } else { components = kb.getUnmatchedEndpointComponents(); } autocomplete_engine.populateContext(ret.bodyTokenPath, context, editor, true, components); return context; } function getCurrentMethodAndTokenPaths(pos) { var tokenIter = editor.iterForPosition(pos.row, pos.column); var startPos = pos; var bodyTokenPath = [], last_var = "", first_scope = true, ret = {}; var STATES = { looking_for_key: 0, // looking for a key but without jumping over anything but white space and colon. looking_for_scope_start: 1, // skip everything until scope start start: 3 }; var state = STATES.start; // initialization problems - var t = tokenIter.getCurrentToken(); if (t) { if (startPos.column == 0) { // if we are at the beginning of the line, the current token is the one after cursor, not before which // deviates from the standard. t = tokenIter.stepBackward(); state = STATES.looking_for_scope_start; } } else { if (startPos.column == 0) { // empty lines do no have tokens, move one back t = tokenIter.stepBackward(); state = STATES.start; } } var walkedSomeBody = false; // climb one scope at a time and get the scope key for (; t && t.type.indexOf("url") == -1 && t.type != "method"; t = tokenIter.stepBackward()) { if (t.type != "whitespace") { walkedSomeBody = true; } // marks we saw something switch (t.type) { case "variable": if (state == STATES.looking_for_key) { bodyTokenPath.unshift(t.value.trim().replace(/"/g, '')); } state = STATES.looking_for_scope_start; // skip everything until the beginning of this scope break; case "paren.lparen": bodyTokenPath.unshift(t.value); if (state == STATES.looking_for_scope_start) { // found it. go look for the relevant key state = STATES.looking_for_key; } break; case "paren.rparen": // reset he search for key state = STATES.looking_for_scope_start; // and ignore this sub scope.. var parenCount = 1; t = tokenIter.stepBackward(); while (t && parenCount > 0) { switch (t.type) { case "paren.lparen": parenCount--; break; case "paren.rparen": parenCount++; break; } if (parenCount > 0) { t = tokenIter.stepBackward(); } } if (!t) // oops we run out.. we don't know what's up return null; { return {}; } continue; case "punctuation.end_triple_quote": // reset the search for key state = STATES.looking_for_scope_start; for (t = tokenIter.stepBackward(); t; t = tokenIter.stepBackward()) { if (t.type === "punctuation.start_tripple_qoute") { t = tokenIter.stepBackward(); break; } } if (!t) // oops we run out.. we don't know what's up return null; { return {}; } continue; case "punctuation.start_triple_quote": if (state == STATES.start) { state = STATES.looking_for_key; } else if (state == STATES.looking_for_key) { state = STATES.looking_for_scope_start; } bodyTokenPath.unshift('"""'); continue; case "string": case "constant.numeric": case "constant.language.boolean": case "text": if (state == STATES.start) { state = STATES.looking_for_key; } else if (state == STATES.looking_for_key) { state = STATES.looking_for_scope_start; } break; case "punctuation.comma": if (state == STATES.start) { state = STATES.looking_for_scope_start; } break; case "punctuation.colon": case "whitespace": if (state == STATES.start) { state = STATES.looking_for_key; } break; // skip white space } } if (walkedSomeBody && (!bodyTokenPath || bodyTokenPath.length == 0)) { // we had some content and still no path -> the cursor is position after a closed body -> no auto complete return {}; } if (tokenIter.getCurrentTokenRow() == startPos.row) { if (t.type === "url.part" || t.type === "url.param" || t.type === "url.value") { // we are on the same line as cursor and dealing with a url. Current token is not part of the context t = tokenIter.stepBackward(); } bodyTokenPath = null; // no not on a body line. } ret.bodyTokenPath = bodyTokenPath; ret.urlTokenPath = []; ret.urlParamsTokenPath = null; ret.requestStartRow = tokenIter.getCurrentTokenRow(); var curUrlPart; while (t && isUrlParamsToken(t)) { switch (t.type) { case "url.value": if (_.isArray(curUrlPart)) { curUrlPart.unshift(t.value); } else if (curUrlPart) { curUrlPart = [t.value, curUrlPart]; } else { curUrlPart = t.value; } break; case "url.comma": if (!curUrlPart) { curUrlPart = []; } else if (!_.isArray(curUrlPart)) { curUrlPart = [curUrlPart]; } break; case "url.param": var v = curUrlPart; curUrlPart = {}; curUrlPart[t.value] = v; break; case "url.amp": case "url.questionmark": if (!ret.urlParamsTokenPath) { ret.urlParamsTokenPath = []; } ret.urlParamsTokenPath.unshift(curUrlPart || {}); curUrlPart = null; break; } t = tokenIter.stepBackward(); } curUrlPart = null; while (t && t.type.indexOf("url") != -1) { switch (t.type) { case "url.part": if (_.isArray(curUrlPart)) { curUrlPart.unshift(t.value); } else if (curUrlPart) { curUrlPart = [t.value, curUrlPart]; } else { curUrlPart = t.value; } break; case "url.comma": if (!curUrlPart) { curUrlPart = []; } else if (!_.isArray(curUrlPart)) { curUrlPart = [curUrlPart]; } break; case "url.slash": ret.urlTokenPath.unshift(curUrlPart); curUrlPart = null; break; } t = editor.parser.prevNonEmptyToken(tokenIter); } if (curUrlPart) { ret.urlTokenPath.unshift(curUrlPart); } if (!ret.bodyTokenPath && !ret.urlParamsTokenPath) { if (ret.urlTokenPath.length > 0) { // started on the url, first token is current token ret.otherTokenValues = ret.urlTokenPath.splice(-1)[0]; } } else { // mark the url as completed. ret.urlTokenPath.push(url_pattern_matcher.URL_PATH_END_MARKER); } if (t && t.type == "method") { ret.method = t.value; } return ret; } var evaluateCurrentTokenAfterAChange = _.debounce(function evaluateCurrentTokenAfterAChange(pos) { var session = editor.getSession(); var currentToken = session.getTokenAt(pos.row, pos.column); if (!currentToken) { if (pos.row == 0) { LAST_EVALUATED_TOKEN = null; return; } currentToken = { start: 0, value: "" }; // empty row } currentToken.row = pos.row; // extend token with row. Ace doesn't supply it by default if (editor.parser.isEmptyToken(currentToken)) { // empty token. check what's coming next var nextToken = session.getTokenAt(pos.row, pos.column + 1); if (editor.parser.isEmptyToken(nextToken)) { // Empty line, or we're not on the edge of current token. Save the current position as base currentToken.start = pos.column; LAST_EVALUATED_TOKEN = currentToken; } else { nextToken.row = pos.row; LAST_EVALUATED_TOKEN = nextToken; } return; } if (!LAST_EVALUATED_TOKEN) { LAST_EVALUATED_TOKEN = currentToken; return; // wait for the next typing. } if (LAST_EVALUATED_TOKEN.start != currentToken.start || LAST_EVALUATED_TOKEN.row != currentToken.row || LAST_EVALUATED_TOKEN.value === currentToken.value) { // not on the same place or nothing changed, cache and wait for the next time LAST_EVALUATED_TOKEN = currentToken; return; } // don't automatically open the auto complete if some just hit enter (new line) or open a parentheses switch (currentToken.type || "UNKNOWN") { case "paren.lparen": case "paren.rparen": case "punctuation.colon": case "punctuation.comma": case "UNKOWN": return; } LAST_EVALUATED_TOKEN = currentToken; editor.execCommand("startAutocomplete"); }, 100); function editorChangeListener(e) { var cursor = editor.selection.lead; if (editor.__ace.completer && editor.__ace.completer.activated) { return; } evaluateCurrentTokenAfterAChange(cursor); } function addChangeListener() { editor.on("changeSelection", editorChangeListener); } function removeChangeListener() { editor.off("changeSelection", editorChangeListener) } function getCompletions(aceEditor, session, pos, prefix, callback) { try { var context = getAutoCompleteContext(editor, session, pos); if (!context) { callback(null, []); } else { var terms = _.map(context.autoCompleteSet, function (term) { if (typeof term !== "object") { term = { name: term } } else { term = _.clone(term); } return _.defaults(term, { value: term.name, meta: "API", score: 0, context: context, completer: { insertMatch: function () { applyTerm(term); } } }); }); terms.sort(function (t1, t2) { /* score sorts from high to low */ if (t1.score > t2.score) { return -1; } if (t1.score < t2.score) { return 1; } /* names sort from low to high */ if (t1.name < t2.name) { return -1; } if (t1.name === t2.name) { return 0; } return 1; }); callback(null, _.map(terms, function (t, i) { t.insert_value = t.insert_value || t.value; t.value = '' + t.value; // normalize to strings t.score = -i; return t; })); } } catch (e) { console.log("error while getting completion terms", e); callback(e, null); } } addChangeListener(); // Hook into Ace // disable standard context based autocompletion. ace.define('ace/autocomplete/text_completer', ['require', 'exports', 'module'], function (require, exports, module) { exports.getCompletions = function (editor, session, pos, prefix, callback) { callback(null, []); } }); var langTools = ace.require('ace/ext/language_tools'); var aceUtils = ace.require('ace/autocomplete/util'); var aceAutoComplete = ace.require('ace/autocomplete'); langTools.addCompleter({ getCompletions: getCompletions }); editor.setOptions({ enableBasicAutocompletion: true }); // Ace doesn't care about tokenization when calculating prefix. It will thus stop on . in keys names. // we patch this behavior. // CHECK ON ACE UPDATE var aceAutoCompleteInstance = new aceAutoComplete.Autocomplete(); aceAutoCompleteInstance.autoInsert = false; aceAutoCompleteInstance.gatherCompletions = function (ace_editor, callback) { var session = ace_editor.getSession(); var pos = ace_editor.getCursorPosition(); var prefix = ""; // change starts here var token = session.getTokenAt(pos.row, pos.column); this.base = _.clone(pos); if (!editor.parser.isEmptyToken(token) && !isSeparatorToken(token)) { if (token.value.indexOf('"') == 0) { this.base.column = token.start + 1; } else { this.base.column = token.start; } prefix = getAutoCompleteValueFromToken(token); } var matches = []; aceUtils.parForEach(ace_editor.completers, function (completer, next) { completer.getCompletions(ace_editor, session, pos, prefix, function (err, results) { if (!err) { matches = matches.concat(results); } next(); }); }, function () { callback(null, { prefix: prefix, matches: matches }); }); return true; }; editor.__ace.completer = aceAutoCompleteInstance; return { _test: { getCompletions: getCompletions, addReplacementInfoToContext: addReplacementInfoToContext, addChangeListener: addChangeListener, removeChangeListener: removeChangeListener } } };
let history = require('./history'); let kb = require('./kb'); let mappings = require('./mappings'); let ace = require('ace'); let utils = require('./utils'); let autocomplete_engine = require('./autocomplete/engine'); let url_pattern_matcher = require('./autocomplete/url_pattern_matcher'); let _ = require('lodash'); let ext_lang_tools = require('ace/ext-language_tools'); var AceRange = ace.require('ace/range').Range; var LAST_EVALUATED_TOKEN = null; module.exports = function (editor) { function isSeparatorToken(token) { switch ((token || {}).type) { case "url.slash": case "url.comma": case "url.questionmark": case "paren.lparen": case "paren.rparen": case "punctuation.colon": case "punctuation.comma": case "whitespace": return true; default: // standing on white space, quotes or another punctuation - no replacing return false; }
let ace = require('ace'); let $ = require('jquery'); let settings = require('./settings'); let OutputMode = require('./sense_editor/mode/output'); var $el = $("#output"); var output = ace.require('ace/ace').edit($el[0]); var outputMode = new OutputMode.Mode(); output.update = function (val, mode, cb) { if (typeof mode === 'function') { cb = mode; mode = void 0; } var session = output.getSession(); session.setMode(val ? (mode || outputMode) : 'ace/mode/text'); session.setValue(val); if (typeof cb === 'function') { setTimeout(cb); } }; output.append = function (val, fold_previous, cb) { if (typeof fold_previous === 'function') { cb = fold_previous; fold_previous = true; } if (_.isUndefined(fold_previous)) {
export function initializeOutput($el) { output = ace.require('ace/ace').edit($el[0]); var outputMode = new OutputMode.Mode(); output.resize = smartResize(output); output.update = function (val, mode, cb) { if (typeof mode === 'function') { cb = mode; mode = void 0; } var session = output.getSession(); session.setMode(val ? (mode || outputMode) : 'ace/mode/text'); session.setValue(val); if (typeof cb === 'function') { setTimeout(cb); } }; output.append = function (val, fold_previous, cb) { if (typeof fold_previous === 'function') { cb = fold_previous; fold_previous = true; } if (_.isUndefined(fold_previous)) { fold_previous = true; } var session = output.getSession(); var lastLine = session.getLength(); if (fold_previous) { output.moveCursorTo(Math.max(0, lastLine - 1), 0); session.toggleFold(false); } session.insert({ row: lastLine, column: 0 }, "\n" + val); output.moveCursorTo(lastLine + 1, 0); if (typeof cb === 'function') { setTimeout(cb); } }; output.$el = $el; (function (session) { session.setMode("ace/mode/text"); session.setFoldStyle('markbeginend'); session.setTabSize(2); session.setUseWrapMode(true); }(output.getSession())); output.setShowPrintMargin(false); output.setReadOnly(true); if (settings) { settings.applyCurrentSettings(output); } return output; }
editor.iterForPosition = function (row, column) { return new (ace.require("ace/token_iterator").TokenIterator)(editor.getSession(), row, column); };
let ace = require('ace'); require('ace/mode-json'); let x_json = require('./x_json_highlight_rules'); var oop = ace.require("ace/lib/oop"); var JsonHighlightRules = ace.require("ace/mode/json_highlight_rules").JsonHighlightRules; var OutputJsonHighlightRules = function () { this.$rules = {}; x_json.addToRules(this, 'start'); this.$rules.start.unshift( { "token": "warning", "regex": "#!.*$" }, { "token": "comment", "regex": "#.*$" } ); if (this.constructor === OutputJsonHighlightRules) { this.normalizeRules(); } }; oop.inherits(OutputJsonHighlightRules, JsonHighlightRules);
let ace = require('ace'); let x_json = require('./x_json_highlight_rules'); var oop = ace.require("ace/lib/oop"); var TextHighlightRules = ace.require("ace/mode/text_highlight_rules").TextHighlightRules; var InputHighlightRules = function () { function mergeTokens(/* ... */) { return [].concat.apply([], arguments); } function addEOL(tokens, reg, nextIfEOL, normalNext) { if (typeof reg == "object") { reg = reg.source; } return [ { token: tokens.concat(["whitespace"]), regex: reg + "(\\s*)$", next: nextIfEOL }, { token: tokens, regex: reg, next: normalNext } ]; } // regexp must not have capturing parentheses. Use (?:) instead. // regexps are ordered -> the first match is used /*jshint -W015 */ this.$rules = { "start": mergeTokens([ { "token": "warning", "regex": "#!.*$" }, { token: "comment", regex: /^#.*$/ }, { token: "paren.lparen", regex: "{", next: "json", push: true } ],
let ace = require('ace'); let acequire = require('acequire'); let mode_json = require('ace/mode-json'); let output_highlighting_rules = require('./output_highlight_rules'); var oop = ace.require("ace/lib/oop"); var JSONMode = ace.require("ace/mode/json").Mode; var HighlightRules = require("./output_highlight_rules").OutputJsonHighlightRules; var MatchingBraceOutdent = ace.require("ace/mode/matching_brace_outdent").MatchingBraceOutdent; var CstyleBehaviour = ace.require("ace/mode/behaviour/cstyle").CstyleBehaviour; var CStyleFoldMode = ace.require("ace/mode/folding/cstyle").FoldMode; var WorkerClient = ace.require("ace/worker/worker_client").WorkerClient; var AceTokenizer = ace.require("ace/tokenizer").Tokenizer; var Mode = function () { this.$tokenizer = new AceTokenizer(new HighlightRules().getRules()); this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); this.foldingRules = new CStyleFoldMode(); }; oop.inherits(Mode, JSONMode); (function () { this.createWorker = function (session) { return null; }; this.$id = "sense/mode/input"; }).call(Mode.prototype);
import ace from 'ace'; import 'ace/ext-modelist'; const modelist = ace.require('ace/ext/modelist'); export function getEditorMode(name) { return modelist.getModeForPath(name).name; }
let ace = require('ace'); let es = require('../../src/es'); import { initializeInput } from '../../src/input'; let editor_input1 = require('raw!./editor_input1.txt'); let utils = require('../../src/utils'); var aceRange = ace.require("ace/range"); var { test, module, ok, fail, asyncTest, deepEqual, equal, start } = QUnit; let input; module("Editor", { setup: function () { input = initializeInput($('#editor'), $('#editor_actions'), $('#copy_as_curl'), null); input.$el.show(); input.autocomplete._test.removeChangeListener(); }, teardown: function () { input.$el.hide(); input.autocomplete._test.addChangeListener(); } }); var testCount = 0; function utils_test(name, prefix, data, test) { var id = testCount++; if (typeof data == "function") { test = data; data = null; }