Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Indent after oneCommandCode on comment, block comment, empty line. Formatting inside block comment. #164

Merged
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cb078d1
extract indentation chars and line code into separate functions
kyklish Jul 17, 2022
67d42bc
change in regex space char to space symbol
kyklish Jul 17, 2022
e4ae591
fix #119 issue with semicolon inside string (expression)
kyklish Jul 16, 2022
d78656d
fix code not indent after one command code
kyklish Jul 17, 2022
cf9bd12
extract save indented line code to buildIndentedLine() function
kyklish Jul 17, 2022
ddd1445
fix block comments not intend and not format
kyklish Jul 17, 2022
1049e33
Revert "fix #119 issue with semicolon inside string (expression)"
kyklish Jul 21, 2022
4a62944
trim purified line
kyklish Jul 21, 2022
e3394c0
add unit test files
kyklish Jul 21, 2022
6339e62
revert: do not change tabs to spaces
kyklish Jul 21, 2022
00503af
Merge remote-tracking branch 'ahk++/main' into fix-formatter-bug-onec…
kyklish Jul 21, 2022
14a8f6d
update 'ahk-ahk-explorer.out.ahk'
kyklish Jul 21, 2022
8690259
move functions to corresponding 'util' file
kyklish Jul 22, 2022
7ab8d69
rename variables
kyklish Jul 25, 2022
329c596
update unit test
kyklish Jul 25, 2022
9ff08de
add directive for formatter
kyklish Jul 31, 2022
1888cc5
comment
kyklish Jul 31, 2022
17a589d
add snippet
kyklish Jul 31, 2022
abd3c59
Merge remote-tracking branch 'ahk++/main' into fix-formatter-bug-onec…
kyklish Jul 31, 2022
609ebf2
fix wrong test files
kyklish Jul 31, 2022
88e565e
update ahk-ahk-explorer.out.ahk with fixed regression in block comment
kyklish Jul 31, 2022
60bb3c7
Apply suggestions from code review
kyklish Aug 14, 2022
d3a3936
Merge remote-tracking branch 'ahk++/main' into fix-formatter-bug-onec…
kyklish Aug 14, 2022
526cb70
ahk-explorer.out.ahk
kyklish Aug 14, 2022
0cce416
update README.md
kyklish Aug 14, 2022
5e2fa32
reorder start/stop position of directive
kyklish Aug 14, 2022
e7b4f74
Merge remote-tracking branch 'ahk++/main' into fix-formatter-bug-onec…
kyklish Aug 15, 2022
4a54b74
update ahk-explorer.out.ahk
kyklish Aug 15, 2022
5248089
add requested changes
kyklish Aug 15, 2022
c300a42
more tests
kyklish Aug 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ AHK++ is a fork of [AutoHotkey Plus by cweijan](https://github.com/AutoHotkey-Pl
- [Find References](#find-symbol-references)
- [Hover Tip](#hover-tip)
- [Code Format](#code-format)
- [Formatter Directives](#formatter-directives)
- [Credits](#credits)

## Why AutoHotkey Plus Plus?
Expand Down Expand Up @@ -111,6 +112,16 @@ Supports standard VS Code formatting.

![Code Format](image/codeFormat.jpg)

### Formatter Directives

```autohotkey
;@AHK++FormatBlockCommentOn
/*
;All text inside block comment will be formatted like regular code.
*/
;@AHK++FormatBlockCommentOff
```

## Credits

Previous extensions:
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@
{
"language": "ahk",
"path": "./snippets/ahk.json"
},
{
"language": "ahk",
"path": "./snippets/ahk++.json"
}
]
},
Expand Down
10 changes: 10 additions & 0 deletions snippets/ahk++.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"FormatBlockCommentOn": {
"prefix": "@AHK++FormatBlockCommentOn",
"body": ";@AHK++FormatBlockCommentOn"
},
"FormatBlockCommentOff": {
"prefix": "@AHK++FormatBlockCommentOff",
"body": ";@AHK++FormatBlockCommentOff"
}
}
131 changes: 110 additions & 21 deletions src/providers/formattingProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import { CodeUtil } from '../common/codeUtil';
import { ConfigKey, Global } from '../common/global';
import {
buildIndentedLine,
hasMoreCloseParens,
hasMoreOpenParens,
removeEmptyLines,
Expand Down Expand Up @@ -58,7 +59,21 @@ export class FormatProvider implements vscode.DocumentFormattingEditProvider {
*/
let oneCommandCode = false;
let blockComment = false;
/** Base indent, that block comment had in original code */
let blockCommentIndent = '';
let atTopLevel = true;
/** Formatter's directive:
* ```ahk
* ;@AHK++FormatBlockCommentOn
* ;@AHK++FormatBlockCommentOff
* ```
* Format text inside block comment like regular code */
let formatBlockComment = false;
// Save important values to this variables on block comment enter, restore them on exit
let preBlockCommentDepth = 0;
let preBlockCommentTagDepth = 0;
let preBlockCommentAtTopLevel = true;
let preBlockCommentOneCommandCode = false;

for (let lineIndex = 0; lineIndex < document.lineCount; lineIndex++) {
const originalLine = document.lineAt(lineIndex).text;
Expand All @@ -70,6 +85,8 @@ export class FormatProvider implements vscode.DocumentFormattingEditProvider {
.replace(/ {2,}/g, ' ')
.concat(comment)
.trim();
/** Line is empty or this is single comment line */
const emptyLine = purifiedLine === '';

atTopLevel = true;

Expand All @@ -78,19 +95,71 @@ export class FormatProvider implements vscode.DocumentFormattingEditProvider {

// This line

// Stop directives for formatter
if (emptyLine) {
if (comment.match(/;\s*@AHK\+\+FormatBlockCommentOff/i)) {
formatBlockComment = false;
}
}

// Block comments
if (originalLine.match(/ *\/\*/)) {
// The /* and */ symbols can be used to comment out an entire section,
// but only if the symbols appear at the beginning of a line (excluding whitespace),
// as in this example:
// /*
// MsgBox, This line is commented out (disabled).
// MsgBox, Common mistake: */ this does not end the comment.
// MsgBox, This line is commented out.
// */
if (!blockComment && originalLine.match(/^\s*\/\*/)) {
// found start '/*' pattern
blockComment = true;
// Save first capture group (original indent)
blockCommentIndent = originalLine.match(/(^\s*)\/\*/)?.[1];
if (formatBlockComment) {
// save indent values on block comment enter
preBlockCommentDepth = depth;
preBlockCommentTagDepth = tagDepth;
preBlockCommentAtTopLevel = atTopLevel;
preBlockCommentOneCommandCode = oneCommandCode;
// reset indent values to default values with added current 'depth' indent
oneCommandCode = false;
}
}
if (originalLine.match(/ *\*\//)) {
blockComment = false;
}

if (blockComment) {
formattedDocument += originalLine;
if (lineIndex !== document.lineCount - 1) {
formattedDocument += '\n';
// Save block comment line only if user don't want format it content
mark-wiemer marked this conversation as resolved.
Show resolved Hide resolved
if (!formatBlockComment) {
let blockCommentLine = '';
if (originalLine.startsWith(blockCommentIndent)) {
blockCommentLine = originalLine.substring(
blockCommentIndent.length,
);
} else {
blockCommentLine = originalLine;
}
formattedDocument += buildIndentedLine(
lineIndex,
document.lineCount,
blockCommentLine,
depth,
options,
);
}
if (originalLine.match(/^\s*\*\//)) {
// found end '*/' pattern
blockComment = false;
if (formatBlockComment) {
// restore indent values on block comment exit
depth = preBlockCommentDepth;
tagDepth = preBlockCommentTagDepth;
atTopLevel = preBlockCommentAtTopLevel;
oneCommandCode = preBlockCommentOneCommandCode;
}
}
if (!formatBlockComment) {
continue;
}
continue;
}

// #IfWinActive, #IfWinNotActive
Expand Down Expand Up @@ -163,28 +232,48 @@ export class FormatProvider implements vscode.DocumentFormattingEditProvider {
if (depth < 0) {
depth = 0;
}

// Add the indented line to the file
const indentationChars = options.insertSpaces
? ' '.repeat(depth * options.tabSize)
: '\t'.repeat(depth);
formattedDocument += !formattedLine?.trim()
? formattedLine
: indentationChars + formattedLine;

// If not last line, add newline
if (lineIndex !== document.lineCount - 1) {
formattedDocument += '\n';
if (preBlockCommentDepth < 0) {
preBlockCommentDepth = 0;
}

// Save indented line
formattedDocument += buildIndentedLine(
lineIndex,
document.lineCount,
formattedLine,
depth,
options,
);

// Next line

// Start directives for formatter
if (emptyLine) {
if (comment.match(/;\s*@AHK\+\+FormatBlockCommentOn/i)) {
formatBlockComment = true;
}
}

// One command code
if (oneCommandCode) {
if (
oneCommandCode &&
// Don't change indentation on empty lines (single line comment is equal to empty line) after one command code.
!emptyLine &&
// Don't change indentation on block comment after one command code.
// Change indentation inside block comment, if user wants to format block comment.
(!blockComment || formatBlockComment)
) {
oneCommandCode = false;
depth--;
}

// Block comments
// Must be after 'One command code' check, because it reset flag 'blockComment' that tests there!
// if (blockComment && originalLine.match(/^\s*\*\//)) {
// // found end '*/' pattern
// blockComment = false;
// }

// #IfWinActive, #IfWinNotActive
if (
purifiedLine.match(/#ifwinactive.*?\s/) ||
Expand Down
54 changes: 54 additions & 0 deletions src/providers/formattingProvider.utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
import * as vscode from 'vscode';

/**
* Build indentation chars
* @param depth Depth of indent
* @param options VS Code formatting options
*/
export function buildIndentationChars(
depth: number,
options: vscode.FormattingOptions,
mark-wiemer marked this conversation as resolved.
Show resolved Hide resolved
): string {
return options.insertSpaces
? ' '.repeat(depth * options.tabSize)
: '\t'.repeat(depth);
}

/**
* Build indented line of code (not ready for saving)
* @param indentationChars Indentation chars
* @param formattedLine Formatted line of code
*/
export function buildIndentedString(
indentationChars: string,
formattedLine: string,
): string {
return !formattedLine?.trim()
? formattedLine
: indentationChars + formattedLine;
}

/**
* Build indented line of code (ready for saving)
* @param lineIndex Line index of passed formattedLine
* @param lastLineIndex Index of last line of document
* @param formattedLine Formatted line of code
* @param depth Depth of indent
* @param options VS Code formatting options
*/
export function buildIndentedLine(
lineIndex: number,
lastLineIndex: number,
formattedLine: string,
depth: number,
options: vscode.FormattingOptions,
) {
const indentationChars = buildIndentationChars(depth, options);
let indentedLine = buildIndentedString(indentationChars, formattedLine);
// If not last line, add newline
if (lineIndex !== lastLineIndex - 1) {
indentedLine += '\n';
}
return indentedLine;
}

/** @return true iff this line has more closing parens than opening parens (round brackets) */
export function hasMoreCloseParens(line: string): boolean {
if (!line.includes(')')) {
Expand Down
2 changes: 2 additions & 0 deletions src/test/suite/format/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ const formatTests: FormatTest[] = [
{ filenameRoot: '40-command-inside-text' },
{ filenameRoot: '56-return-command-after-label' },
{ filenameRoot: '58-parentheses-indentation' },
{ filenameRoot: '59-one-command-indentation' },
{ filenameRoot: '72-paren-hotkey' },
{ filenameRoot: '119-semicolon-inside-string' },
{ filenameRoot: '185-block-comment' },
{ filenameRoot: '189-space-at-end-of-line' },
{ filenameRoot: 'ahk-explorer' },
{ filenameRoot: 'demo' },
Expand Down
39 changes: 39 additions & 0 deletions src/test/suite/format/samples/185-block-comment.in.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; [Issue #185](https://github.com/mark-wiemer/vscode-autohotkey-plus-plus/issues/185)
foo () {
;@AHK++FormatBlockCommentOn
/*
typedef struct TEST {
DWORD cbSize ; 0
} CMINVOKECOMMANDINFOEX;
*/
/*
MsgBox, This line is commented out (disabled).
MsgBox, Common mistake: */ this does not end the comment.
MsgBox, This line is commented out.
*/
/*
bar() {
Loop, 4 {
MsgBox % A_Index
}
if (true) {
SoundBeep
} else {
MsgBox
}
}
if (true)
ToolTip
MsgBox
*/
;@AHK++FormatBlockCommentOff
MsgBox
/*
All text in this block comment must save original indent
bar() {
Loop, 4 {
MsgBox % A_Index
}
}
*/
}
39 changes: 39 additions & 0 deletions src/test/suite/format/samples/185-block-comment.out.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; [Issue #185](https://github.com/mark-wiemer/vscode-autohotkey-plus-plus/issues/185)
foo () {
;@AHK++FormatBlockCommentOn
/*
typedef struct TEST {
DWORD cbSize ; 0
} CMINVOKECOMMANDINFOEX;
*/
/*
MsgBox, This line is commented out (disabled).
MsgBox, Common mistake: */ this does not end the comment.
MsgBox, This line is commented out.
*/
/*
bar() {
Loop, 4 {
MsgBox % A_Index
}
if (true) {
SoundBeep
} else {
MsgBox
}
}
if (true)
ToolTip
MsgBox
*/
;@AHK++FormatBlockCommentOff
MsgBox
/*
All text in this block comment must save original indent
bar() {
Loop, 4 {
MsgBox % A_Index
}
}
*/
}
11 changes: 11 additions & 0 deletions src/test/suite/format/samples/59-one-command-indentation.in.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; [Issue #59](https://github.com/mark-wiemer/vscode-autohotkey-plus-plus/issues/59)
if (true)

; comment
/*
comment
*/
success = 1
else
success = 1
failure = 0
Loading