Skip to content

Commit 0495b09

Browse files
Merge pull request #273 from kzamanbd/blade-space
Add auto-space in blade syntax
2 parents 3f2d2ed + f075288 commit 0495b09

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@
110110
"default": true,
111111
"description": "Show popups for errors."
112112
},
113+
"Laravel.blade.autoSpaceTags": {
114+
"type": "boolean",
115+
"default": true,
116+
"description": "Automatically add spacing around Blade echo and comment tags."
117+
},
113118
"Laravel.appBinding.diagnostics": {
114119
"type": "boolean",
115120
"default": true,

src/blade/bladeSpacer.ts

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { config } from "@src/support/config";
2+
import {
3+
Position,
4+
Range,
5+
SnippetString,
6+
TextDocument,
7+
TextDocumentChangeEvent,
8+
TextDocumentContentChangeEvent,
9+
TextEditor,
10+
} from "vscode";
11+
12+
const TAG_DOUBLE = 0;
13+
const TAG_UNESCAPED = 1;
14+
const TAG_COMMENT = 2;
15+
16+
const snippets: Record<number, string> = {
17+
[TAG_DOUBLE]: "{{ ${1:${TM_SELECTED_TEXT/[{}]//g}} }}$0",
18+
[TAG_UNESCAPED]: "{!! ${1:${TM_SELECTED_TEXT/[{} !]//g}} !!}$0",
19+
[TAG_COMMENT]: "{{-- ${1:${TM_SELECTED_TEXT/(--)|[{} ]//g}} --}}$0",
20+
};
21+
22+
const triggers = ["{}", "!", "-", "{"];
23+
24+
const regexes = [
25+
/({{(?!\s|-))(.*?)(}})/,
26+
/({!!(?!\s))(.*?)?(}?)/,
27+
/({{[\s]?--)(.*?)?(}})/,
28+
];
29+
30+
const translate = (position: Position, offset: number) => {
31+
try {
32+
return position.translate(0, offset);
33+
} catch (error) {
34+
// VS Code doesn't like negative numbers passed
35+
// to translate (even though it works fine), so
36+
// this block prevents debug console errors
37+
}
38+
39+
return position;
40+
};
41+
42+
const charsForChange = (
43+
doc: TextDocument,
44+
change: TextDocumentContentChangeEvent,
45+
) => {
46+
if (change.text === "!") {
47+
return 2;
48+
}
49+
50+
if (change.text !== "-") {
51+
return 1;
52+
}
53+
54+
const start = translate(change.range.start, -2);
55+
const end = translate(change.range.start, -1);
56+
57+
return doc.getText(new Range(start, end)) === " " ? 4 : 3;
58+
};
59+
60+
export const bladeSpacer = async (
61+
e: TextDocumentChangeEvent,
62+
editor?: TextEditor,
63+
) => {
64+
if (
65+
!config("blade.autoSpaceTags", true) ||
66+
!editor ||
67+
editor.document.fileName.indexOf(".blade.php") === -1
68+
) {
69+
return;
70+
}
71+
72+
let tagType: number = -1;
73+
let ranges: Range[] = [];
74+
let offsets: number[] = [];
75+
76+
// Changes (per line) come in right-to-left when we need them left-to-right
77+
const changes = e.contentChanges.slice().reverse();
78+
79+
changes.forEach((change) => {
80+
if (triggers.indexOf(change.text) === -1) {
81+
return;
82+
}
83+
84+
if (!offsets[change.range.start.line]) {
85+
offsets[change.range.start.line] = 0;
86+
}
87+
88+
const startOffset =
89+
offsets[change.range.start.line] -
90+
charsForChange(e.document, change);
91+
92+
const start = translate(change.range.start, startOffset);
93+
const lineEnd = e.document.lineAt(start.line).range.end;
94+
95+
for (let i = 0; i < regexes.length; i++) {
96+
// If we typed a - or a !, don't consider the "double" tag type
97+
if (i === TAG_DOUBLE && ["-", "!"].indexOf(change.text) !== -1) {
98+
continue;
99+
}
100+
101+
// Only look at unescaped tags if we need to
102+
if (i === TAG_UNESCAPED && change.text !== "!") {
103+
continue;
104+
}
105+
106+
// Only look at comment tags if we need to
107+
if (i === TAG_COMMENT && change.text !== "-") {
108+
continue;
109+
}
110+
111+
const tag = regexes[i].exec(
112+
e.document.getText(new Range(start, lineEnd)),
113+
);
114+
115+
if (tag) {
116+
tagType = i;
117+
ranges.push(
118+
new Range(start, start.translate(0, tag[0].length)),
119+
);
120+
offsets[start.line] += tag[1].length;
121+
}
122+
}
123+
});
124+
125+
if (ranges.length > 0 && snippets[tagType]) {
126+
editor.insertSnippet(new SnippetString(snippets[tagType]), ranges);
127+
}
128+
};

src/extension.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { setParserBinaryPath } from "./support/parser";
2525
import { clearDefaultPhpCommand, initVendorWatchers } from "./support/php";
2626
import { hasWorkspace, projectPathExists } from "./support/project";
2727
import { cleanUpTemp } from "./support/util";
28+
import { bladeSpacer } from "./blade/bladeSpacer";
2829

2930
let client: LanguageClient;
3031

@@ -92,6 +93,9 @@ export function activate(context: vscode.ExtensionContext) {
9293
vscode.workspace.onDidSaveTextDocument((event) => {
9394
updateDiagnostics(vscode.window.activeTextEditor);
9495
}),
96+
vscode.workspace.onDidChangeTextDocument((event) => {
97+
bladeSpacer(event, vscode.window.activeTextEditor);
98+
}),
9599
// vscode.languages.registerDocumentHighlightProvider(
96100
// documentSelector,
97101
// new DocumentHighlight(),

src/support/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ type ConfigKey =
99
| "tests.docker.enabled"
1010
| "tests.ssh.enabled"
1111
| "tests.suiteSuffix"
12-
| "showErrorPopups";
12+
| "showErrorPopups"
13+
| "blade.autoSpaceTags";
1314

1415
export const config = <T>(key: ConfigKey, fallback: T): T =>
1516
vscode.workspace.getConfiguration("Laravel").get<T>(key, fallback);

0 commit comments

Comments
 (0)