@atlaskit/editor-plugin-code-block 12.1.10 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cjs/codeBlockPlugin.js +9 -2
- package/dist/cjs/editor-commands/index.js +56 -4
- package/dist/cjs/pm-plugins/actions.js +3 -1
- package/dist/cjs/pm-plugins/auto-detect-state.js +11 -0
- package/dist/cjs/pm-plugins/auto-detect.js +57 -0
- package/dist/cjs/pm-plugins/main.js +1 -1
- package/dist/cjs/pm-plugins/toolbar.js +47 -11
- package/dist/cjs/pm-plugins/utils.js +0 -3
- package/dist/cjs/ui/CodeBlockLanguagePicker.js +15 -8
- package/dist/cjs/ui/LanguagePicker.js +7 -15
- package/dist/cjs/ui/language-picker-options.js +2 -1
- package/dist/cjs/utils/auto-detect-state.js +185 -0
- package/dist/cjs/utils/auto-detect-view.js +127 -0
- package/dist/cjs/utils/language-detect.js +126 -0
- package/dist/es2019/codeBlockPlugin.js +5 -1
- package/dist/es2019/editor-commands/index.js +52 -2
- package/dist/es2019/pm-plugins/actions.js +3 -1
- package/dist/es2019/pm-plugins/auto-detect-state.js +3 -0
- package/dist/es2019/pm-plugins/auto-detect.js +47 -0
- package/dist/es2019/pm-plugins/main.js +1 -1
- package/dist/es2019/pm-plugins/toolbar.js +41 -3
- package/dist/es2019/pm-plugins/utils.js +0 -3
- package/dist/es2019/ui/CodeBlockLanguagePicker.js +15 -8
- package/dist/es2019/ui/LanguagePicker.js +6 -14
- package/dist/es2019/ui/language-picker-options.js +2 -1
- package/dist/es2019/utils/auto-detect-state.js +179 -0
- package/dist/es2019/utils/auto-detect-view.js +108 -0
- package/dist/es2019/utils/language-detect.js +99 -0
- package/dist/esm/codeBlockPlugin.js +9 -2
- package/dist/esm/editor-commands/index.js +55 -3
- package/dist/esm/pm-plugins/actions.js +3 -1
- package/dist/esm/pm-plugins/auto-detect-state.js +5 -0
- package/dist/esm/pm-plugins/auto-detect.js +50 -0
- package/dist/esm/pm-plugins/main.js +1 -1
- package/dist/esm/pm-plugins/toolbar.js +47 -11
- package/dist/esm/pm-plugins/utils.js +0 -3
- package/dist/esm/ui/CodeBlockLanguagePicker.js +15 -8
- package/dist/esm/ui/LanguagePicker.js +7 -15
- package/dist/esm/ui/language-picker-options.js +2 -1
- package/dist/esm/utils/auto-detect-state.js +178 -0
- package/dist/esm/utils/auto-detect-view.js +120 -0
- package/dist/esm/utils/language-detect.js +119 -0
- package/dist/types/editor-commands/index.d.ts +2 -0
- package/dist/types/pm-plugins/actions.d.ts +2 -0
- package/dist/types/pm-plugins/auto-detect-state.d.ts +16 -0
- package/dist/types/pm-plugins/auto-detect.d.ts +5 -0
- package/dist/types/pm-plugins/utils.d.ts +1 -1
- package/dist/types/ui/CodeBlockLanguagePicker.d.ts +7 -1
- package/dist/types/ui/LanguagePicker.d.ts +4 -8
- package/dist/types/utils/auto-detect-state.d.ts +11 -0
- package/dist/types/utils/auto-detect-view.d.ts +8 -0
- package/dist/types/utils/language-detect.d.ts +3 -0
- package/dist/types-ts4.5/editor-commands/index.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/auto-detect-state.d.ts +16 -0
- package/dist/types-ts4.5/pm-plugins/auto-detect.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/utils.d.ts +1 -1
- package/dist/types-ts4.5/ui/CodeBlockLanguagePicker.d.ts +7 -1
- package/dist/types-ts4.5/ui/LanguagePicker.d.ts +4 -8
- package/dist/types-ts4.5/utils/auto-detect-state.d.ts +11 -0
- package/dist/types-ts4.5/utils/auto-detect-view.d.ts +8 -0
- package/dist/types-ts4.5/utils/language-detect.d.ts +3 -0
- package/package.json +12 -12
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.updateAutoDetectState = exports.shouldTriggerLargeChangeDetection = exports.removeAutoDetection = exports.queueAutoDetection = exports.hasEnoughTextForAutoDetection = exports.getLocalId = exports.getFirstLine = exports.createAutoDetectEntry = void 0;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
var _codeBlock = require("@atlaskit/editor-common/code-block");
|
|
11
|
+
var _utils = require("../pm-plugins/utils");
|
|
12
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
13
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
14
|
+
var MIN_AUTO_DETECT_TEXT_LENGTH = 20;
|
|
15
|
+
var shouldTriggerLargeChangeDetection = exports.shouldTriggerLargeChangeDetection = function shouldTriggerLargeChangeDetection(lastObservedText, text) {
|
|
16
|
+
if (!lastObservedText) {
|
|
17
|
+
return text.length > 0;
|
|
18
|
+
}
|
|
19
|
+
return Math.abs(text.length - lastObservedText.length) > lastObservedText.length / 2;
|
|
20
|
+
};
|
|
21
|
+
var getFirstLine = exports.getFirstLine = function getFirstLine(text) {
|
|
22
|
+
var _text$split$;
|
|
23
|
+
return (_text$split$ = text.split('\n')[0]) !== null && _text$split$ !== void 0 ? _text$split$ : '';
|
|
24
|
+
};
|
|
25
|
+
var hasEnoughTextForAutoDetection = exports.hasEnoughTextForAutoDetection = function hasEnoughTextForAutoDetection(text) {
|
|
26
|
+
return text.trim().length >= MIN_AUTO_DETECT_TEXT_LENGTH;
|
|
27
|
+
};
|
|
28
|
+
var getLocalId = exports.getLocalId = function getLocalId(node) {
|
|
29
|
+
return typeof node.attrs.localId === 'string' ? node.attrs.localId : null;
|
|
30
|
+
};
|
|
31
|
+
var createAutoDetectEntry = exports.createAutoDetectEntry = function createAutoDetectEntry(node, pos, isPending, previous) {
|
|
32
|
+
return {
|
|
33
|
+
lastObservedText: node.textContent,
|
|
34
|
+
lastObservedFirstLine: getFirstLine(node.textContent),
|
|
35
|
+
isPending: isPending,
|
|
36
|
+
detectionResult: previous === null || previous === void 0 ? void 0 : previous.detectionResult,
|
|
37
|
+
autoDetectedLanguage: previous === null || previous === void 0 ? void 0 : previous.autoDetectedLanguage,
|
|
38
|
+
pos: pos
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
var queueAutoDetection = exports.queueAutoDetection = function queueAutoDetection(languageDetectionMap, node, pos, isPending) {
|
|
42
|
+
var localId = getLocalId(node);
|
|
43
|
+
if (!localId) {
|
|
44
|
+
return languageDetectionMap;
|
|
45
|
+
}
|
|
46
|
+
return _objectSpread(_objectSpread({}, languageDetectionMap), {}, (0, _defineProperty2.default)({}, localId, createAutoDetectEntry(node, pos, isPending, languageDetectionMap[localId])));
|
|
47
|
+
};
|
|
48
|
+
var removeAutoDetection = exports.removeAutoDetection = function removeAutoDetection(languageDetectionMap, localId) {
|
|
49
|
+
if (!languageDetectionMap[localId]) {
|
|
50
|
+
return languageDetectionMap;
|
|
51
|
+
}
|
|
52
|
+
var nextLanguageDetectionMap = _objectSpread({}, languageDetectionMap);
|
|
53
|
+
delete nextLanguageDetectionMap[localId];
|
|
54
|
+
return nextLanguageDetectionMap;
|
|
55
|
+
};
|
|
56
|
+
var getCodeBlockLocalIdsRemovedFromChangedRanges = function getCodeBlockLocalIdsRemovedFromChangedRanges(tr, codeBlockType) {
|
|
57
|
+
var localIds = new Set();
|
|
58
|
+
tr.steps.forEach(function (step, stepIndex) {
|
|
59
|
+
var docAtStep = tr.docs[stepIndex];
|
|
60
|
+
step.getMap().forEach(function (oldStart, oldEnd) {
|
|
61
|
+
if (oldStart === oldEnd) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
var clampedOldEnd = Math.min(oldEnd, docAtStep.content.size);
|
|
65
|
+
docAtStep.nodesBetween(oldStart, clampedOldEnd, function (node, pos) {
|
|
66
|
+
if (node.type !== codeBlockType) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
var isWholeCodeBlockRemoved = pos >= oldStart && pos + node.nodeSize <= clampedOldEnd;
|
|
70
|
+
if (!isWholeCodeBlockRemoved) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
var localId = getLocalId(node);
|
|
74
|
+
if (localId) {
|
|
75
|
+
localIds.add(localId);
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
return localIds;
|
|
82
|
+
};
|
|
83
|
+
var getCodeBlockTransactionChanges = function getCodeBlockTransactionChanges(tr, codeBlockType) {
|
|
84
|
+
var insertedNodesWithPos = (0, _codeBlock.getInsertedCodeBlocksInTransaction)(tr, codeBlockType);
|
|
85
|
+
var removedFromChangedRangesLocalIds = getCodeBlockLocalIdsRemovedFromChangedRanges(tr, codeBlockType);
|
|
86
|
+
var insertedLocalIds = new Set();
|
|
87
|
+
var insertedCodeBlocks = [];
|
|
88
|
+
insertedNodesWithPos.forEach(function (_ref) {
|
|
89
|
+
var node = _ref.node,
|
|
90
|
+
pos = _ref.pos;
|
|
91
|
+
var localId = getLocalId(node);
|
|
92
|
+
if (!localId) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
insertedLocalIds.add(localId);
|
|
96
|
+
if (!removedFromChangedRangesLocalIds.has(localId)) {
|
|
97
|
+
insertedCodeBlocks.push({
|
|
98
|
+
localId: localId,
|
|
99
|
+
node: node,
|
|
100
|
+
pos: pos
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
var deletedLocalIds = new Set();
|
|
105
|
+
removedFromChangedRangesLocalIds.forEach(function (localId) {
|
|
106
|
+
if (!insertedLocalIds.has(localId)) {
|
|
107
|
+
deletedLocalIds.add(localId);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return {
|
|
111
|
+
deletedLocalIds: deletedLocalIds,
|
|
112
|
+
insertedCodeBlocks: insertedCodeBlocks
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
var updateAutoDetectState = exports.updateAutoDetectState = function updateAutoDetectState(tr, pluginState) {
|
|
116
|
+
var codeBlock = tr.doc.type.schema.nodes.codeBlock;
|
|
117
|
+
var isPaste = tr.getMeta('paste') === true || tr.getMeta('uiEvent') === 'paste';
|
|
118
|
+
var isExternalContentChange = tr.getMeta('replaceDocument') === true || tr.getMeta('isRemote') === true;
|
|
119
|
+
var hasTrackedEntries = Object.keys(pluginState.languageDetectionMap).length > 0;
|
|
120
|
+
|
|
121
|
+
// Page loads and remote edits should not start auto-detection for code blocks.
|
|
122
|
+
if (!hasTrackedEntries && isExternalContentChange) {
|
|
123
|
+
return pluginState.languageDetectionMap;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Existing entries still need mapping/deletion cleanup, but external edits should not refresh text.
|
|
127
|
+
var changedCodeBlockNodes = isExternalContentChange ? [] : (0, _utils.getAllChangedCodeBlocksInTransaction)(tr);
|
|
128
|
+
if (!hasTrackedEntries && !changedCodeBlockNodes.length) {
|
|
129
|
+
return pluginState.languageDetectionMap;
|
|
130
|
+
}
|
|
131
|
+
var _getCodeBlockTransact = getCodeBlockTransactionChanges(tr, codeBlock),
|
|
132
|
+
deletedLocalIds = _getCodeBlockTransact.deletedLocalIds,
|
|
133
|
+
insertedCodeBlocks = _getCodeBlockTransact.insertedCodeBlocks;
|
|
134
|
+
var languageDetectionMap = hasTrackedEntries ? Object.fromEntries(Object.entries(pluginState.languageDetectionMap).map(function (_ref2) {
|
|
135
|
+
var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
|
|
136
|
+
localId = _ref3[0],
|
|
137
|
+
entry = _ref3[1];
|
|
138
|
+
return [localId, _objectSpread(_objectSpread({}, entry), {}, {
|
|
139
|
+
pos: tr.mapping.map(entry.pos)
|
|
140
|
+
})];
|
|
141
|
+
})) : pluginState.languageDetectionMap;
|
|
142
|
+
if (!isExternalContentChange) {
|
|
143
|
+
insertedCodeBlocks.forEach(function (_ref4) {
|
|
144
|
+
var localId = _ref4.localId,
|
|
145
|
+
node = _ref4.node,
|
|
146
|
+
pos = _ref4.pos;
|
|
147
|
+
if (node.attrs.language) {
|
|
148
|
+
languageDetectionMap = removeAutoDetection(languageDetectionMap, localId);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
languageDetectionMap = queueAutoDetection(languageDetectionMap, node, pos, hasEnoughTextForAutoDetection(node.textContent));
|
|
152
|
+
});
|
|
153
|
+
changedCodeBlockNodes.forEach(function (_ref5) {
|
|
154
|
+
var node = _ref5.node,
|
|
155
|
+
pos = _ref5.pos;
|
|
156
|
+
var localId = getLocalId(node);
|
|
157
|
+
if (!localId || !languageDetectionMap[localId]) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
var currentLanguage = node.attrs.language;
|
|
161
|
+
var previousEntry = languageDetectionMap[localId];
|
|
162
|
+
if (currentLanguage && currentLanguage !== previousEntry.autoDetectedLanguage) {
|
|
163
|
+
languageDetectionMap = removeAutoDetection(languageDetectionMap, localId);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
var text = node.textContent;
|
|
167
|
+
var firstLine = getFirstLine(text);
|
|
168
|
+
var shouldTriggerDetection = previousEntry.isPending || isPaste || firstLine !== previousEntry.lastObservedFirstLine || shouldTriggerLargeChangeDetection(previousEntry.lastObservedText, text);
|
|
169
|
+
var isPending = hasEnoughTextForAutoDetection(text) && shouldTriggerDetection;
|
|
170
|
+
|
|
171
|
+
// Only pending detection refreshes the text snapshot; otherwise gradual typing
|
|
172
|
+
// should continue comparing against the last attempted detection.
|
|
173
|
+
languageDetectionMap = isPending ? queueAutoDetection(languageDetectionMap, node, pos, true) : _objectSpread(_objectSpread({}, languageDetectionMap), {}, (0, _defineProperty2.default)({}, localId, _objectSpread(_objectSpread({}, previousEntry), {}, {
|
|
174
|
+
isPending: false,
|
|
175
|
+
pos: pos
|
|
176
|
+
})));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
deletedLocalIds.forEach(function (localId) {
|
|
180
|
+
if (languageDetectionMap[localId]) {
|
|
181
|
+
languageDetectionMap = removeAutoDetection(languageDetectionMap, localId);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return languageDetectionMap;
|
|
185
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.syncPendingDetectionTimers = void 0;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
11
|
+
var _actions = require("../pm-plugins/actions");
|
|
12
|
+
var _autoDetectState = require("../pm-plugins/auto-detect-state");
|
|
13
|
+
var _autoDetectState2 = require("./auto-detect-state");
|
|
14
|
+
var _languageDetect = require("./language-detect");
|
|
15
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
16
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
17
|
+
var AUTO_DETECT_DEBOUNCE_MS = 500;
|
|
18
|
+
|
|
19
|
+
// Stored positions are mapped through transactions; verify the localId before using them.
|
|
20
|
+
var getCodeBlockFromEntry = function getCodeBlockFromEntry(view, localId, entry) {
|
|
21
|
+
var node = view.state.doc.nodeAt(entry.pos);
|
|
22
|
+
var codeBlockType = view.state.schema.nodes.codeBlock;
|
|
23
|
+
if ((node === null || node === void 0 ? void 0 : node.type) === codeBlockType && node.attrs.localId === localId) {
|
|
24
|
+
return {
|
|
25
|
+
node: node,
|
|
26
|
+
pos: entry.pos
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Runs after debounce, so it must re-read current editor state before applying language changes.
|
|
33
|
+
var runPendingDetection = function runPendingDetection(view, localId, api) {
|
|
34
|
+
var _api$core;
|
|
35
|
+
var pluginState = _autoDetectState.autoDetectPluginKey.getState(view.state);
|
|
36
|
+
var entry = pluginState === null || pluginState === void 0 ? void 0 : pluginState.languageDetectionMap[localId];
|
|
37
|
+
if (!(entry !== null && entry !== void 0 && entry.isPending)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
var found = getCodeBlockFromEntry(view, localId, entry);
|
|
41
|
+
if (!found) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
var detectedLanguage = (0, _languageDetect.detectLanguage)(found.node.textContent);
|
|
45
|
+
var detectionResult = detectedLanguage ? 'detected' : 'noneDetected';
|
|
46
|
+
// Keep a previous auto-detected language when the latest snippet is too weak to classify.
|
|
47
|
+
var shouldPreserveAutoDetectedLanguage = !detectedLanguage && Boolean(entry.autoDetectedLanguage) && found.node.attrs.language === entry.autoDetectedLanguage;
|
|
48
|
+
var nextEntry = _objectSpread(_objectSpread({}, (0, _autoDetectState2.createAutoDetectEntry)(found.node, found.pos, false, entry)), {}, {
|
|
49
|
+
detectionResult: detectionResult,
|
|
50
|
+
autoDetectedLanguage: detectedLanguage !== null && detectedLanguage !== void 0 ? detectedLanguage : entry.autoDetectedLanguage
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// If there is no confident detection, record the result without clearing user-visible language.
|
|
54
|
+
var shouldOnlyUpdateDetectionState = !detectedLanguage && (!found.node.attrs.language || shouldPreserveAutoDetectedLanguage);
|
|
55
|
+
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref) {
|
|
56
|
+
var _api$analytics;
|
|
57
|
+
var tr = _ref.tr;
|
|
58
|
+
if (!shouldOnlyUpdateDetectionState) {
|
|
59
|
+
tr.setNodeMarkup(found.pos, undefined, _objectSpread(_objectSpread({}, found.node.attrs), {}, {
|
|
60
|
+
language: detectedLanguage
|
|
61
|
+
}), found.node.marks);
|
|
62
|
+
}
|
|
63
|
+
tr.setMeta(_autoDetectState.autoDetectPluginKey, {
|
|
64
|
+
type: _actions.ACTIONS.SET_AUTO_DETECT_ENTRY,
|
|
65
|
+
data: {
|
|
66
|
+
localId: localId,
|
|
67
|
+
entry: nextEntry
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent({
|
|
71
|
+
action: _analytics.ACTION.LANGUAGE_AUTO_DETECTED,
|
|
72
|
+
actionSubject: _analytics.ACTION_SUBJECT.CODE_BLOCK,
|
|
73
|
+
attributes: {
|
|
74
|
+
language: detectedLanguage !== null && detectedLanguage !== void 0 ? detectedLanguage : 'none',
|
|
75
|
+
detectionResult: detectionResult
|
|
76
|
+
},
|
|
77
|
+
eventType: _analytics.EVENT_TYPE.TRACK
|
|
78
|
+
})(tr);
|
|
79
|
+
return tr;
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
var clearTimer = function clearTimer(timers, localId) {
|
|
83
|
+
var scheduledDetection = timers.get(localId);
|
|
84
|
+
if (scheduledDetection) {
|
|
85
|
+
clearTimeout(scheduledDetection.timer);
|
|
86
|
+
timers.delete(localId);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Keeps one debounce timer per pending code block and drops timers for stale entries.
|
|
91
|
+
var syncPendingDetectionTimers = exports.syncPendingDetectionTimers = function syncPendingDetectionTimers(view, timers, api) {
|
|
92
|
+
var _pluginState$language;
|
|
93
|
+
var pluginState = _autoDetectState.autoDetectPluginKey.getState(view.state);
|
|
94
|
+
var pendingEntries = Object.entries((_pluginState$language = pluginState === null || pluginState === void 0 ? void 0 : pluginState.languageDetectionMap) !== null && _pluginState$language !== void 0 ? _pluginState$language : {}).filter(function (_ref2) {
|
|
95
|
+
var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
|
|
96
|
+
entry = _ref3[1];
|
|
97
|
+
return entry.isPending;
|
|
98
|
+
});
|
|
99
|
+
var pendingLocalIds = new Set(pendingEntries.map(function (_ref4) {
|
|
100
|
+
var _ref5 = (0, _slicedToArray2.default)(_ref4, 1),
|
|
101
|
+
localId = _ref5[0];
|
|
102
|
+
return localId;
|
|
103
|
+
}));
|
|
104
|
+
pendingEntries.forEach(function (_ref6) {
|
|
105
|
+
var _ref7 = (0, _slicedToArray2.default)(_ref6, 2),
|
|
106
|
+
localId = _ref7[0],
|
|
107
|
+
entry = _ref7[1];
|
|
108
|
+
var scheduledDetection = timers.get(localId);
|
|
109
|
+
if ((scheduledDetection === null || scheduledDetection === void 0 ? void 0 : scheduledDetection.lastObservedText) === entry.lastObservedText) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
clearTimer(timers, localId);
|
|
113
|
+
var timer = setTimeout(function () {
|
|
114
|
+
timers.delete(localId);
|
|
115
|
+
runPendingDetection(view, localId, api);
|
|
116
|
+
}, AUTO_DETECT_DEBOUNCE_MS);
|
|
117
|
+
timers.set(localId, {
|
|
118
|
+
lastObservedText: entry.lastObservedText,
|
|
119
|
+
timer: timer
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
timers.forEach(function (_, localId) {
|
|
123
|
+
if (!pendingLocalIds.has(localId)) {
|
|
124
|
+
clearTimer(timers, localId);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.detectLanguage = void 0;
|
|
8
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
9
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
+
/* eslint-disable require-unicode-regexp */
|
|
11
|
+
|
|
12
|
+
// Conservative weighted-regex heuristic for common high-confidence snippets, not a full classifier.
|
|
13
|
+
// Ambiguous snippets intentionally return null so users can select the language manually.
|
|
14
|
+
var MAX_DETECTION_CHARS = 10000;
|
|
15
|
+
var MIN_DETECTION_SCORE = 3; // Require at least one medium-confidence signal before auto-selecting.
|
|
16
|
+
var MIN_SCORE_GAP = 2; // Avoid auto-selecting when top two languages are too close to distinguish.
|
|
17
|
+
|
|
18
|
+
var hasPattern = function hasPattern(code, pattern) {
|
|
19
|
+
// Reset stateful regexes so repeated tests always start at the beginning.
|
|
20
|
+
pattern.lastIndex = 0;
|
|
21
|
+
return pattern.test(code);
|
|
22
|
+
};
|
|
23
|
+
var scorePatterns = function scorePatterns(code, patterns) {
|
|
24
|
+
return patterns.reduce(function (score, _ref) {
|
|
25
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
26
|
+
pattern = _ref2[0],
|
|
27
|
+
value = _ref2[1];
|
|
28
|
+
return score + (hasPattern(code, pattern) ? value : 0);
|
|
29
|
+
}, 0);
|
|
30
|
+
};
|
|
31
|
+
var looksLikeHtmlTagPair = function looksLikeHtmlTagPair(code) {
|
|
32
|
+
var openTags = new Set();
|
|
33
|
+
var tagPattern = /<\/?([a-z][a-z0-9-]*)\b[^<>]{0,500}>/gi;
|
|
34
|
+
var match;
|
|
35
|
+
while ((match = tagPattern.exec(code)) !== null) {
|
|
36
|
+
var _match = match,
|
|
37
|
+
_match2 = (0, _slicedToArray2.default)(_match, 2),
|
|
38
|
+
tag = _match2[0],
|
|
39
|
+
tagName = _match2[1];
|
|
40
|
+
if (tag.endsWith('/>')) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (tag.startsWith('</')) {
|
|
44
|
+
if (openTags.has(tagName.toLowerCase())) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
openTags.add(tagName.toLowerCase());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
};
|
|
53
|
+
var looksLikeJson = function looksLikeJson(code) {
|
|
54
|
+
var trimmed = code.trim();
|
|
55
|
+
if (!/^[{[]/.test(trimmed) || !/[}\]]$/.test(trimmed)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
var parsed = JSON.parse(trimmed);
|
|
60
|
+
return parsed !== null && (0, _typeof2.default)(parsed) === 'object';
|
|
61
|
+
} catch (_unused) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var getLanguageScores = function getLanguageScores(code) {
|
|
66
|
+
return [{
|
|
67
|
+
language: 'json',
|
|
68
|
+
score: looksLikeJson(code) ? 8 : 0
|
|
69
|
+
}, {
|
|
70
|
+
language: 'html',
|
|
71
|
+
score: scorePatterns(code, [[/<!doctype\s+html/i, 5], [/<\/?(?:html|head|body|div|span|script|style|section|template)\b/i, 2]]) + (looksLikeHtmlTagPair(code) ? 3 : 0)
|
|
72
|
+
}, {
|
|
73
|
+
language: 'css',
|
|
74
|
+
score: scorePatterns(code, [[/@[\w-]+\s+[^{]+\{/, 3], [/[.#]?[-_a-zA-Z][-_a-zA-Z0-9\s,.:#>+~*\[\]='"]+\{[^}]*\b(?:color|display|margin|padding|font|background|border|width|height|grid|flex)\s*:/, 5], [/\b(?:color|display|margin|padding|font-size|background|border|width|height)\s*:\s*[^;{}]+;/, 3]])
|
|
75
|
+
}, {
|
|
76
|
+
language: 'sql',
|
|
77
|
+
score: scorePatterns(code, [[/\bSELECT\b[\s\S]+\bFROM\b/i, 5], [/\b(?:INSERT\s+INTO|UPDATE\b[\s\S]+\bSET\b|DELETE\s+FROM|CREATE\s+TABLE|ALTER\s+TABLE)\b/i, 5], [/\b(?:JOIN|WHERE|GROUP\s+BY|ORDER\s+BY|LIMIT)\b/i, 2]])
|
|
78
|
+
}, {
|
|
79
|
+
language: 'typescript',
|
|
80
|
+
score: scorePatterns(code, [[/\b(?:interface|type)\s+[A-Z_$][\w$]*(?:\s*[=<{])/, 5], [/\bimport\s+type\b|\bexport\s+type\b/, 4], [/\b(?:const|let|var)\s+[\w$]+\s*:\s*[A-Za-z_$][\w$<>|\[\],\s]*/, 4], [/\)\s*:\s*(?:Promise<)?[A-Za-z_$][\w$<>|\[\],\s]*(?:>|\s)?\s*=>?\s*[{;]/, 3], [/\b(?:as\s+const|implements\s+[A-Z_$]|enum\s+[A-Z_$])/, 3]])
|
|
81
|
+
}, {
|
|
82
|
+
language: 'javascript',
|
|
83
|
+
score: scorePatterns(code, [[/\b(?:const|let|var)\s+[\w$]+\s*=/, 3], [/\bfunction\s*[\w$]*\s*\([^)]*\)\s*\{/, 3], [/=>\s*(?:\{|[\w$'"`(])/, 3], [/\b(?:import|export)\s+(?:[\w${}*,\s]+\s+from\s+)?['"][^'"]+['"]/, 3], [/\b(?:console\.log|document\.|window\.|require\()|\bmodule\.exports\b/, 3]])
|
|
84
|
+
}, {
|
|
85
|
+
language: 'python',
|
|
86
|
+
score: scorePatterns(code, [[/^\s*def\s+[a-zA-Z_]\w*\([^)]*\)\s*:/m, 5], [/^\s*class\s+[A-Z_]\w*(?:\([^)]*\))?\s*:/m, 4], [/^\s*(?:from\s+[\w.]+\s+import\s+\w+|import\s+[\w.]+)/m, 3], [/^\s*(?:if|elif|else|for|while|try|except)\b[^\n]*:\s*$/m, 2], [/\bprint\([^)]*\)/, 2]])
|
|
87
|
+
}, {
|
|
88
|
+
language: 'java',
|
|
89
|
+
score: scorePatterns(code, [[/\bpublic\s+(?:final\s+)?class\s+[A-Z]\w*/, 5], [/\bpublic\s+static\s+void\s+main\s*\(\s*String\[\]/, 5], [/\bSystem\.out\.println\s*\(/, 4], [/\b(?:private|protected|public)\s+(?:static\s+)?(?:final\s+)?[A-Z]\w*(?:<[^>]+>)?\s+\w+\s*[;(=]/, 3]])
|
|
90
|
+
}, {
|
|
91
|
+
language: 'go',
|
|
92
|
+
score: scorePatterns(code, [[/^\s*package\s+\w+/m, 5], [/\bfunc\s+(?:\([^)]*\)\s*)?[A-Za-z_]\w*\s*\([^)]*\)\s*(?:[A-Za-z_*\[\]]+\s*)?\{/, 5], [/\bfmt\.(?:Println|Printf)\s*\(/, 3], [/\bimport\s+\(\s*[\s\S]*?\)/, 2]])
|
|
93
|
+
}, {
|
|
94
|
+
language: 'ruby',
|
|
95
|
+
score: scorePatterns(code, [[/^\s*def\s+[a-z_]\w*[!?=]?/m, 4], [/^\s*class\s+[A-Z]\w*(?:\s*<\s*[A-Z]\w*)?/m, 3], [/^\s*end\s*$/m, 3], [/\b(?:puts|require|attr_reader|attr_accessor)\b/, 3], [/\bdo\s*\|[^|]+\|/, 2]])
|
|
96
|
+
}, {
|
|
97
|
+
language: 'rust',
|
|
98
|
+
score: scorePatterns(code, [[/\bfn\s+[a-z_]\w*\s*\([^)]*\)\s*(?:->\s*[A-Za-z_:<>]+\s*)?\{/, 5], [/\blet\s+mut\s+\w+/, 3], [/\bprintln!\s*\(/, 4], [/\buse\s+(?:std|crate|super)::/, 3], [/\b(?:impl|pub\s+struct|enum)\s+[A-Z]\w*/, 3]])
|
|
99
|
+
}, {
|
|
100
|
+
language: 'shell',
|
|
101
|
+
score: scorePatterns(code, [[/^#!\/usr\/bin\/(?:env\s+)?(?:ba|z|k)?sh\b/m, 6], [/^\s*(?:if|for|while)\b[\s\S]+\b(?:then|do)\b/m, 4], [/^\s*(?:fi|done)\s*$/m, 3], [/\b(?:echo|export|cd|grep|sed|awk|curl)\b[\s\S]*(?:\$\w+|&&|\|)/, 3], [/\$\{?[A-Z_][A-Z0-9_]*\}?/, 2]])
|
|
102
|
+
}];
|
|
103
|
+
};
|
|
104
|
+
var detectLanguage = exports.detectLanguage = function detectLanguage(code) {
|
|
105
|
+
var trimmedCode = code.trim();
|
|
106
|
+
if (trimmedCode.length < 8) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
var codeForDetection = trimmedCode.slice(0, MAX_DETECTION_CHARS);
|
|
110
|
+
var _getLanguageScores$fi = getLanguageScores(codeForDetection).filter(function (_ref3) {
|
|
111
|
+
var score = _ref3.score;
|
|
112
|
+
return score > 0;
|
|
113
|
+
}).sort(function (a, b) {
|
|
114
|
+
return b.score - a.score;
|
|
115
|
+
}),
|
|
116
|
+
_getLanguageScores$fi2 = (0, _slicedToArray2.default)(_getLanguageScores$fi, 2),
|
|
117
|
+
best = _getLanguageScores$fi2[0],
|
|
118
|
+
secondBest = _getLanguageScores$fi2[1];
|
|
119
|
+
if (!best || best.score < MIN_DETECTION_SCORE) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
if (secondBest && best.score - secondBest.score < MIN_SCORE_GAP) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return best.language;
|
|
126
|
+
};
|
|
@@ -8,6 +8,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
8
8
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
9
9
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
10
10
|
import { createInsertCodeBlockTransaction, insertCodeBlockWithAnalytics } from './editor-commands';
|
|
11
|
+
import { createAutoDetectPlugin } from './pm-plugins/auto-detect';
|
|
11
12
|
import { codeBlockAutoFullStopTransformPlugin } from './pm-plugins/codeBlockAutoFullStopTransformPlugin';
|
|
12
13
|
import { codeBlockCopySelectionPlugin, copySelectionPluginKey } from './pm-plugins/codeBlockCopySelectionPlugin';
|
|
13
14
|
import ideUX from './pm-plugins/ide-ux';
|
|
@@ -73,7 +74,10 @@ const codeBlockPlugin = ({
|
|
|
73
74
|
var _api$analytics;
|
|
74
75
|
return createCodeBlockInputRule(schema, api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
|
|
75
76
|
}
|
|
76
|
-
}, {
|
|
77
|
+
}, ...(expValEquals('platform_editor_code_block_auto_detection', 'isEnabled', true) ? [{
|
|
78
|
+
name: 'codeBlockAutoDetect',
|
|
79
|
+
plugin: () => createAutoDetectPlugin(api)
|
|
80
|
+
}] : []), {
|
|
77
81
|
name: 'codeBlockIDEKeyBindings',
|
|
78
82
|
plugin: () => ideUX(api)
|
|
79
83
|
}, {
|
|
@@ -9,9 +9,11 @@ import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
|
9
9
|
import { findParentNodeOfType, findSelectedNodeOfType, isNodeSelection, removeParentNodeOfType, removeSelectedNode, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
10
10
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
11
11
|
import { ACTIONS } from '../pm-plugins/actions';
|
|
12
|
+
import { autoDetectPluginKey } from '../pm-plugins/auto-detect-state';
|
|
12
13
|
import { copySelectionPluginKey } from '../pm-plugins/codeBlockCopySelectionPlugin';
|
|
13
14
|
import { pluginKey } from '../pm-plugins/plugin-key';
|
|
14
15
|
import { transformToCodeBlockAction } from '../pm-plugins/transform-to-code-block';
|
|
16
|
+
import { createAutoDetectEntry, getLocalId, hasEnoughTextForAutoDetection } from '../utils/auto-detect-state';
|
|
15
17
|
export const removeCodeBlockWithAnalytics = editorAnalyticsAPI => {
|
|
16
18
|
return withAnalytics(editorAnalyticsAPI, {
|
|
17
19
|
action: ACTION.DELETED,
|
|
@@ -41,7 +43,7 @@ export const removeCodeBlock = (state, dispatch) => {
|
|
|
41
43
|
return true;
|
|
42
44
|
};
|
|
43
45
|
export const changeLanguage = editorAnalyticsAPI => (language, selectionSource) => (state, dispatch) => {
|
|
44
|
-
var _pluginKey$getState
|
|
46
|
+
var _pluginKey$getState, _autoDetectPluginKey$;
|
|
45
47
|
const {
|
|
46
48
|
codeBlock
|
|
47
49
|
} = state.schema.nodes;
|
|
@@ -50,10 +52,20 @@ export const changeLanguage = editorAnalyticsAPI => (language, selectionSource)
|
|
|
50
52
|
return false;
|
|
51
53
|
}
|
|
52
54
|
const node = state.doc.nodeAt(pos);
|
|
55
|
+
const localId = node === null || node === void 0 ? void 0 : node.attrs.localId;
|
|
56
|
+
const previousAutoDetectEntry = expValEquals('platform_editor_code_block_auto_detection', 'isEnabled', true) ? (_autoDetectPluginKey$ = autoDetectPluginKey.getState(state)) === null || _autoDetectPluginKey$ === void 0 ? void 0 : _autoDetectPluginKey$.languageDetectionMap[localId] : undefined;
|
|
53
57
|
const tr = state.tr.setNodeMarkup(pos, codeBlock, {
|
|
54
58
|
...(node === null || node === void 0 ? void 0 : node.attrs),
|
|
55
59
|
language
|
|
56
60
|
}).setMeta('scrollIntoView', false);
|
|
61
|
+
if (expValEquals('platform_editor_code_block_auto_detection', 'isEnabled', true)) {
|
|
62
|
+
tr.setMeta(autoDetectPluginKey, {
|
|
63
|
+
type: ACTIONS.REMOVE_AUTO_DETECT_ENTRY,
|
|
64
|
+
data: {
|
|
65
|
+
localId
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
57
69
|
const selection = isNodeSelection(state.selection) ? NodeSelection.create(tr.doc, pos) : tr.selection;
|
|
58
70
|
const result = tr.setSelection(selection);
|
|
59
71
|
if (dispatch) {
|
|
@@ -64,7 +76,9 @@ export const changeLanguage = editorAnalyticsAPI => (language, selectionSource)
|
|
|
64
76
|
language: language !== null && language !== void 0 ? language : 'none',
|
|
65
77
|
...(selectionSource ? {
|
|
66
78
|
selectionSource
|
|
67
|
-
} : {})
|
|
79
|
+
} : {}),
|
|
80
|
+
autoDetectionResult: previousAutoDetectEntry === null || previousAutoDetectEntry === void 0 ? void 0 : previousAutoDetectEntry.detectionResult,
|
|
81
|
+
autoDetectedLanguage: previousAutoDetectEntry === null || previousAutoDetectEntry === void 0 ? void 0 : previousAutoDetectEntry.autoDetectedLanguage
|
|
68
82
|
},
|
|
69
83
|
eventType: EVENT_TYPE.TRACK
|
|
70
84
|
})(result);
|
|
@@ -72,6 +86,42 @@ export const changeLanguage = editorAnalyticsAPI => (language, selectionSource)
|
|
|
72
86
|
}
|
|
73
87
|
return true;
|
|
74
88
|
};
|
|
89
|
+
|
|
90
|
+
/** Queue auto-detection for selected code block. */
|
|
91
|
+
export const detectLanguage = () => (state, dispatch) => {
|
|
92
|
+
var _pluginKey$getState2;
|
|
93
|
+
const pos = (_pluginKey$getState2 = pluginKey.getState(state)) === null || _pluginKey$getState2 === void 0 ? void 0 : _pluginKey$getState2.pos;
|
|
94
|
+
if (typeof pos !== 'number') {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const node = state.doc.nodeAt(pos);
|
|
98
|
+
if (!node) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const localId = getLocalId(node);
|
|
102
|
+
if (!localId) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
const autoDetectState = autoDetectPluginKey.getState(state);
|
|
106
|
+
const previousEntry = autoDetectState === null || autoDetectState === void 0 ? void 0 : autoDetectState.languageDetectionMap[localId];
|
|
107
|
+
const entry = createAutoDetectEntry(node, pos, hasEnoughTextForAutoDetection(node.textContent), previousEntry);
|
|
108
|
+
const tr = state.tr.setNodeMarkup(pos, state.schema.nodes.codeBlock, {
|
|
109
|
+
...node.attrs,
|
|
110
|
+
language: null
|
|
111
|
+
}).setMeta(autoDetectPluginKey, {
|
|
112
|
+
type: ACTIONS.SET_AUTO_DETECT_ENTRY,
|
|
113
|
+
data: {
|
|
114
|
+
localId,
|
|
115
|
+
entry
|
|
116
|
+
}
|
|
117
|
+
}).setMeta('scrollIntoView', false);
|
|
118
|
+
const selection = isNodeSelection(state.selection) ? NodeSelection.create(tr.doc, pos) : tr.selection;
|
|
119
|
+
const result = tr.setSelection(selection);
|
|
120
|
+
if (dispatch) {
|
|
121
|
+
dispatch(result);
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
};
|
|
75
125
|
export const copyContentToClipboardWithAnalytics = editorAnalyticsAPI => (state, dispatch) => {
|
|
76
126
|
const {
|
|
77
127
|
schema: {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export const ACTIONS = {
|
|
2
2
|
SET_COPIED_TO_CLIPBOARD: 'SET_COPIED_TO_CLIPBOARD',
|
|
3
3
|
SET_SHOULD_IGNORE_FOLLOWING_MUTATIONS: 'SET_SHOULD_IGNORE_FOLLOWING_MUTATIONS',
|
|
4
|
-
SET_IS_WRAPPED: 'SET_IS_WRAPPED'
|
|
4
|
+
SET_IS_WRAPPED: 'SET_IS_WRAPPED',
|
|
5
|
+
SET_AUTO_DETECT_ENTRY: 'SET_AUTO_DETECT_ENTRY',
|
|
6
|
+
REMOVE_AUTO_DETECT_ENTRY: 'REMOVE_AUTO_DETECT_ENTRY'
|
|
5
7
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
|
+
import { removeAutoDetection, updateAutoDetectState } from '../utils/auto-detect-state';
|
|
3
|
+
import { syncPendingDetectionTimers } from '../utils/auto-detect-view';
|
|
4
|
+
import { ACTIONS } from './actions';
|
|
5
|
+
import { autoDetectPluginKey } from './auto-detect-state';
|
|
6
|
+
export const createAutoDetectPlugin = api => new SafePlugin({
|
|
7
|
+
key: autoDetectPluginKey,
|
|
8
|
+
state: {
|
|
9
|
+
init() {
|
|
10
|
+
return {
|
|
11
|
+
languageDetectionMap: {}
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
apply(tr, pluginState) {
|
|
15
|
+
const meta = tr.getMeta(autoDetectPluginKey);
|
|
16
|
+
let languageDetectionMap = tr.docChanged ? updateAutoDetectState(tr, pluginState) : pluginState.languageDetectionMap;
|
|
17
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.type) === ACTIONS.SET_AUTO_DETECT_ENTRY) {
|
|
18
|
+
languageDetectionMap = {
|
|
19
|
+
...languageDetectionMap,
|
|
20
|
+
[meta.data.localId]: meta.data.entry
|
|
21
|
+
};
|
|
22
|
+
} else if ((meta === null || meta === void 0 ? void 0 : meta.type) === ACTIONS.REMOVE_AUTO_DETECT_ENTRY) {
|
|
23
|
+
languageDetectionMap = removeAutoDetection(languageDetectionMap, meta.data.localId);
|
|
24
|
+
}
|
|
25
|
+
if (languageDetectionMap === pluginState.languageDetectionMap) {
|
|
26
|
+
return pluginState;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
languageDetectionMap
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
view(view) {
|
|
34
|
+
const timers = new Map();
|
|
35
|
+
return {
|
|
36
|
+
update() {
|
|
37
|
+
syncPendingDetectionTimers(view, timers, api);
|
|
38
|
+
},
|
|
39
|
+
destroy() {
|
|
40
|
+
timers.forEach(({
|
|
41
|
+
timer
|
|
42
|
+
}) => clearTimeout(timer));
|
|
43
|
+
timers.clear();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
@@ -97,11 +97,11 @@ export const createPlugin = ({
|
|
|
97
97
|
}
|
|
98
98
|
if (tr.docChanged) {
|
|
99
99
|
const node = findCodeBlock(newState, tr.selection);
|
|
100
|
+
const codeBlockNodes = getAllChangedCodeBlocksInTransaction(tr);
|
|
100
101
|
|
|
101
102
|
// Updates mapping position of all existing decorations to new positions
|
|
102
103
|
// specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
|
|
103
104
|
let updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
|
|
104
|
-
const codeBlockNodes = getAllChangedCodeBlocksInTransaction(tr);
|
|
105
105
|
if (codeBlockNodes) {
|
|
106
106
|
updateCodeBlockWrappedStateNodeKeys(codeBlockNodes, _oldState);
|
|
107
107
|
// Disabled when using advanced code block for performance reasons
|