Skip to content

Commit

Permalink
folding for php alternative syntax (#5491)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkslanc authored Mar 27, 2024
1 parent a66f861 commit 2e40702
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 3 deletions.
127 changes: 127 additions & 0 deletions src/mode/folding/php.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"use strict";

var oop = require("../../lib/oop");
var MixedFoldMode = require("./mixed").FoldMode;
var CstyleFoldMode = require("./cstyle").FoldMode;
var Range = require("../../range").Range;
var TokenIterator = require("../../token_iterator").TokenIterator;


var FoldMode = exports.FoldMode = function () {
this.cstyleFoldMode = new CstyleFoldMode();
MixedFoldMode.call(this, this, {
"js-": new CstyleFoldMode(),
"css-": new CstyleFoldMode(),
"php-": this
});
};

oop.inherits(FoldMode, MixedFoldMode);

(function () {
this.indentKeywords = {
"if": 1,
"while": 1,
"for": 1,
"foreach": 1,
"switch": 1,
"else": 0,
"elseif": 0,
"endif": -1,
"endwhile": -1,
"endfor": -1,
"endforeach": -1,
"endswitch": -1
};

this.foldingStartMarker = /(?:\s|^)(if|else|elseif|while|for|foreach|switch).*\:/i;
this.foldingStopMarker = /(?:\s|^)(endif|endwhile|endfor|endforeach|endswitch)\;/i;

this.getFoldWidgetRange = function (session, foldStyle, row) {
var line = session.doc.getLine(row);
var match = this.foldingStartMarker.exec(line);
if (match) {
return this.phpBlock(session, row, match.index + 2);
}

var match = this.foldingStopMarker.exec(line);
if (match) {
return this.phpBlock(session, row, match.index + 2);
}
return this.cstyleFoldMode.getFoldWidgetRange(session, foldStyle, row);
};


// must return "" if there's no fold, to enable caching
this.getFoldWidget = function (session, foldStyle, row) {
var line = session.getLine(row);
var isStart = this.foldingStartMarker.test(line);
var isEnd = this.foldingStopMarker.test(line);
if (isStart && !isEnd) {
var match = this.foldingStartMarker.exec(line);
var keyword = match && match[1].toLowerCase();
if (keyword) {
var type = session.getTokenAt(row, match.index + 2).type;
if (type == "keyword") {
return "start";
}
}
}
if (isEnd && foldStyle === "markbeginend") {
var match = this.foldingStopMarker.exec(line);
var keyword = match && match[1].toLowerCase();
if (keyword) {
var type = session.getTokenAt(row, match.index + 2).type;
if (type == "keyword") {
return "end";
}
}
}
return this.cstyleFoldMode.getFoldWidget(session, foldStyle, row);
};

this.phpBlock = function (session, row, column, tokenRange) {
var stream = new TokenIterator(session, row, column);

var token = stream.getCurrentToken();
if (!token || token.type != "keyword") return;

var val = token.value;
var stack = [val];
var dir = this.indentKeywords[val];

if (val === "else" || val === "elseif") {
dir = 1;
}

if (!dir) return;

var startColumn = dir === -1 ? stream.getCurrentTokenColumn() : session.getLine(row).length;
var startRow = row;

stream.step = dir === -1 ? stream.stepBackward : stream.stepForward;
while (token = stream.step()) {
if (token.type !== "keyword") continue;
var level = dir * this.indentKeywords[token.value];

if (level > 0) {
stack.unshift(token.value);
}
else if (level <= 0) {
stack.shift();
if (!stack.length) break;
if (level === 0) stack.unshift(token.value);
}
}

if (!token) return null;

if (tokenRange) return stream.getCurrentTokenRange();

var row = stream.getCurrentTokenRow();
if (dir === -1) return new Range(
row, session.getLine(row).length, startRow, startColumn); else return new Range(
startRow, startColumn, row, stream.getCurrentTokenColumn());
};

}).call(FoldMode.prototype);
57 changes: 57 additions & 0 deletions src/mode/folding/php_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
if (typeof process !== "undefined") require("amd-loader");

"use strict";

var PHPMode = require("../php").Mode;
var EditSession = require("../../edit_session").EditSession;
var assert = require("../../test/assertions");

module.exports = {
setUp: function () {
this.mode = new PHPMode();
},

"test: php folding with alternative syntax": function () {
var session = new EditSession([
'<?php', 'function checkNumber($number)', '{', ' switch ($number) {', ' case 0:',
' echo "Number is zero again";', ' if ($number == 0):',
' echo "Number is zero";', ' elseif ($number > 0):',
' echo "Number is positive";', ' else:',
' echo "Number is negative";', 'endif;', ' break;', ' default:',
' echo "Number is not zero";', ' }', 'foreach (array(1, 2, 3) as $num):',
' echo "Num: $num";', ' endforeach;', '}', '?>'
]);

session.setFoldStyle("markbeginend");
session.setMode(this.mode);
session.bgTokenizer.$worker();

assert.equal(session.getFoldWidget(0), "");
assert.equal(session.getFoldWidget(1), "");
assert.equal(session.getFoldWidget(2), "start");
assert.equal(session.getFoldWidget(3), "start");
assert.equal(session.getFoldWidget(4), "");
assert.equal(session.getFoldWidget(5), "");
assert.equal(session.getFoldWidget(6), "start");
assert.equal(session.getFoldWidget(7), "");
assert.equal(session.getFoldWidget(8), "start");
assert.equal(session.getFoldWidget(10), "start");
assert.equal(session.getFoldWidget(12), "end");
assert.equal(session.getFoldWidget(16), "end");
assert.equal(session.getFoldWidget(17), "start");
assert.equal(session.getFoldWidget(19), "end");
assert.equal(session.getFoldWidget(20), "end");

assert.range(session.getFoldWidgetRange(2), 2, 1, 20, 0); // Range for the function's foldable section
assert.range(session.getFoldWidgetRange(3), 3, 21, 16, 7); // Range for the 'switch' statement
assert.range(session.getFoldWidgetRange(6), 6, 29, 8, 11); // Range for the 'if' block
assert.range(session.getFoldWidgetRange(8), 8, 32, 10, 11); // Range for the 'elseif' block
assert.range(session.getFoldWidgetRange(10), 10, 16, 12, 0); // Range for the 'else' block
assert.range(session.getFoldWidgetRange(12), 10, 16, 12, 0); // Range for the 'endif' line
assert.range(session.getFoldWidgetRange(17), 17, 33, 19, 3);
assert.range(session.getFoldWidgetRange(19), 17, 33, 19, 3);
}
};


if (typeof module !== "undefined" && module === require.main) require("asyncjs").test.testcase(module.exports).exec();
6 changes: 3 additions & 3 deletions src/mode/php.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var PhpLangHighlightRules = require("./php_highlight_rules").PhpLangHighlightRul
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var WorkerClient = require("../worker/worker_client").WorkerClient;
var PhpCompletions = require("./php_completions").PhpCompletions;
var CStyleFoldMode = require("./folding/cstyle").FoldMode;
var PhpFoldMode = require("./folding/php").FoldMode;
var unicode = require("../unicode");
var HtmlMode = require("./html").Mode;
var JavaScriptMode = require("./javascript").Mode;
Expand All @@ -18,7 +18,7 @@ var PhpMode = function(opts) {
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = this.$defaultBehaviour;
this.$completer = new PhpCompletions();
this.foldingRules = new CStyleFoldMode();
this.foldingRules = new PhpFoldMode();
};
oop.inherits(PhpMode, TextMode);

Expand Down Expand Up @@ -91,7 +91,7 @@ var Mode = function(opts) {
"css-": CssMode,
"php-": PhpMode
});
this.foldingRules.subModes["php-"] = new CStyleFoldMode();
this.foldingRules = new PhpFoldMode();
};
oop.inherits(Mode, HtmlMode);

Expand Down

2 comments on commit 2e40702

@Syone
Copy link

@Syone Syone commented on 2e40702 May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HI @mkslanc I've opened an issue about this change: #5547
We can fold php alternative syntax now, it's cool but we can't fold html tags anymore

@mkslanc
Copy link
Contributor Author

@mkslanc mkslanc commented on 2e40702 May 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HI @mkslanc I've opened an issue about this change: #5547 We can fold php alternative syntax now, it's cool but we can't fold html tags anymore

Hi @Syone , good catch! I will push the fix ASAP

Please sign in to comment.