Skip to content

Commit 3df470a

Browse files
committed
[python mode] Improve handling of indentation in bracketed code
Closes codemirror#3797 Closes codemirror#3794
1 parent a491854 commit 3df470a

File tree

1 file changed

+32
-31
lines changed

1 file changed

+32
-31
lines changed

mode/python/python.js

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=|\-=|\*=|%=|\/=|&=|\|=|\^=)/;
5454
var tripleDelimiters = parserConf.tripleDelimiters || /^(\/\/=|>>=|<<=|\*\*=)/;
5555

56-
if (parserConf.version && parseInt(parserConf.version, 10) == 3){
56+
if (parserConf.version && parseInt(parserConf.version, 10) == 3) {
5757
// since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator
5858
var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!@]/;
5959
var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/;
@@ -65,12 +65,12 @@
6565
var hangingIndent = parserConf.hangingIndent || conf.indentUnit;
6666

6767
var myKeywords = commonKeywords, myBuiltins = commonBuiltins;
68-
if(parserConf.extra_keywords != undefined){
68+
if (parserConf.extra_keywords != undefined)
6969
myKeywords = myKeywords.concat(parserConf.extra_keywords);
70-
}
71-
if(parserConf.extra_builtins != undefined){
70+
71+
if (parserConf.extra_builtins != undefined)
7272
myBuiltins = myBuiltins.concat(parserConf.extra_builtins);
73-
}
73+
7474
if (parserConf.version && parseInt(parserConf.version, 10) == 3) {
7575
myKeywords = myKeywords.concat(py3.keywords);
7676
myBuiltins = myBuiltins.concat(py3.builtins);
@@ -87,11 +87,12 @@
8787
function tokenBase(stream, state) {
8888
// Handle scope changes
8989
if (stream.sol() && top(state).type == "py") {
90+
state.indent = stream.indentation()
9091
var scopeOffset = top(state).offset;
9192
if (stream.eatSpace()) {
9293
var lineOffset = stream.indentation();
9394
if (lineOffset > scopeOffset)
94-
pushScope(stream, state, "py");
95+
pushPyScope(state);
9596
else if (lineOffset < scopeOffset && dedent(stream, state))
9697
state.errorToken = true;
9798
return null;
@@ -224,16 +225,18 @@
224225
return tokenString;
225226
}
226227

227-
function pushScope(stream, state, type) {
228-
var offset = 0, align = null;
229-
if (type == "py") {
230-
while (top(state).type != "py")
231-
state.scopes.pop();
232-
}
233-
offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingIndent);
234-
if (type != "py" && !stream.match(/^(\s|#.*)*$/, false))
235-
align = stream.column() + 1;
236-
state.scopes.push({offset: offset, type: type, align: align});
228+
function pushPyScope(state) {
229+
while (top(state).type != "py") state.scopes.pop()
230+
state.scopes.push({offset: top(state).offset + conf.indentUnit,
231+
type: "py",
232+
align: null})
233+
}
234+
235+
function pushBracketScope(stream, state, type) {
236+
var align = stream.match(/^([\s\[\{\(]|#.*)*$/, false) ? null : stream.column() + 1
237+
state.scopes.push({offset: state.indent + hangingIndent,
238+
type: type,
239+
align: align})
237240
}
238241

239242
function dedent(stream, state) {
@@ -250,12 +253,11 @@
250253
var current = stream.current();
251254

252255
// Handle decorators
253-
if (current == "@"){
254-
if(parserConf.version && parseInt(parserConf.version, 10) == 3){
255-
return stream.match(identifiers, false) ? "meta" : "operator";
256-
} else {
257-
return stream.match(identifiers, false) ? "meta" : ERRORCLASS;
258-
}
256+
if (current == "@") {
257+
if (parserConf.version && parseInt(parserConf.version, 10) == 3)
258+
return stream.match(identifiers, false) ? "meta" : "operator";
259+
else
260+
return stream.match(identifiers, false) ? "meta" : ERRORCLASS;
259261
}
260262

261263
if ((style == "variable" || style == "builtin")
@@ -268,15 +270,15 @@
268270

269271
if (current == "lambda") state.lambda = true;
270272
if (current == ":" && !state.lambda && top(state).type == "py")
271-
pushScope(stream, state, "py");
273+
pushPyScope(state);
272274

273275
var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1;
274276
if (delimiter_index != -1)
275-
pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
277+
pushBracketScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1));
276278

277279
delimiter_index = "])}".indexOf(current);
278280
if (delimiter_index != -1) {
279-
if (top(state).type == current) state.scopes.pop();
281+
if (top(state).type == current) state.indent = state.scopes.pop().offset - hangingIndent
280282
else return ERRORCLASS;
281283
}
282284
if (state.dedent > 0 && stream.eol() && top(state).type == "py") {
@@ -292,6 +294,7 @@
292294
return {
293295
tokenize: tokenBase,
294296
scopes: [{offset: basecolumn || 0, type: "py", align: null}],
297+
indent: basecolumn || 0,
295298
lastToken: null,
296299
lambda: false,
297300
dedent: 0
@@ -316,16 +319,14 @@
316319
if (state.tokenize != tokenBase)
317320
return state.tokenize.isString ? CodeMirror.Pass : 0;
318321

319-
var scope = top(state);
320-
var closing = textAfter && textAfter.charAt(0) == scope.type;
322+
var scope = top(state), closing = scope.type == textAfter.charAt(0)
321323
if (scope.align != null)
322-
return scope.align - (closing ? 1 : 0);
323-
else if (closing && state.scopes.length > 1)
324-
return state.scopes[state.scopes.length - 2].offset;
324+
return scope.align - (closing ? 1 : 0)
325325
else
326-
return scope.offset;
326+
return scope.offset - (closing ? hangingIndent : 0)
327327
},
328328

329+
electricInput: /^\s*[\}\]\)]$/,
329330
closeBrackets: {triples: "'\""},
330331
lineComment: "#",
331332
fold: "indent"

0 commit comments

Comments
 (0)