@ohos-ports/codemirror-formatting 1.0.0-beta.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/README.md +3 -0
- package/bower.json +16 -0
- package/formatting.js +121 -0
- package/ohos-loader.js +105 -0
- package/package.json +31 -0
package/README.md
ADDED
package/bower.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codemirror-formatting",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"main": ["formatting.js"],
|
|
5
|
+
"ignore": [
|
|
6
|
+
"**/.*",
|
|
7
|
+
"*.yml",
|
|
8
|
+
"node_modules",
|
|
9
|
+
"bower_components",
|
|
10
|
+
"test",
|
|
11
|
+
"tests"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"codemirror": ">= 4.3.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
package/formatting.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
(function(mod) {
|
|
2
|
+
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
3
|
+
mod(require("codemirror/lib/codemirror"));
|
|
4
|
+
else if (typeof define == "function" && define.amd) // AMD
|
|
5
|
+
define(["codemirror/lib/codemirror"], mod);
|
|
6
|
+
else // Plain browser env
|
|
7
|
+
mod(CodeMirror);
|
|
8
|
+
})(function(CodeMirror) {
|
|
9
|
+
|
|
10
|
+
CodeMirror.extendMode("css", {
|
|
11
|
+
commentStart: "/*",
|
|
12
|
+
commentEnd: "*/",
|
|
13
|
+
newlineAfterToken: function(_type, content) {
|
|
14
|
+
return /^[;{}]$/.test(content);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
CodeMirror.extendMode("javascript", {
|
|
19
|
+
commentStart: "/*",
|
|
20
|
+
commentEnd: "*/",
|
|
21
|
+
// FIXME semicolons inside of for
|
|
22
|
+
newlineAfterToken: function(_type, content, textAfter, state) {
|
|
23
|
+
if (this.jsonMode) {
|
|
24
|
+
return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
|
|
25
|
+
} else {
|
|
26
|
+
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
|
|
27
|
+
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/;
|
|
33
|
+
|
|
34
|
+
CodeMirror.extendMode("xml", {
|
|
35
|
+
commentStart: "<!--",
|
|
36
|
+
commentEnd: "-->",
|
|
37
|
+
newlineAfterToken: function(type, content, textAfter, state) {
|
|
38
|
+
var inline = false;
|
|
39
|
+
if (this.configuration == "html")
|
|
40
|
+
inline = state.context ? inlineElements.test(state.context.tagName) : false;
|
|
41
|
+
return !inline && ((type == "tag" && />$/.test(content) && state.context) ||
|
|
42
|
+
/^</.test(textAfter));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Comment/uncomment the specified range
|
|
47
|
+
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
|
|
48
|
+
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
|
|
49
|
+
cm.operation(function() {
|
|
50
|
+
if (isComment) { // Comment range
|
|
51
|
+
cm.replaceRange(curMode.commentEnd, to);
|
|
52
|
+
cm.replaceRange(curMode.commentStart, from);
|
|
53
|
+
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
|
|
54
|
+
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
|
|
55
|
+
} else { // Uncomment range
|
|
56
|
+
var selText = cm.getRange(from, to);
|
|
57
|
+
var startIndex = selText.indexOf(curMode.commentStart);
|
|
58
|
+
var endIndex = selText.lastIndexOf(curMode.commentEnd);
|
|
59
|
+
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
|
|
60
|
+
// Take string till comment start
|
|
61
|
+
selText = selText.substr(0, startIndex) +
|
|
62
|
+
// From comment start till comment end
|
|
63
|
+
selText.substring(startIndex + curMode.commentStart.length, endIndex) +
|
|
64
|
+
// From comment end till string end
|
|
65
|
+
selText.substr(endIndex + curMode.commentEnd.length);
|
|
66
|
+
}
|
|
67
|
+
cm.replaceRange(selText, from, to);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Applies automatic mode-aware indentation to the specified range
|
|
73
|
+
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
|
|
74
|
+
var cmInstance = this;
|
|
75
|
+
this.operation(function () {
|
|
76
|
+
for (var i = from.line; i <= to.line; i++) {
|
|
77
|
+
cmInstance.indentLine(i, "smart");
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Applies automatic formatting to the specified range
|
|
83
|
+
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
|
|
84
|
+
var cm = this;
|
|
85
|
+
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
|
|
86
|
+
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
|
|
87
|
+
var tabSize = cm.getOption("tabSize");
|
|
88
|
+
|
|
89
|
+
var out = "", lines = 0, atSol = from.ch === 0;
|
|
90
|
+
function newline() {
|
|
91
|
+
out += "\n";
|
|
92
|
+
atSol = true;
|
|
93
|
+
++lines;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (var i = 0; i < text.length; ++i) {
|
|
97
|
+
var stream = new CodeMirror.StringStream(text[i], tabSize);
|
|
98
|
+
while (!stream.eol()) {
|
|
99
|
+
var inner = CodeMirror.innerMode(outer, state);
|
|
100
|
+
var style = outer.token(stream, state), cur = stream.current();
|
|
101
|
+
stream.start = stream.pos;
|
|
102
|
+
if (!atSol || /\S/.test(cur)) {
|
|
103
|
+
out += cur;
|
|
104
|
+
atSol = false;
|
|
105
|
+
}
|
|
106
|
+
if (!atSol && inner.mode.newlineAfterToken &&
|
|
107
|
+
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
|
|
108
|
+
newline();
|
|
109
|
+
}
|
|
110
|
+
if (!stream.pos && outer.blankLine) outer.blankLine(state);
|
|
111
|
+
if (!atSol && i < text.length - 1) newline();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
cm.operation(function () {
|
|
115
|
+
cm.replaceRange(out, from, to);
|
|
116
|
+
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
|
|
117
|
+
cm.indentLine(cur, "smart");
|
|
118
|
+
cm.setSelection(from, cm.getCursor(false));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
package/ohos-loader.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HarmonyOS DOM Environment Loader for codemirror-formatting
|
|
3
|
+
*
|
|
4
|
+
* CodeMirror 5.x requires browser DOM (document, window) to load.
|
|
5
|
+
* This loader sets up a jsdom environment before requiring codemirror
|
|
6
|
+
* and the formatting addon, making them usable on HarmonyOS Node.js.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* const CodeMirror = require('./ohos-loader.js');
|
|
10
|
+
* // CodeMirror is ready with formatting extensions registered
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { JSDOM } = require('jsdom');
|
|
14
|
+
|
|
15
|
+
// Create a minimal DOM environment
|
|
16
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body><textarea id="editor"></textarea></body></html>', {
|
|
17
|
+
url: 'http://localhost/',
|
|
18
|
+
pretendToBeVisual: true
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Install DOM globals required by CodeMirror 5.x
|
|
22
|
+
global.document = dom.window.document;
|
|
23
|
+
global.window = dom.window;
|
|
24
|
+
global.navigator = dom.window.navigator;
|
|
25
|
+
global.HTMLElement = dom.window.HTMLElement;
|
|
26
|
+
global.Node = dom.window.Node;
|
|
27
|
+
global.Element = dom.window.Element;
|
|
28
|
+
global.DocumentFragment = dom.window.DocumentFragment;
|
|
29
|
+
global.Range = dom.window.Range;
|
|
30
|
+
|
|
31
|
+
// CodeMirror needs requestAnimationFrame
|
|
32
|
+
if (!global.requestAnimationFrame) {
|
|
33
|
+
global.requestAnimationFrame = function(callback) {
|
|
34
|
+
return setTimeout(callback, 0);
|
|
35
|
+
};
|
|
36
|
+
global.cancelAnimationFrame = function(id) {
|
|
37
|
+
clearTimeout(id);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Polyfill getBoundingClientRect for Range objects (jsdom doesn't implement this)
|
|
42
|
+
const RangeProto = dom.window.Range.prototype;
|
|
43
|
+
if (!RangeProto.getBoundingClientRect || RangeProto.getBoundingClientRect === Object.prototype.getBoundingClientRect) {
|
|
44
|
+
RangeProto.getBoundingClientRect = function() {
|
|
45
|
+
return { top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0 };
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (!RangeProto.getClientRects) {
|
|
49
|
+
RangeProto.getClientRects = function() {
|
|
50
|
+
return [];
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Also override document.createRange to return polyfilled ranges
|
|
55
|
+
const origCreateRange = dom.window.document.createRange.bind(dom.window.document);
|
|
56
|
+
dom.window.document.createRange = function() {
|
|
57
|
+
const range = origCreateRange();
|
|
58
|
+
if (typeof range.getBoundingClientRect !== 'function' || range.getBoundingClientRect === Object.prototype.getBoundingClientRect) {
|
|
59
|
+
range.getBoundingClientRect = function() {
|
|
60
|
+
return { top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0 };
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (typeof range.getClientRects !== 'function' || range.getClientRects === Object.prototype.getClientRects) {
|
|
64
|
+
range.getClientRects = function() {
|
|
65
|
+
return [];
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return range;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Polyfill Element.getBoundingClientRect
|
|
72
|
+
const ElementProto = dom.window.Element.prototype;
|
|
73
|
+
if (!ElementProto.getBoundingClientRect || ElementProto.getBoundingClientRect === Object.prototype.getBoundingClientRect) {
|
|
74
|
+
ElementProto.getBoundingClientRect = function() {
|
|
75
|
+
return { top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0 };
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Polyfill getComputedStyle
|
|
80
|
+
if (!dom.window.getComputedStyle) {
|
|
81
|
+
dom.window.getComputedStyle = function(el) {
|
|
82
|
+
return {
|
|
83
|
+
getPropertyValue: function() { return ''; },
|
|
84
|
+
direction: 'ltr',
|
|
85
|
+
whiteSpace: 'pre'
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
global.getComputedStyle = dom.window.getComputedStyle.bind(dom.window);
|
|
90
|
+
|
|
91
|
+
// Load CodeMirror core in the DOM environment
|
|
92
|
+
const CodeMirror = require('codemirror/lib/codemirror');
|
|
93
|
+
|
|
94
|
+
// Load mode modules that the formatting addon extends
|
|
95
|
+
// These are required for commentRange, autoFormatRange, etc. to work
|
|
96
|
+
require('codemirror/mode/javascript/javascript');
|
|
97
|
+
require('codemirror/mode/css/css');
|
|
98
|
+
require('codemirror/mode/xml/xml');
|
|
99
|
+
|
|
100
|
+
// Load the formatting addon (extends CodeMirror with commentRange,
|
|
101
|
+
// autoIndentRange, autoFormatRange)
|
|
102
|
+
require('./formatting.js');
|
|
103
|
+
|
|
104
|
+
// Export the enhanced CodeMirror instance
|
|
105
|
+
module.exports = CodeMirror;
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ohos-ports/codemirror-formatting",
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"description": "Codemirror formatting addon http://codemirror.net/2/demo/formatting.html",
|
|
5
|
+
"main": "ohos-loader.js",
|
|
6
|
+
"directories": {
|
|
7
|
+
"test": "test"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/ohos-ports/ohos-ports.git",
|
|
15
|
+
"directory": "ports/codemirror-formatting/1.0.0"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"codemirror",
|
|
19
|
+
"formatting"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ohos-ports/ohos-ports/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/artf/codemirror-formatting#readme",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"codemirror": "^5.65.18",
|
|
29
|
+
"jsdom": "^30.1.0"
|
|
30
|
+
}
|
|
31
|
+
}
|