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

378 lines
10 KiB
JavaScript

ace.define("ace/ext/emmet", ["require", "exports", "module", "ace/keyboard/hash_handler", "ace/editor", "ace/snippets", "ace/range", "ace/config", "resources", "resources", "tabStops", "resources", "utils", "actions"], function (require, exports, module) {
"use strict";
var HashHandler = require("../keyboard/hash_handler").HashHandler;
var Editor = require("../editor").Editor;
// var snippetManager = require("../snippets").snippetManager;
var Range = require("../range").Range;
var config = require("../config");
var emmet, emmetPath;
function AceEmmetEditor() {}
AceEmmetEditor.prototype = {
setupContext: function (editor) {
this.ace = editor;
this.indentation = editor.session.getTabString();
if (!emmet)
emmet = window.emmet;
var resources = emmet.resources || emmet.require("resources");
resources.setVariable("indentation", this.indentation);
this.$syntax = null;
this.$syntax = this.getSyntax();
},
getSelectionRange: function () {
var range = this.ace.getSelectionRange();
var doc = this.ace.session.doc;
return {
start: doc.positionToIndex(range.start),
end: doc.positionToIndex(range.end)
};
},
createSelection: function (start, end) {
var doc = this.ace.session.doc;
this.ace.selection.setRange({
start: doc.indexToPosition(start),
end: doc.indexToPosition(end)
});
},
getCurrentLineRange: function () {
var ace = this.ace;
var row = ace.getCursorPosition().row;
var lineLength = ace.session.getLine(row).length;
var index = ace.session.doc.positionToIndex({
row: row,
column: 0
});
return {
start: index,
end: index + lineLength
};
},
getCaretPos: function () {
var pos = this.ace.getCursorPosition();
return this.ace.session.doc.positionToIndex(pos);
},
setCaretPos: function (index) {
var pos = this.ace.session.doc.indexToPosition(index);
this.ace.selection.moveToPosition(pos);
},
getCurrentLine: function () {
var row = this.ace.getCursorPosition().row;
return this.ace.session.getLine(row);
},
replaceContent: function (value, start, end, noIndent) {
if (end == null)
end = start == null ? this.getContent().length : start;
if (start == null)
start = 0;
var editor = this.ace;
var doc = editor.session.doc;
var range = Range.fromPoints(doc.indexToPosition(start), doc.indexToPosition(end));
editor.session.remove(range);
range.end = range.start;
value = this.$updateTabstops(value);
config.loadModule("ace/snippets", function (e) {
e.snippetManager.insertSnippet(editor, value)
});
},
getContent: function () {
return this.ace.getValue();
},
getSyntax: function () {
if (this.$syntax)
return this.$syntax;
var syntax = this.ace.session.$modeId.split("/").pop();
if (syntax == "html" || syntax == "php") {
var cursor = this.ace.getCursorPosition();
var state = this.ace.session.getState(cursor.row);
if (typeof state != "string")
state = state[0];
if (state) {
state = state.split("-");
if (state.length > 1)
syntax = state[0];
else if (syntax == "php")
syntax = "html";
}
}
return syntax;
},
getProfileName: function () {
var resources = emmet.resources || emmet.require("resources");
switch (this.getSyntax()) {
case "css":
return "css";
case "xml":
case "xsl":
return "xml";
case "html":
var profile = resources.getVariable("profile");
if (!profile)
profile = this.ace.session.getLines(0, 2).join("").search(/<!DOCTYPE[^>]+XHTML/i) != -1 ? "xhtml" : "html";
return profile;
default:
var mode = this.ace.session.$mode;
return mode.emmetConfig && mode.emmetConfig.profile || "xhtml";
}
},
prompt: function (title) {
return prompt(title); // eslint-disable-line no-alert
},
getSelection: function () {
return this.ace.session.getTextRange();
},
getFilePath: function () {
return "";
},
$updateTabstops: function (value) {
var base = 1000;
var zeroBase = 0;
var lastZero = null;
var ts = emmet.tabStops || emmet.require('tabStops');
var resources = emmet.resources || emmet.require("resources");
var settings = resources.getVocabulary("user");
var tabstopOptions = {
tabstop: function (data) {
var group = parseInt(data.group, 10);
var isZero = group === 0;
if (isZero)
group = ++zeroBase;
else
group += base;
var placeholder = data.placeholder;
if (placeholder) {
placeholder = ts.processText(placeholder, tabstopOptions);
}
var result = '${' + group + (placeholder ? ':' + placeholder : '') + '}';
if (isZero) {
lastZero = [data.start, result];
}
return result;
},
escape: function (ch) {
if (ch == '$') return '\\$';
if (ch == '\\') return '\\\\';
return ch;
}
};
value = ts.processText(value, tabstopOptions);
if (settings.variables['insert_final_tabstop'] && !/\$\{0\}$/.test(value)) {
value += '${0}';
} else if (lastZero) {
var common = emmet.utils ? emmet.utils.common : emmet.require('utils');
value = common.replaceSubstring(value, '${0}', lastZero[0], lastZero[1]);
}
return value;
}
};
// !!! 部分快捷键和ace快捷键冲突
var keymap = {
// expand_abbreviation: {
// "mac": "ctrl+alt+e",
// "win": "alt+e"
// },
// match_pair_outward: {
// "mac": "ctrl+d",
// "win": "ctrl+,"
// },
// match_pair_inward: {
// "mac": "ctrl+j",
// "win": "ctrl+shift+0"
// },
// matching_pair: {
// "mac": "ctrl+alt+j",
// "win": "alt+j"
// },
// next_edit_point: "alt+right",
// prev_edit_point: "alt+left",
// toggle_comment: {
// "mac": "command+/",
// "win": "ctrl+/"
// },
// split_join_tag: {
// "mac": "shift+command+'",
// "win": "shift+ctrl+`"
// },
// remove_tag: {
// "mac": "command+'",
// "win": "shift+ctrl+;"
// },
// evaluate_math_expression: {
// "mac": "shift+command+y",
// "win": "shift+ctrl+y"
// },
// increment_number_by_1: "ctrl+up",
// decrement_number_by_1: "ctrl+down",
// increment_number_by_01: "alt+up",
// decrement_number_by_01: "alt+down",
// increment_number_by_10: {
// "mac": "alt+command+up",
// "win": "shift+alt+up"
// },
// decrement_number_by_10: {
// "mac": "alt+command+down",
// "win": "shift+alt+down"
// },
// select_next_item: {
// "mac": "shift+command+.",
// "win": "shift+ctrl+."
// },
// select_previous_item: {
// "mac": "shift+command+,",
// "win": "shift+ctrl+,"
// },
// reflect_css_value: {
// "mac": "shift+command+r",
// "win": "shift+ctrl+r"
// },
// encode_decode_data_url: {
// "mac": "shift+ctrl+d",
// "win": "ctrl+'"
// },
expand_abbreviation_with_tab: "Tab",
// wrap_with_abbreviation: {
// "mac": "shift+ctrl+a",
// "win": "shift+ctrl+a"
// }
};
var editorProxy = new AceEmmetEditor();
exports.commands = new HashHandler();
// TODO tab之后的操作
exports.runEmmetCommand = function runEmmetCommand(editor) {
if (this.action == "expand_abbreviation_with_tab") {
if (!editor.selection.isEmpty())
return false;
var pos = editor.selection.lead;
var token = editor.session.getTokenAt(pos.row, pos.column);
if (token && /\btag\b/.test(token.type))
return false;
}
try {
editorProxy.setupContext(editor);
var actions = emmet.actions || emmet.require("actions");
if (this.action == "wrap_with_abbreviation") {
return setTimeout(function () {
actions.run("wrap_with_abbreviation", editorProxy);
}, 0);
}
// !!! TAB是否标签
var result = actions.run(this.action, editorProxy);
} catch (e) {
if (!emmet) {
var loading = exports.load(runEmmetCommand.bind(this, editor));
if (this.action == "expand_abbreviation_with_tab")
return false;
return loading;
}
editor._signal("changeStatus", typeof e == "string" ? e : e.message);
config.warn(e);
result = false;
}
return result;
};
for (var command in keymap) {
exports.commands.addCommand({
name: "emmet:" + command,
action: command,
bindKey: keymap[command],
exec: exports.runEmmetCommand,
multiSelectAction: "forEach"
});
}
exports.updateCommands = function (editor, enabled) {
if (enabled) {
editor.keyBinding.addKeyboardHandler(exports.commands);
} else {
editor.keyBinding.removeKeyboardHandler(exports.commands);
}
};
exports.isSupportedMode = function (mode) {
if (!mode) return false;
if (mode.emmetConfig) return true;
var id = mode.$id || mode;
return /css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(id);
};
exports.isAvailable = function (editor, command) {
if (/(evaluate_math_expression|expand_abbreviation)$/.test(command))
return true;
var mode = editor.session.$mode;
var isSupported = exports.isSupportedMode(mode);
if (isSupported && mode.$modes) {
try {
editorProxy.setupContext(editor);
if (/js|php/.test(editorProxy.getSyntax()))
isSupported = false;
} catch (e) {}
}
return isSupported;
};
var onChangeMode = function (e, target) {
var editor = target;
if (!editor)
return;
var enabled = exports.isSupportedMode(editor.session.$mode);
if (e.enableEmmet === false)
enabled = false;
if (enabled)
exports.load();
exports.updateCommands(editor, enabled);
};
exports.load = function (cb) {
if (typeof emmetPath !== "string") {
config.warn("script for emmet-core is not loaded");
return false;
}
config.loadModule(emmetPath, function () {
emmetPath = null;
cb && cb();
});
return true;
};
exports.AceEmmetEditor = AceEmmetEditor;
config.defineOptions(Editor.prototype, "editor", {
enableEmmet: {
set: function (val) {
this[val ? "on" : "removeListener"]("changeMode", onChangeMode);
onChangeMode({
enableEmmet: !!val
}, this);
},
value: true
}
});
exports.setCore = function (e) {
if (typeof e == "string")
emmetPath = e;
else
emmet = e;
};
});
(function () {
ace.require(["ace/ext/emmet"], function (m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();