-
Notifications
You must be signed in to change notification settings - Fork 0
/
plugin.js
171 lines (152 loc) · 4.43 KB
/
plugin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* Emmet plugin for CodeMirror
*/
import EmmetEditor from './editor';
import emmet from './emmet';
var defaultKeymap = {
'Cmd-E': 'emmet.expand_abbreviation',
'Tab': 'emmet.expand_abbreviation_with_tab',
'Cmd-D': 'emmet.balance_outward',
'Shift-Cmd-D': 'emmet.balance_inward',
'Cmd-M': 'emmet.matching_pair',
'Shift-Cmd-A': 'emmet.wrap_with_abbreviation',
'Ctrl-Alt-Right': 'emmet.next_edit_point',
'Ctrl-Alt-Left': 'emmet.prev_edit_point',
'Cmd-L': 'emmet.select_line',
'Cmd-Shift-M': 'emmet.merge_lines',
'Cmd-/': 'emmet.toggle_comment',
'Cmd-J': 'emmet.split_join_tag',
'Cmd-K': 'emmet.remove_tag',
'Shift-Cmd-Y': 'emmet.evaluate_math_expression',
'Ctrl-Up': 'emmet.increment_number_by_1',
'Ctrl-Down': 'emmet.decrement_number_by_1',
'Ctrl-Alt-Up': 'emmet.increment_number_by_01',
'Ctrl-Alt-Down': 'emmet.decrement_number_by_01',
'Shift-Ctrl-Up': 'emmet.increment_number_by_10',
'Shift-Ctrl-Down': 'emmet.decrement_number_by_10',
'Shift-Cmd-.': 'emmet.select_next_item',
'Shift-Cmd-,': 'emmet.select_previous_item',
'Cmd-B': 'emmet.reflect_css_value',
'Enter': 'emmet.insert_formatted_line_break_only'
};
// actions that should be performed in single selection mode
var singleSelectionActions = [
'prev_edit_point', 'next_edit_point', 'merge_lines',
'reflect_css_value', 'select_next_item', 'select_previous_item',
'wrap_with_abbreviation', 'update_tag', 'insert_formatted_line_break_only'
];
/**
* Setup Emmet on given CodeMirror editor instance
* @param {CodeMirror} cm
* @param {Object} keymap
*/
export default function main(cm, keymap=defaultKeymap) {
keymap = systemKeymap(keymap);
cm.__emmetKeymap = keymap;
cm.addKeyMap(keymap);
return cm;
}
main.dispose = function(cm) {
if (cm.__emmetKeymap) {
cm.removeKeyMap(cm.__emmetKeymap);
delete cm.__emmetKeymap;
}
};
main.defaultKeymap = defaultKeymap;
main.systemKeymap = systemKeymap;
main.emmet = emmet;
main.EmmetEditor = EmmetEditor;
main.setup = function(CodeMirror) {
// setup default Emmet actions
emmet.actions.getList().forEach(obj => {
var action = obj.name;
var command = 'emmet.' + action;
if (!CodeMirror.commands[command]) {
CodeMirror.commands[command] = ~singleSelectionActions.indexOf(action)
? actionDecorator(action)
: multiSelectionActionDecorator(action);
}
});
// add “profile” property to CodeMirror defaults so in won’t be lost
// then CM instance is instantiated with “profile” property
if (CodeMirror.defineOption) {
CodeMirror.defineOption('profile', 'html');
} else {
CodeMirror.defaults.profile = 'html';
}
};
if (typeof CodeMirror !== 'undefined') {
main.setup(CodeMirror);
}
function noop() {
if (CodeMirror.version >= '3.1') {
return CodeMirror.Pass;
}
throw CodeMirror.Pass;
}
/**
* Emmet action decorator: creates a command function
* for CodeMirror and executes Emmet action as single
* undo command
* @param {String} name Action name
* @return {Function}
*/
function actionDecorator(name) {
return function(cm) {
var result;
cm.operation(() => result = runAction(name, new EmmetEditor(cm)));
return result;
};
}
/**
* Same as `actionDecorator()` but executes action
* with multiple selections
* @param {String} name Action name
* @return {Function}
*/
function multiSelectionActionDecorator(name) {
return function(cm) {
var editor = new EmmetEditor(cm);
var selections = editor.selectionList();
var result = null;
cm.operation(function() {
for (var i = 0, il = selections.length; i < il; i++) {
editor.selectionIndex = i;
result = runAction(name, editor);
if (result === CodeMirror.Pass) {
break;
}
}
});
return result;
};
}
/**
* Runs Emmet action
* @param {String} name Action name
* @param {EmmetEditor} editor EmmetEditor instance
* @return {Boolean} Returns `true` if action is performed
* successfully
*/
function runAction(name, editor) {
if (name == 'expand_abbreviation_with_tab' && (editor.context.somethingSelected() || !editor.isValidSyntax())) {
// pass through Tab key handler if there's a selection
return noop();
}
var result = false;
try {
result = emmet.run(name, editor);
if (!result && name == 'insert_formatted_line_break_only') {
return noop();
}
} catch (e) {
console.error(e);
}
return result;
}
function systemKeymap(keymap) {
var mac = /Mac/.test(navigator.platform);
var out = {};
Object.keys(keymap).forEach(key => out[!mac ? key.replace('Cmd', 'Ctrl') : key] = keymap[key]);
return out;
}