forked from apense/NimKate
-
Notifications
You must be signed in to change notification settings - Fork 1
/
nim.js
174 lines (154 loc) · 5.42 KB
/
nim.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
172
173
174
var katescript = {
"name": "Nim",
"type": "indentation",
"author": "Paul Giannaros <paul@giannaros.org>, Gerald Senarclens de Grancy <oss@senarclens.eu>, Flaviu Tamas <tamas.flaviu@gmail.com>",
"license": "LGPL",
"revision": 4,
"kate-version": "5.1",
"indent-languages": ["Nim"],
"priority": 0
};
/*
* Note: Unlike everything else, this is licenced under the LGPL
*/
// required katepart js libraries
require ("range.js");
require ("string.js");
openings = ['(', '[', '{'];
closings = [')', ']', '}']; // requires same order as in openings
indenters = [/:$/,
/=\s*(object|enum|generic.*)?$/,
/(type|var|let|const)$/i]
unindenters = [/continue/i,
/raise/i,
/return/i,
/break/i];
// Return the given line without comments and leading or trailing whitespace.
// Eg.
// getCode(x) -> "for i in range(3):"
// if document.line(x) == " for i in range(3):"
// getCode(x) -> "for i in range(3):"
// if document.line(x) == "for i in range(3): "
// getCode(x) -> "for i in range(3):"
// if document.line(x) == "for i in range(3): # grand"
function getCode(lineNr) {
var line = document.line(lineNr);
var code = '';
for (var position = 0; position < line.length; position++)
if (document.isCode(lineNr, position) || line[position] == '=')
code += line[position];
return code.trim();
}
// Return the indent if a opening bracket is not closed (incomplete sequence).
// The calculated intent is the innermost opening bracket's position plus 1.
// `lineNr`: the number of the line on which the brackets should be counted
function _calcOpeningIndent(lineNr) {
var line = document.line(lineNr);
var countClosing = new Array();
closings.forEach(function(elem) {
countClosing[elem] = 0;
});
for (i = line.length - 1; i >= 0; --i) {
if (document.isComment(lineNr, i) || document.isString(lineNr, i))
continue;
if (closings.indexOf(line[i]) > -1)
countClosing[line[i]]++;
var index = openings.indexOf(line[i]);
if (index > -1) {
if (countClosing[closings[index]] == 0) {
return i + 1;
}
countClosing[closings[index]]--;
}
}
return -1;
}
// Return the indent if a closing bracket not opened (incomplete sequence).
// The intent is the same as on the line with the unmatched opening bracket.
// `lineNr`: the number of the line on which the brackets should be counted
function _calcClosingIndent(lineNr, indentWidth) {
var line = document.line(lineNr);
var countClosing = new Array();
closings.forEach(function(elem) {
countClosing[elem] = 0;
});
for (i = line.length - 1; i >= 0; --i) {
if (document.isComment(lineNr, i) || document.isString(lineNr, i))
continue;
if (closings.indexOf(line[i]) > -1)
countClosing[line[i]]++;
var index = openings.indexOf(line[i]);
if (index > -1)
countClosing[closings[index]]--;
}
for (var key in countClosing) {
if (countClosing[key] > 0) { // unmatched closing bracket
for (--lineNr; lineNr >= 0; --lineNr) {
if (_calcOpeningIndent(lineNr) > -1) {
var indent = document.firstVirtualColumn(lineNr);
if (shouldUnindent(lineNr + 1))
return Math.max(0, indent - indentWidth);
return indent;
}
}
}
}
return -1;
}
// Returns the indent for mismatched (opening or closing) brackets.
// If there are no mismatched brackets, -1 is returned.
// `lineNr`: number of the line for which the indent is calculated
function calcBracketIndent(lineNr, indentWidth) {
var indent = _calcOpeningIndent(lineNr - 1);
if (indent > -1)
return indent
indent = _calcClosingIndent(lineNr - 1, indentWidth);
if (indent > -1)
return indent
return -1;
}
// Return true if a single unindent should occur.
function shouldUnindent(LineNr) {
lastLine = getCode(LineNr - 1);
for (var i = 0; i < unindenters.length; i++)
if (lastLine.search(unindenters[i]) >= 0)
return true;
return false;
}
function shouldIndent(LineNr) {
lastLine = getCode(LineNr - 1);
for (var i = 0; i < indenters.length; i++)
if (lastLine.search(indenters[i]) >= 0)
return true;
return false;
}
// Return the amount of characters (in spaces) to be indented.
// Special indent() return values:
// -2 = no indent
// -1 = keep last indent
// Follow PEP8 for unfinished sequences and argument lists.
// Nested sequences are not implemented. (neither by Emacs' python-mode)
function indent(line, indentWidth, character) {
if (line == 0) // don't ever act on document's first line
return -2;
if (!document.line(line - 1).length) // empty line
return -2;
var lastLine = getCode(line - 1);
var lastChar = lastLine.substr(-1);
// indent when opening bracket
if (openings.indexOf(lastChar) >= 0) {
return document.firstVirtualColumn(line - 1) + indentWidth;
}
var indent = calcBracketIndent(line, indentWidth);
if (shouldIndent(line)) {
if (indent > -1)
indent += indentWidth;
else
indent = document.firstVirtualColumn(line - 1) + indentWidth;
}
// continue, pass, raise, return etc. should unindent
if (shouldUnindent(line) && (indent == -1))
indent = Math.max(0, document.firstVirtualColumn(line - 1) - indentWidth);
return indent;
}
// kate: space-indent on; indent-width 4; replace-tabs on;