Files
FOF-ACE-Editor/lib/ace/src-noconflict/ext-tern.js
2025-08-16 16:14:03 +08:00

1580 lines
50 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: Zh_Strong
* @Date: 2022-11-07 16:55:18
* @LastEditTime: 2025-07-15 15:45:12
* @LastEditors: Qiang 1841747216@qq.com
* @Description: Zh_Strong
* @FilePath: \view\lib\ace\src-noconflict\ext-tern.js
*/
ace.define("ace/ext/tern", ["require", "exports", "module", "ace/range", "ace/lib/dom", "ace/lib/lang", "ace/config"], function (require, exports, module) {
"use strict";
var dom = require("ace/lib/dom");
var lang = require("../lib/lang");
var config = require("../config");
dom.importCssString(".Ace-Tern-tooltip { border: 1px solid silver; border-radius: 3px; padding: 5px 10px; padding-right:15px; color:#444; font-weight: bold; background-color: white; white-space: pre-wrap; max-width: 50em; max-height:30em; overflow-y:auto; position: absolute; z-index: 10; -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); transition: opacity 1s; -moz-transition: opacity 1s; -webkit-transition: opacity 1s; -o-transition: opacity 1s; -ms-transition: opacity 1s; } .Ace-Tern-tooltip-boxclose { position:absolute; top:0; right:3px; color:red; } .Ace-Tern-tooltip-boxclose:hover { background-color:yellow; } .Ace-Tern-tooltip-boxclose:before { content:'×'; cursor:pointer; font-weight:bold; font-size:larger; } .Ace-Tern-completion { padding-left: 12px; position: relative; } .Ace-Tern-completion:before { position: absolute; left: 0; bottom: 0; border-radius: 50%; font-weight: bold; height: 13px; width: 13px; font-size:11px; line-height: 14px; text-align: center; color: white; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } .Ace-Tern-completion-unknown:before { content:'?'; background: #4bb; } .Ace-Tern-completion-object:before { content:'O'; background: #77c; } .Ace-Tern-completion-fn:before { content:'F'; background: #7c7; } .Ace-Tern-completion-array:before { content:'A'; background: #c66; } .Ace-Tern-completion-number:before { content:'1'; background: #999; } .Ace-Tern-completion-string:before { content:'S'; background: #999; } .Ace-Tern-completion-bool:before { content:'B'; background: #999; } .Ace-Tern-completion-guess { color: #999; } .Ace-Tern-hint-doc { max-width: 35em; } .Ace-Tern-fhint-guess { opacity: .7; } .Ace-Tern-fname { color: black; } .Ace-Tern-farg { color: #70a; font-size: smaller; } .Ace-Tern-farg-current { color: #70a; font-weight:bold; font-size:larger; text-decoration:underline; } .Ace-Tern-farg-current-description { margin-top:5px; font-weight: normal; } .Ace-Tern-farg-current-name { font-weight:bold; } .Ace-Tern-type { color: #07c; font-size:smaller; } .Ace-Tern-jsdoc-tag { color: #B93A38; text-transform: lowercase; font-size:smaller; font-weight:600; } .Ace-Tern-jsdoc-param-wrapper{ /*background-color: #FFFFE3; padding:3px;*/ } .ace-tip-info{ white-space: pre-line; line-height: 1.8; } .Ace-Tern-jsdoc-tag-param-child{ display:inline-block; } .Ace-Tern-jsdoc-param-optionalWrapper { } .Ace-Tern-jsdoc-param-optionalBracket { color:grey; } .Ace-Tern-jsdoc-param-name { color: #70a; font-weight:bold; } .Ace-Tern-jsdoc-param-defaultValue { font-size: smaller;} .Ace-Tern-jsdoc-param-description { color:black; } .Ace-Tern-typeHeader-simple{ font-size:smaller; font-weight:bold; display:block; margin-bottom:3px; color:grey; } .Ace-Tern-typeHeader{ display:block; margin-bottom:3px; } .Ace-Tern-tooltip-link{font-size:smaller; color:blue;}", "ace_tern");
// 主线程
const worker = new Worker('/lib/ace/src-noconflict/worker-tern.js');
// 同步变量
let CODE_TYPE_WORKER, EDIT_DOC_WORKER, LAY_ID_WORKER;
worker.postMessage({
action: 'syncvar',
config: {
name: "host",
data: window.location.host
}
});
// 错误提示
function showError(editor, error) {
// console.error(editor, error);
}
// 拆解键值 JSON类|JSON
function splitLang(data) {
if (Object.prototype.toString.call(data) === '[object Object]') {
for (const key in data) {
data[key] = splitLang(data[key]);
if (/\|/.test(key)) {
let arr = key.split("|");
arr.forEach((name, index) => {
data[name] = {
...data[key],
"!translated": index ? arr[0] : arr[1]
};
})
delete data[key]
}
}
};
return data;
}
// 分析器
let requestId = 0;
let callbackArr = {};
var TernServer = function (options) {
let self = this;
this.options = options || {};
let plugins = this.options.plugins || (this.options.plugins = {});
if (!plugins.hasOwnProperty('doc_comment')) {
plugins.doc_comment = {}
};
if (!plugins.doc_comment.hasOwnProperty('fullDocs')) {
plugins.doc_comment.fullDocs = true
};
if (!this.options.hasOwnProperty('defs')) {
this.options.defs = ['browser', "ecmascript"];
}
// 绑定解析器服务
worker.postMessage({
action: 'init',
config: {
async: true,
defs: this.options.defs,
plugins: this.options.plugins
}
});
// js的标准文件
if (this.options.defs && this.options.defs.length > 0) {
this.options.defs.forEach(async v => {
this.addDefs("lib/tern/defs/" + v + ".json")
});
}
worker.onmessage = function (event) {
const {
id,
error,
data
} = event.data;
// 利用分析结果更新编辑器状态
if (id && callbackArr["callback" + id]) {
callbackArr["callback" + id](error, data);
delete callbackArr["callback" + id];
};
if (id && id == "addDefsError") {
// layer.open({
// title: "分析器加载错误",
// area: "500px",
// content: "加载支持库分析模块出现错误,错误原因如下:<br>" + error
// })
}
};
worker.onerror = function (error) {
console.error('海燕分析器错误:', error.message);
};
// 设置代码文本为空对象(绝对空对象---没有原型)
this.docs = Object.create(null);
// 文本改变
this.trackChange = function (change, doc) {
trackChange(self, doc, change);
};
// 分析器的提示代码
this.aceTextCompletor = null;
// 分析器的防抖节流变量
this.lastAutoCompleteFireTime = null;
// 防抖时间
this.queryTimeout = 3000;
// 配置参数的防抖时间,进行转换数值型
if (this.options.queryTimeout && !isNaN(parseInt(this.options.queryTimeout))) {
this.queryTimeout = parseInt(this.options.queryTimeout)
};
};
var Pos = function (line, ch) {
return {
"line": line,
"ch": ch
};
};
var cls = "Ace-Tern-";
var bigDoc = 250;
var debugCompletions = false;
var requireIds = [];
TernServer.prototype = {
// 添加文档,上下文关联提示器
addDoc: async function (name, doc) {
var data = {
doc: doc.session || doc,
name: name,
changed: null
};
var value = '';
if (doc.constructor.name === 'String') {
value = doc;
} else {
value = docValue(this, data);
doc.on("change", this.trackChange);
}
// 提示关联视图添加文件
worker.postMessage({
action: 'addFile',
config: {
name: name,
value: value
}
});
return this.docs[name] = data;
},
// 删除文档
delDoc: async function (name) {
var found = this.docs[name];
if (!found) return;
try {
found.doc.off("change", this.trackChange);
} catch (ex) { }
delete this.docs[name];
worker.postMessage({
action: 'delFile',
config: {
name: name
}
});
},
// 添加def文件
addDefs: async function (def, after = false) {
worker.postMessage({
action: 'addDefs',
config: {
def,
after
}
});
},
// 删除def文件
deleteDefs: async function (name) {
worker.postMessage({
action: 'deleteDefs',
config: {
name
}
});
},
/**
* 请求分析器 目前类型:
* completions 提示器代码
* type 当前值类型
* definition 当前定义类型
* documentation 当前文档
* refs 当前变量的引用
* rename 变量重命名
* properties 所有属性
* files 分析服务器的文件
*
*/
request: function (editor, query, callback, pos, forcePushChangedfile) {
var self = this;
var id;
if (editor.file && editor.file.id) {
id = editor.file.id
}
var doc = findDoc(this, editor, id);
var request = buildRequest(this, doc, query, pos, forcePushChangedfile);
requestId++;
callbackArr["callback" + requestId] = callback;
worker.postMessage({
action: 'request',
id: requestId,
config: {
request
}
});
},
// 获取代码提示
getCompletions: function (editor, session, pos, prefix, callback) {
getCompletions(this, editor, session, pos, prefix, callback);
},
// 获取当前值类型
getTypeAt: function (editor = EDITOR, prefix = '', callback = null) {
this.request(editor, {
type: "type",
types: true,
origins: true,
docs: true,
urls: true,
prefix: prefix
}, function (error, data) {
callback && callback(data);
if (error) return showError(editor, error);
});
},
// 更新参数值介绍
updateArgHints: function (editor = EDITOR) {
updateArgHints(this, editor);
},
// 获取当前页面变量、函数
getoutline: function (editor, fileid, callback) {
this.request(editor, {
type: "outline",
file: fileid,
lineCharPositions: true,
needfile: [fileid]
}, function (error, data) {
// 赋值
callback(data ? data.outline : []);
});
},
// 生成提示代码
createInfoDataTip: function (data = '') {
return createInfoDataTip(data);
},
// 获取项目变量
// 获取项目变量
getAllFileVar: function () {
return new Promise((resolve, reject) => {
let files = [];
let num = 0;
// 获取项目缓存
if (!window.files_snippets) {
window.files_snippets = JSON.parse(GetFilesFunctionCache("filesFunction") || "{}");
}
const cacheFlieIds = Object.keys(files_snippets); // 获取所有页面代码数据(每次都要重新运行,项目文件可能会更改)
function getAllFileFunction(fileJson = []) {
(fileJson.length > 0) && fileJson.forEach(v => {
let titleArr = v.title.split(".");
let type = titleArr[titleArr.length - 1];
if (['lhtml', 'lcss', 'ljs'].includes(type)) {
if (ALL_FILE_SEARCH.includes(v.id) || !cacheFlieIds.includes(v.id)) {
files.push({
"id": v.id,
"title": v.title,
"mode": v.type,
"href": v.href,
"content": FILE.getFile(v.href)
})
ALL_FILE_SEARCH.push(v.id)
};
}
if (v.children) {
getAllFileFunction(v.children);
}
})
}
getAllFileFunction(DirectoryTreeJson);
function getSnippet(data = [], file, p_name = '', p_type = '') {
let snippetData = [];
data.forEach(v => {
let type = stringToType(v.type);
snippetData.push({
title: v.title,
snippet: v.title,
p_snippet: p_name,
page_id: file.id,
type: type,
// start: v.start,
// end: v.end,
// id: v.id,
tabTrigger: file.id,
is_user: v.isUser
});
if (v.children) {
snippetData = [...snippetData, ...getSnippet(v.children, file, p_name ? p_name + "." + v.title : v.title, type)]
};
})
if (snippetData.length > 0) {
let uniqueArr = snippetData.reduce((map, item) => {
const key = `${item.title}-${item.type}`; // 创建一个组合键
if (!map.has(key)) {
map.set(key, item);
}
return map;
}, new Map()).values();
snippetData = Array.from(uniqueArr);
}
return snippetData;
}
// 获取全部提示
if (files.length === 0) {
resolve(ALL_FILE_SEARCH_VAR);
return;
}
files.forEach(file => {
if (!this.docs[file.id] || this.docs[file.id].doc) {
if (!TAB["tab-" + file.id]) {
TAB['tab-' + file.id] = new EditSession(file.content, "ace/mode/" + file.mode);
TAB['tab-' + file.id]["file"] = {
id: file["id"],
title: file["title"],
href: file["href"],
content: file.content,
mode: file["mode"],
};
}
this.addDoc(file.id, TAB["tab-" + file.id])
}
num++;
this.getoutline(this.docs[file.id].doc, this.docs[file.id].name, function (data) {
window.files_snippets[file.id] = Array.from(new Set(getSnippet(data, file)));
num--;
if (num == 0) {
ALL_FILE_SEARCH_VAR = [];
for (const id in files_snippets) {
ALL_FILE_SEARCH_VAR = ALL_FILE_SEARCH_VAR.concat(files_snippets[id])
}
resolve(ALL_FILE_SEARCH_VAR);
ALL_FILE_SEARCH = [];
SetFilesFunctionCache("filesFunction", JSON.stringify(files_snippets))
}
})
})
});
},
// 重置海鸥服务
reServer: function () {
var plugins = {
...this.options.plugins || (this.options.plugins = {})
};
// 桌面端需要导入导出
if (!plugins.hasOwnProperty('es_modules')) plugins.es_modules = {};
if (!plugins.hasOwnProperty('modules')) plugins.modules = {};
worker.postMessage({
action: 'init',
config: {
async: true,
defs: this.options.defs,
plugins: this.options.plugins
}
});
}
};
// 获取文档
function docValue(ts, doc, query) {
let val
if (doc?.getValue) {
val = JSON.parse(JSON.stringify(doc.doc.getValue()));
} else if (doc?.doc?.getValue) {
val = JSON.parse(JSON.stringify(doc.doc.getValue()));
} else {
return "";
}
requireIds = [];
if (ts.options.fileFilter) {
val = ts.options.fileFilter(val, doc.name, doc.doc)
};
// 对应光标位置设置标识(行数不会变)
try {
if (query && query.type == "completions") {
let end = query.end;
let lines = val.split('\n');
let line = lines[end["line"]];
lines[end["line"]] = line.slice(0, end["ch"]) + '${fof#光标位置#fof}' + line.slice(end["ch"]);
val = lines.join('\n');
}
} catch (error) {
}
// TODO @类型转换
val = val.replace(/[\u4E00-\u9FA5A-Za-z0-9_]+@\(([\S\s]+?)\)/g, ($1, $2) => {
return createType($2);
});
// 更改set局域
val = val.replace(/set\s+/g, "");
// 引用,导出
val = val.replace(/(exports|导出模块)\./g, "导出命令 常量 ");
val = val.replace(/(const|常量)\s+([\S\s]+?)=\s*(require|导入模块)\(([\S\s]+?)\)/g, ($1, $2, $3, $4, $5) => {
let id = getFileID($5);
(requireIds.findIndex(rid => rid == id) == -1) && requireIds.push(id);
if (id === $5.replace(/"/g, "")) {
return `import ${$3} from "${id}"`;
} else {
return `import ${$3} from "./${id}"`;
}
});
// 兼容异步函数无法提示-2024-2-29更新
val = val.replace(/(?<=^|\s|;)(异步)(?=\s|$)/g, ";");
// 获取标识重新设置光标位置
try {
if (query && query.type == "completions") {
let end = query.end;
let lines = val.split('\n');
let line = lines[end["line"]];
query.end.ch = line.indexOf("${fof#光标位置#fof}");
val = val.replace("${fof#光标位置#fof}", "")
}
} catch (error) {
}
return val;
}
// 新建类型
function createType(type) {
return `${type}.原型`;
}
// 改变坐标格式
function toTernLoc(pos) {
if (typeof (pos.row) !== 'undefined') {
return {
line: pos.row,
ch: pos.column
};
}
return pos;
}
// 改变坐标格式
function toAceLoc(pos) {
if (pos.line) {
return {
row: pos.line,
column: pos.ch
};
}
return pos;
}
// 查找文档
function findDoc(ts, doc, name) {
for (var n in ts.docs) {
var cur = ts.docs[n];
// if (cur.doc == doc) return cur;
if (cur.doc?.id == doc?.session?.id) {
return cur;
}
}
// 没有名称则默认生成名称 docdoc1,doc2...
if (!name) {
for (var i = 0; ; ++i) {
n = "[页面" + (i || "") + "]";
if (!ts.docs[n]) {
name = n;
break;
}
}
};
return ts.addDoc(name, doc);
}
// 文件修改
function trackChange(ts, doc, change) {
var _change = {};
_change.from = toTernLoc(change.start);
_change.to = toTernLoc(change.end);
_change.text = change.lines;
var data = findDoc(ts, doc);
var argHints = ts.cachedArgHints;
if (argHints && argHints.doc == doc && cmpPos(argHints.start, _change.to) <= 0) {
ts.cachedArgHints = null;
}
var changed = data.changed; //data is the tern server doc, which keeps a changed property, which is null here
if (changed === null) {
data.changed = changed = {
from: _change.from.line,
to: _change.from.line
};
}
var end = _change.from.line + (_change.text.length - 1);
if (changed.to && _change.from.line < changed.to) {
changed.to = changed.to - (_change.to.line - end);
}
if (changed?.to && end >= changed.to) {
changed.to = end + 1;
}
if (changed?.from && changed.from > _change.from.line) {
changed.from = changed.from.line;
}
}
// 生成请求
function buildRequest(ts, doc, query, pos, forcePushChangedfile) {
var files = [],
offsetLines = 0,
allowFragments = !query.fullDocs;
if (!allowFragments) delete query.fullDocs;
if (typeof query == "string") query = {
type: query
};
query.lineCharPositions = true;
if (query.end == null) {
try {
query.end = toTernLoc(pos || (doc.doc.selection.getCursor ? doc.doc.selection.getCursor() : doc.selection.getCursor()));
} catch (error) {
query.end = toTernLoc(0);
}
}
var startPos = query.start || query.end;
if (!forcePushChangedfile && doc.doc && doc.doc.session && doc.doc.session.getLength() > bigDoc && allowFragments !== false &&
doc.changed.to - doc.changed.from < 100 &&
doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
files.push(getFragmentAround(doc, startPos, query.end));
query.file = "#0";
var offsetLines = files[0].offsetLines;
if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
query.end = Pos(query.end.line - offsetLines, query.end.ch);
} else {
if(!doc.name){
doc.name = "[页面1]"
}
files.push({
type: "full",
name: doc.name,
text: docValue(ts, doc, query)
});
query.file = doc.name;
doc.changed = null;
}
for (var name in ts.docs) {
var cur = ts.docs[name];
if (cur.changed && cur != doc) {
files.push({
type: "full",
name: cur.name,
text: docValue(ts, cur, query)
});
cur.changed = null;
}
};
if (query.prefix && query.type == "completions" && /\./g.test(query.prefix)) {
if ((SnippetManager.getActiveScopes(EDITOR) || ["html"])[0] == "html") {
files[0].text += `\n${query.prefix}`;
query.end = {
line: files[0].text.split('\n').length - 1,
ch: query.prefix.length
}
}
};
return {
query: query,
files: files
};
}
function getFragmentAround(data, start, end) {
var editor = data.doc;
var minIndent = null,
minLine = null,
endLine,
tabSize = editor.session.$tabSize;
for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
var line = editor.session.getLine(p),
fn = line.search(/\bfunction\b/);
if (fn < 0) continue;
var indent = countColumn(line, null, tabSize);
if (minIndent != null && minIndent <= indent) continue;
minIndent = indent;
minLine = p;
}
if (minLine == null) minLine = min;
var max = Math.min(editor.session.getLength() - 1, end.line + 20);
if (minIndent == null || minIndent == countColumn(editor.session.getLine(start.line), null, tabSize)) endLine = max;
else
for (endLine = end.line + 1; endLine < max; ++endLine) {
var indent = countColumn(editor.session.getLine(endLine), null, tabSize);
if (indent <= minIndent) break;
}
var from = Pos(minLine, 0);
return {
type: "part",
name: data.name,
offsetLines: from.line,
text: editor.session.getTextRange({
start: toAceLoc(from),
end: toAceLoc(Pos(endLine, 0))
})
};
}
function countColumn(string, end, tabSize, startIndex, startValue) {
if (end == null) {
end = string.search(/[^\s\u00a0]/);
if (end == -1) end = string.length;
}
for (var i = startIndex || 0, n = startValue || 0; i < end; ++i) {
if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
else ++n;
}
return n;
}
// 获取提示器
function getCompletions(ts, editor, session, pos, prefix, callback) {
var autoCompleteFiredTwiceInThreshold = function () {
try {
var t = ts.lastAutoCompleteFireTime;
if (!t) {
return false;
}
var msPassed = new Date().getTime() - t;
if (msPassed < 1000) { //less than 1 second
return true;
}
} catch (ex) {
showError({
msg: 'autoCompleteFiredTwiceInThreshold',
err: ex
});
}
return false;
};
var forceEnableAceTextCompletor = autoCompleteFiredTwiceInThreshold();
if (!forceEnableAceTextCompletor) {
var t = getCurrentToken(editor);
if (t && t.type && t.type.indexOf('comment') !== -1) forceEnableAceTextCompletor = true;
}
var groupName = '';
if (debugCompletions) {
groupName = Math.random().toString(36).slice(2);
//console.group(groupName);
//console.time('get completions from tern server');
}
// 请求分析提示对应代码
ts.request(editor, {
type: "completions",
types: true,
urls: true,
origins: true,
docs: true,
filter: false,
omitObjectPrototype: false, // 隐藏prototype
sort: false,
includeKeywords: true,
guess: true,
expandWordForward: true,
prefix: prefix,
pos: pos
},
function (error, data) {
if (debugCompletions) console.timeEnd('get completions from tern server');
if (error) {
callback(error, data)
return showError(ts, editor, error);
}
callback(null, data.completions.map(function (item) {
// let isClassName = class_code.includes(item.name);
// let isClassName_other = false;
// if (item.class) {
// isClassName_other = class_code.includes(item.class)
// }
let caption = item.name;
if (/[\u4E00-\u9FA5]/g.test(caption)) {
caption = pinyin_transliteration(item.name);
if (item.translated) {
caption += "|" + item.translated
}
}
if (item.end && pos.row === item.end.line && pos.column === item.end.ch) {
return null;
}
let value_suffix = '';
if (/^fn\(/.test(item.type) /*&& !isClassName&& !isClassName_other*/) {
value_suffix = "()"
};
return {
//iconClass: " " + (item.guess ? cls + "guess" : typeToIcon(item.type)), // 图标
iconClass: " " + (item.guess ? typeToIcon("?") : typeToIcon(item.type)),
description: item.doc, // 解释
type: (item.type === "?") ? item.name : item.type, // 类型
caption: caption, // 筛选名称
title: item.name,
title_en: item.translated,
explain: item.explain,
parameter: item.parameter,
value: item.value || item.name + value_suffix, // 值
score: 99999, // 排序
page_id: item.origin, // 页面id
overall: item.overall || false,
meta: item.origin ? item.origin.replace(/^.*[\\\/]/, '') : '', // 提示类型
other: item.origin ? 1 : 0,
pt: item.pt || ""
};
}));
if (debugCompletions) console.time('get and merge other completions');
});
}
// 生成类型图标
function typeToIcon(type) {
var suffix;
if (type == "?") suffix = "unknown";
else if (type == "number" || type == "string" || type == "bool") suffix = type;
else if (/^fn\(/.test(type)) suffix = "fn";
else if (/^\[/.test(type)) suffix = "array";
else suffix = "object";
return cls + "completion " + cls + "completion-" + suffix;
};
var popupSelectBound = false;
// 转真实类型
function stringToType(type) {
var suffix;
if (type == "?") suffix = "未知";
else if (type == "number" || type == "string" || type == "bool") suffix = type;
else if (/^fn\(/.test(type)) suffix = "function";
else if (/^\[/.test(type)) suffix = "array";
else suffix = "object";
return suffix;
}
// 弹出对应的提示
var debounce_updateArgHints; // 防抖
function updateArgHints(ts, editor) {
clearTimeout(debounce_updateArgHints);
var callPos = getCallPos(editor);
if (!callPos) {
return;
}
var start = callPos.start;
var argpos = callPos.argpos;
var cache = ts.cachedArgHints;
if (cache && cache.doc == editor && cmpPos(start, cache.start) === 0) {
if (window.isCloseArgHints) {
return;
}
var line = editor.session.getLine(cache.start["line"]);
var name = "";
for (let index = cache.start["ch"] - 1; index >= 0; index--) {
if (!/\s/.test(line[index])) {
name = line[index] + name;
} else {
break;
}
}
if (name === cache.name) {
if (cache?.argpos == argpos) {
return;
}
return showArgHints(ts, editor, argpos);
}
} else {
window.isCloseArgHints = false;
};
debounce_updateArgHints = setTimeout(inner, 300);
function inner() {
ts.request(editor, {
type: "type",
types: true,
origins: true,
docs: true,
urls: true,
end: start,
preferFunction: true,
}, function (error, data) {
if (error) {
if (error.toString().toLowerCase().indexOf('no expression at') === -1 && error.toString().toLowerCase().indexOf('no type found at') === -1) {
return showError(editor, error);
}
}
if (error || !data.type || !(/^fn\(/).test(data.type)) {
return;
};
if (cache && [data?.exprName, data?.name].includes(cache.name)) {
if (cache?.argpos == argpos) {
return;
}
showArgHints(ts, editor, argpos);
return;
}
let view = null;
if (ExeFun_SelectJSTextIf(data.name)) {
view = JSON.parse(ExeFun_SelectJSTextData(data.name))
} else {
let lib_data = tree.getData("librarys", data.exprName || data.name)
if (lib_data.length > 0) {
let 参数信息 = [];
if (lib_data[0]["parameter"].length > 0) {
lib_data[0]["parameter"].forEach(参数 => {
参数信息.push({
"内部解释": "是否可空【1代表可空2代表必须输入】-是否扩展参数【1代表可扩展参数2代表不可扩展参数】",
"参数类型": 参数["Class"],
"名称": 参数["title"],
"描述": 参数["usage"],
"排序": 参数["int"]
})
})
}
view = {
"type": "9",
"三方命令": 1,
"中文名称": lib_data[0]["title"],
"中文命令示例": lib_data[0]["body"],
"内部注意信息": "浏览器1支持0不支持",
"参数信息": JSON.stringify(参数信息),
"命令类型": lib_data[0]["CodeType"],
"描述信息": `<p>${lib_data[0]["usage"]}</p>`,
"返回值描述": lib_data[0]["ReturnText"],
"返回值类型": lib_data[0]["ReturnClass"]
}
}
}
ts.cachedArgHints = {
start: start,
type: parseFnType(data.type),
name: data.exprName || data.name || "fn",
guess: data.guess,
doc: editor,
comments: data.doc,
view: view,
argpos: argpos
};
showArgHints(ts, editor, argpos);
});
}
}
function parseFnType(text) {
if (text.substring(0, 2) !== 'fn') return null;
if (text.indexOf('(') === -1) return null;
var args = [],
pos = 3;
function skipMatching(upto) {
var depth = 0,
start = pos;
for (; ;) {
var next = text.charAt(pos);
if (upto.test(next) && !depth) return text.slice(start, pos);
if (/[{\[\(]/.test(next)) ++depth;
else if (/[}\]\)]/.test(next)) --depth;
++pos;
}
}
if (text.charAt(pos) != ")")
for (; ;) {
var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
if (name) {
pos += name[0].length;
name = name[1];
}
args.push({
name: name,
type: skipMatching(/[\),]/)
});
if (text.charAt(pos) == ")") break;
pos += 2;
}
var rettype = text.slice(pos).match(/^\) -> (.*)$/);
return {
args: args,
rettype: rettype && rettype[1]
};
}
function getCurrentToken(editor) {
try {
var pos = editor.getSelectionRange().end;
return editor.session.getTokenAt(pos.row, pos.column);
} catch (ex) {
showError(ts, editor, ex);
}
}
// 获取调用位置
function getCallPos(editor, pos) {
var start = {};
var currentPosistion = pos || editor.getSelectionRange().start; //{row,column}
currentPosistion = toAceLoc(currentPosistion); //just in case
var currentLine = currentPosistion.row;
var currentCol = currentPosistion.column;
// var firstLineToCheck = Math.max(0, currentLine - 6);
var firstLineToCheck = 0;
var ch = '';
var depth = 0;
var commas = [];
for (var row = currentLine; row >= firstLineToCheck; row--) {
var thisRow = editor.session.getLine(row);
if (row === currentLine) {
thisRow = thisRow.substr(0, currentCol);
}
for (var col = thisRow.length; col >= 0; col--) {
ch = thisRow.substr(col, 1);
if (ch === '}' || ch === ')' || ch === ']') {
depth += 1;
} else if (ch === '{' || ch === '(' || ch === '[') {
if (depth > 0) {
depth -= 1;
} else if (ch === '(') {
var upToParen = thisRow.substr(0, col);
if (!upToParen.length) {
break;
}
if (upToParen.substr(upToParen.length - 1) === ' ') {
break;
}
var wordBeforeFnName = upToParen.split(' ').reverse()[1];
if (wordBeforeFnName && wordBeforeFnName.toLowerCase() === 'function') {
break;
}
if (wordBeforeFnName && wordBeforeFnName.toLowerCase() === '定义函数') {
break;
}
var token = editor.session.getTokenAt(row, col);
if (token) {
if (token.type.toString().indexOf('comment') !== -1 || token.type === 'keyword' || token.type === 'storage.type') {
break;
}
}
start = {
line: row,
ch: col
};
break;
} else {
break;
}
}
}
if (start.hasOwnProperty('line')) {
break;
}
}
if (!start.hasOwnProperty('line')) return; //start not found
depth = 0;
for (var row = start["line"]; row <= currentLine; row++) {
var thisRow = editor.session.getLine(row);
if (row === currentLine) {
thisRow = thisRow.substr(0, currentCol);
}
for (var col = 0; col <= thisRow.length; col++) {
ch = thisRow.substr(col, 1);
if (ch === '}' || ch === ')' || ch === ']') {
depth -= 1;
} else if (ch === '{' || ch === '(' || ch === '[') {
depth += 1;
} else if (ch === ',' && depth === 1) {
commas.push({
line: row,
ch: col
});
}
}
}
var argpos = 0;
for (var i = 0; i < commas.length; i++) {
var p = commas[i];
if ((p.line === start.line && p.ch > start.ch) || (p.line > start.line)) {
argpos += 1;
}
}
return {
start: toTernLoc(start),
"argpos": argpos
};
}
function cmpPos(a, b) {
a = toTernLoc(a);
b = toTernLoc(b);
return a.line - b.line || a.ch - b.ch;
}
function showArgHints(ts, editor, pos) {
var cache = ts.cachedArgHints;
// var place = getCusorPosForTooltip(editor);
if (!cache.hasOwnProperty('params')) {
if (!cache.comments) {
cache.params = null;
} else {
var params = parseJsDocParams(cache.comments);
if (!params || params.length === 0) {
cache.params = null;
} else {
cache.params = params;
}
}
};
var data = {
name: cache.name,
guess: cache.guess,
fnArgs: cache.type,
doc: cache.comments,
params: cache.params,
view: cache.view
};
var tip = createInfoDataTip(data, true, pos);
// ts.activeArgHints = makeTooltip(place.left, place.top, tip, editor, true);
// $(".ace_active_tooltip").remove();
var node = elt("div", cls + "tooltip ace_doc-tooltip ace_active_tooltip", tip);
document.querySelector("#funtipText").innerHTML = node.innerHTML;
if (cache.view && openIDETooltipType == "右侧") {
MenuTool.viewDoc(true, cache.view, true);
return
};
return;
}
// function showArgHints(ts, editor, pos) {
// var cache = ts.cachedArgHints;
// var place = getCusorPosForTooltip(editor);
// if (!cache.hasOwnProperty('params')) {
// if (!cache.comments) {
// cache.params = null;
// } else {
// var params = parseJsDocParams(cache.comments);
// if (!params || params.length === 0) {
// cache.params = null;
// } else {
// cache.params = params;
// }
// }
// };
// var data = {
// name: cache.name,
// guess: cache.guess,
// fnArgs: cache.type,
// doc: cache.comments,
// params: cache.params,
// view: cache.view
// };
// var tip = createInfoDataTip(data, true, pos);
// ts.activeArgHints = makeTooltip(place.left, place.top, tip, editor, true);
// if (cache.view && openIDETooltipType == "右侧") {
// MenuTool.viewDoc(true, cache.view, true);
// return
// };
// return;
// }
function makeTooltip(x, y, content, editor, closeOnCusorActivity, fadeOutDuration) {
var rect;
if (x === null || y === null) {
var location = getCusorPosForTooltip(editor);
x = location.left;
y = location.top;
rect = location.rect;
}
// $(".ace_active_tooltip").remove();
var node = elt("div", cls + "tooltip ace_doc-tooltip ace_active_tooltip", content);
node.style.left = x + "px";
node.style.top = y + "px";
node.style.width = "500px";
node.style.minHeight = "auto";
node.style.maxHeight = "300px";
node.style.overflow = "hidden";
node.style.overflowY = "auto";
node.style.opacity = 0;
node.style.transition = "none";
if (is_openIDETooltip && openIDETooltipType == "右侧") {
document.querySelector("#funtipText").innerHTML = node.innerHTML;
} else {
document.body.appendChild(node);
}
var _height = node.clientHeight;
var place = editor.renderer.$cursorLayer.getPixelPosition();
if (!rect) {
rect = editor.container.getBoundingClientRect();
}
// rect.height += $(".layui-tab2").height();
if (rect.height - editor.renderer.$cursorLayer.cursors[0].offsetTop - 30 < _height) {
node.style.transform = `translateY(-${parseInt(_height) + 60}px)`;
}
node.style.opacity = 1;
if (closeOnCusorActivity === true) {
if (!editor) {
throw Error('tern.makeTooltip called with closeOnCursorActivity=true but editor was not passed. Need to pass editor!');
}
var closeThisTip = function () {
setTimeout(() => {
if (!node.parentNode) return; //not sure what this is for, its from CM
remove(node);
editor.getSession().selection.off('changeCursor', closeThisTip);
editor.getSession().off('changeScrollTop', closeThisTip);
editor.getSession().off('changeScrollLeft', closeThisTip);
}, 100)
};
editor.getSession().selection.on('changeCursor', closeThisTip);
editor.getSession().on('changeScrollTop', closeThisTip);
editor.getSession().on('changeScrollLeft', closeThisTip);
}
if (fadeOutDuration) {
fadeOutDuration = parseInt(fadeOutDuration, 10);
if (fadeOutDuration > 100) {
var fadeThistip = function () {
if (!node.parentNode) return; //not sure what this is for, its from CM
fadeOut(node, fadeOutDuration);
try {
editor.getSession().selection.off('changeCursor', closeThisTip);
editor.getSession().off('changeScrollTop', closeThisTip);
editor.getSession().off('changeScrollLeft', closeThisTip);
} catch (ex) { }
};
setTimeout(fadeThistip, fadeOutDuration);
}
}
return node;
}
function getCusorPosForTooltip(editor) {
var renderer = editor.renderer;
var place = renderer.$cursorLayer.getPixelPosition();
var rect = editor.container.getBoundingClientRect();
place.top = editor.renderer.$cursorLayer.cursors[0].offsetTop;
place.top += rect.top;
place.left += rect.left - editor.renderer.scrollLeft;
place.left += renderer.gutterWidth
if (rect.width - (place.left - rect.left) - 45 < 500) {
place.left = rect.width + rect.left - 500 - 45
}
return {
left: place.left,
top: place.top + 30,
rect: rect
};
}
function moveTooltip(tip, x, y, editor) {
if (x === null || y === null) {
var location = getCusorPosForTooltip(editor);
x = location.left;
y = location.top;
}
tip.style.left = x + "px";
tip.style.top = y + "px";
}
function remove(node) {
var p = node && node.parentNode;
if (p) p.removeChild(node);
}
function fadeOut(tooltip, timeout) {
if (!timeout) {
timeout = 1100;
}
if (timeout === -1) {
remove(tooltip);
return;
}
tooltip.style.opacity = "0";
setTimeout(function () {
remove(tooltip);
}, timeout);
}
// 查询参数解释
function parseJsDocParams(str) {
if (!str) return [];
str = str.replace(/@param/gi, '@参数');
var params = [];
while (str.indexOf('@参数') !== -1) {
str = str.substring(str.indexOf('@参数') + 3);
var nextTagStart = str.indexOf('@');
var paramStr = nextTagStart === -1 ? str : str.substr(0, nextTagStart);
var thisParam = {
name: "",
parentName: "",
type: "",
description: "",
optional: false,
defaultValue: ""
};
var re = /\s{[^}]{1,50}}\s/;
var m;
while ((m = re.exec(paramStr)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
thisParam.type = m[0];
paramStr = paramStr.replace(thisParam.type, '').trim();
thisParam.type = thisParam.type.replace('{', '').replace('}', '').replace(' ', '').trim();
}
paramStr = paramStr.trim();
if (paramStr.substr(0, 1) === '[') {
thisParam.optional = true;
var endBracketIdx = paramStr.indexOf(']');
if (endBracketIdx === -1) {
showError('failed to parse parameter name; Found starting \'[\' but missing closing \']\'');
continue;
}
var nameStr = paramStr.substring(0, endBracketIdx + 1);
paramStr = paramStr.replace(nameStr, '').trim();
nameStr = nameStr.replace('[', '').replace(']', '');
if (nameStr.indexOf('=') !== -1) {
var defaultValue = nameStr.substr(nameStr.indexOf('=') + 1);
if (defaultValue.trim() === '') {
thisParam.defaultValue = "undefined";
} else {
thisParam.defaultValue = defaultValue.trim();
}
thisParam.name = nameStr.substring(0, nameStr.indexOf('=')).trim();
} else {
thisParam.name = nameStr.trim();
}
} else {
var nextSpace = paramStr.indexOf(' ');
if (nextSpace !== -1) {
thisParam.name = paramStr.substr(0, nextSpace);
paramStr = paramStr.substr(nextSpace).trim();
} else {
thisParam.name = paramStr;
paramStr = '';
}
}
var nameDotIdx = thisParam.name.indexOf('.');
if (nameDotIdx !== -1) {
thisParam.parentName = thisParam.name.substring(0, nameDotIdx);
thisParam.name = thisParam.name.substring(nameDotIdx + 1);
}
paramStr = paramStr.trim();
if (paramStr.length > 0) {
thisParam.description = paramStr.replace('-', '').trim();
}
thisParam.name = lang.escapeHTML(thisParam.name);
thisParam.parentName = lang.escapeHTML(thisParam.parentName);
thisParam.description = lang.escapeHTML(thisParam.description);
thisParam.type = lang.escapeHTML(thisParam.type);
thisParam.defaultValue = lang.escapeHTML(thisParam.defaultValue);
params.push(thisParam);
}
return params;
}
// 制作虚拟节点
function elFromString(s) {
var frag = document.createDocumentFragment(),
temp = document.createElement('span');
temp.innerHTML = s;
while (temp.firstChild) {
frag.appendChild(temp.firstChild);
}
return frag;
}
// 制作html标签
function elt(tagname, cls /*, ... elts*/) {
var e = document.createElement(tagname);
if (cls) e.className = cls;
for (var i = 2; i < arguments.length; ++i) {
var elt = arguments[i];
if (typeof elt == "string") elt = document.createTextNode(elt);
e.appendChild(elt);
}
return e;
}
// 制作函数提示弹出
function createInfoDataTip(data, includeType, activeArg) {
var tip = elt("span", null);
tip.style = {
"padding": "10px"
};
var d = data.doc;
var params = data.params || parseJsDocParams(d); //parse params
var data_arr = []
var activeData = [];
if (data.view) {
try {
data_arr = JSON.parse(data.view["参数信息"]);
activeData = data_arr[activeArg];
} catch (error) { }
}
if (includeType) {
var fnArgs = data.fnArgs ? data.fnArgs : data.type ? parseFnType(data.type) : null; //will be null if parseFnType detects that this is not a function
if (fnArgs) {
var getParam = function (arg, getChildren) {
if (params === null) return null;
if (!arg.name) return null;
var children = [];
for (var i = 0; i < params.length; i++) {
if (getChildren === true) {
if (params[i].parentName.toLowerCase().trim() === arg.name.toLowerCase().trim()) {
children.push(params[i]);
}
} else {
if (params[i].name.toLowerCase().trim() === arg.name.toLowerCase().trim()) {
return params[i];
}
}
}
if (getChildren === true) return children;
return null;
};
var getParamDetailedName = function (param) {
var name = param.name;
if (param.optional === true) {
if (param.defaultValue) {
name = "[" + name + " = " + param.defaultValue + "]";
} else {
name = "[" + name + "]";
}
}
return name;
};
var useDetailedArgHints = params.length === 0 || !isNaN(parseInt(activeArg));
var typeStr = '';
typeStr += lang.escapeHTML(data.exprName || data.name || "fn");
typeStr += "(";
var activeParam = null,
activeParamChildren = []; //one ore more child params for multiple object properties
for (var i = 0; i < fnArgs.args.length; i++) {
var paramStr = '';
var isCurrent = !isNaN(parseInt(activeArg)) ? i === activeArg : false;
var arg = fnArgs.args[i]; //name,type
var name = arg.name || "?";
if (name.length > 1 && name.substr(name.length - 1) === '?') {
name = name.substr(0, name.length - 1);
arg.name = name; //update the arg var with proper name for use below
}
if (!useDetailedArgHints) {
paramStr += lang.escapeHTML(name);
} else {
var param = getParam(arg, false);
var children = getParam(arg, true);
var type = arg.type;
var optional = false;
var defaultValue = '';
if (param !== null) {
name = param.name;
if (param.type) {
type = param.type;
}
if (isCurrent) {
activeParam = param;
}
optional = param.optional;
defaultValue = param.defaultValue.trim();
}
if (children && children.length > 0) {
if (isCurrent) {
activeParamChildren = children;
}
type = "{";
for (var c = 0; c < children.length; c++) {
type += children[c].name;
if (c + 1 !== children.length && children.length > 1) type += ", ";
}
type += "}";
}
paramStr += '<span class="' + cls + (isCurrent ? "farg-current" : "farg") + '">' + (lang.escapeHTML(name) || "?") + '</span>';
if (data_arr[i]) {
paramStr += type ? ':<span class="' + cls + 'type">' + data_arr[i]["参数类型"] + '</span> ' : '';
} else {
paramStr += type ? ':<span class="' + cls + 'type">' + (typeTips[lang.escapeHTML(type)] || lang.escapeHTML(type)) + '</span> ' : '';
}
if (defaultValue !== '') {
paramStr += '<span class="' + cls + 'jsdoc-param-defaultValue">= ' + lang.escapeHTML(defaultValue) + '</span>';
}
if (optional) {
paramStr = '<span class="' + cls + 'jsdoc-param-optionalWrapper">' + '<span class="' + cls + 'farg-optionalBracket">[</span>' + paramStr + '<span class="' + cls + 'jsdoc-param-optionalBracket">]</span>' + '</span>';
}
}
if (i > 0) paramStr = ', ' + paramStr;
typeStr += paramStr;
}
typeStr += ")";
if (data.view && data.view["返回值类型"]) {
typeStr += ' -> ' + data.view["返回值类型"];
} else if (fnArgs.rettype) {
if (useDetailedArgHints) {
typeStr += ' -> <span class="' + cls + 'type">' + (typeTips[lang.escapeHTML(fnArgs.rettype)] || lang.escapeHTML(fnArgs.rettype)) + '</span>';
} else {
typeStr += ' -> ' + lang.escapeHTML(fnArgs.rettype);
}
}
typeStr = '<span class="' + cls + (useDetailedArgHints ? "typeHeader" : "typeHeader-simple") + '">' + typeStr + '</span>'; //outer wrapper
if (useDetailedArgHints) {
if (activeParam && activeParam.description) {
typeStr += '<div class="' + cls + 'farg-current-description"><span class="' + cls + 'farg-current-name">' + activeParam.name + ': </span>' + activeParam.description + '</div>';
}
if (activeParamChildren && activeParamChildren.length > 0) {
for (var i = 0; i < activeParamChildren.length; i++) {
var t = activeParamChildren[i].type ? '<span class="' + cls + 'type">{' + (typeTips[activeParamChildren[i].type] || activeParamChildren[i].type) + '} </span>' : '';
typeStr += '<div class="' + cls + 'farg-current-description">' + t + '<span class="' + cls + 'farg-current-name">' + getParamDetailedName(activeParamChildren[i]) + ' </span>' + activeParamChildren[i].description + '</div>';
}
}
}
if (data.view) {
try {
typeStr += `<hr><div>参数简介:${activeData["描述"].replace(/\r\n/g, "<br>")}</div>`;
} catch (error) { }
}
var closeBtn = elt("span", null);
closeBtn.className = "closeBtn";
$(closeBtn).css({
"position": "absolute",
"top": "5px",
"right": "5px",
"background": "red",
"borderRadius": "50px",
"cursor": "pointer",
"padding": "0 2px"
});
// $(closeBtn).on("click", function () {
// window.isCloseArgHints = true;
// $(".ace_active_tooltip").remove();
// });
closeBtn.appendChild(elFromString(`<i class="layui-icon layui-icon-close" style="color:#fff;font-size:12px"></i>`));
tip.appendChild(elFromString(typeStr));
tip.appendChild(closeBtn);
}
}
if (!data["view"]) {
if (data.doc) {
var replaceParams = function (str, params) {
if (params.length === 0) {
return str;
}
str = str.replace(/@param/gi, '@参数').replace(/@returns/gi, '@返回'); //make sure all param tags are lowercase
var beforeParams = str.substr(0, str.indexOf('@参数'));
while (str.indexOf('@参数') !== -1) {
str = str.substring(str.indexOf('@参数') + 6); //starting after first param match
}
if (str.indexOf('@') !== -1) {
str = str.substr(str.indexOf('@')); //start at next tag that is not a param
} else {
str = ''; //@param was likely the last tag, trim remaining as its likely the end of a param description
}
var paramStr = '';
for (var i = 0; i < params.length; i++) {
paramStr += '<div>';
if (params[i].parentName.trim() === '') {
paramStr += ' <span class="' + cls + 'jsdoc-tag">@参数</span> ';
} else {
paramStr += '<span class="' + cls + 'jsdoc-tag-param-child">|-</span> '; //dont show param tag for child param
}
paramStr += params[i].type.trim() === '' ? '' : '<span class="' + cls + 'type">{' + (typeTips[params[i].type] || params[i].type) + '}</span> ';
if (params[i].name.trim() !== '') {
var name = params[i].name.trim();
if (params[i].parentName.trim() !== '') {
name = params[i].parentName.trim() + '.' + name;
}
var pName = '<span class="' + cls + 'jsdoc-param-name">' + name + '</span>';
if (params[i].defaultValue.trim() !== '') {
pName += '<span class="' + cls + 'jsdoc-param-defaultValue"> = ' + params[i].defaultValue + '</span>';
}
if (params[i].optional) {
pName = '<span class="' + cls + 'jsdoc-param-optionalWrapper">' + '<span class="' + cls + 'farg-optionalBracket">[</span>' + pName + '<span class="' + cls + 'jsdoc-param-optionalBracket">]</span>' + '</span>';
}
paramStr += pName;
}
paramStr += params[i].description.trim() === '' ? '' : ' - <span class="' + cls + 'jsdoc-param-description">' + params[i].description + '</span>';
paramStr += '</div>';
}
if (paramStr !== '') {
str = '<span class="' + cls + 'jsdoc-param-wrapper">' + paramStr + '</span>' + str;
}
return beforeParams + str;
};
var highlighTags = function (str) {
try {
str = ' ' + str + ' '; //add white space for regex
var re = / ?@([\w\u4e00-\u9fa5]{1,50})\s ?/gi;
var m;
while ((m = re.exec(str)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
str = str.replace(m[0], ' <span class="' + cls + 'jsdoc-tag">' + m[0].trim() + '</span> ');
}
} catch (ex) {
showError(ts, editor, ex);
}
return str.trim();
};
var highlightTypes = function (str) {
str = ' ' + str + ' '; //add white space for regex
try {
var re = /\s{[^}]{1,100}}\s/g;
var m;
while ((m = re.exec(str)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
str = str.replace(m[0], ' <span class="' + cls + 'type">{' + (typeTips[m[0].trim().replace(/{|}/g, "")] || m[0].trim().replace(/{|}/g, "")) + '}</span> ');
}
} catch (ex) {
showError(ts, editor, ex);
}
return str.trim();
};
var createLinks = function (str) {
try {
var httpProto = 'HTTP_PROTO_PLACEHOLDER';
var httpsProto = 'HTTPS_PROTO_PLACEHOLDER';
var re = /\bhttps?:\/\/[^\s<>"`{}|\^\[\]\\]+/gi;
var m;
while ((m = re.exec(str)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
var withoutProtocol = m[0].replace(/https/i, httpsProto).replace(/http/i, httpProto);
var text = m[0].replace(new RegExp('https://', 'i'), '').replace(new RegExp('http://', 'i'), '');
str = str.replace(m[0], '<a class="' + cls + 'tooltip-link" href="' + withoutProtocol + '" target="_blank">' + text + ' </a>');
}
str = str.replace(new RegExp(httpsProto, 'gi'), 'https').replace(new RegExp(httpProto, 'gi'), 'http');
} catch (ex) {
showError(ts, editor, ex);
}
return str;
};
if (d.substr(0, 1) === '*') {
d = d.substr(1); //tern leaves this for jsDoc as they start with /**, not exactly sure why...
}
d = lang.escapeHTML(d.trim());
d = replaceParams(d, params);
d = highlighTags(d);
d = highlightTypes(d);
d = createLinks(d);
tip.appendChild(elFromString(d));
}
if (data.url) {
tip.appendChild(document.createTextNode(" "));
var link = elt("a", null, "[docs]");
link.target = "_blank";
link.href = data.url;
tip.appendChild(link);
}
if (data.origin) {
tip.appendChild(elt("div", null, elt("em", null, "source: " + data.origin)));
}
}
return tip;
}
exports.tern_server = new TernServer();
});
(function () {
ace.require(["ace/ext/tern"], function (m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();