Skip to content

Commit 5ab9f86

Browse files
mbelskyalexdima
andauthored
Support Transform to Kebab Case (microsoft#147956)
* 🍡 Support `Transform to Kebab Case` * Fix eslint warnings Co-authored-by: Alexandru Dima <[email protected]>
1 parent 393099a commit 5ab9f86

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

src/vs/editor/contrib/linesOperations/browser/linesOperations.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,49 @@ export class SnakeCaseAction extends AbstractCaseAction {
11621162
}
11631163
}
11641164

1165+
export class KebabCaseAction extends AbstractCaseAction {
1166+
1167+
public static isSupported(): boolean {
1168+
const areAllRegexpsSupported = [
1169+
this.caseBoundary,
1170+
this.singleLetters,
1171+
this.underscoreBoundary,
1172+
].every((regexp) => regexp.isSupported());
1173+
1174+
return areAllRegexpsSupported;
1175+
}
1176+
1177+
private static caseBoundary = new BackwardsCompatibleRegExp('(\\p{Ll})(\\p{Lu})', 'gmu');
1178+
private static singleLetters = new BackwardsCompatibleRegExp('(\\p{Lu}|\\p{N})(\\p{Lu}\\p{Ll})', 'gmu');
1179+
private static underscoreBoundary = new BackwardsCompatibleRegExp('(\\S)(_)(\\S)', 'gm');
1180+
1181+
constructor() {
1182+
super({
1183+
id: 'editor.action.transformToKebabcase',
1184+
label: nls.localize('editor.transformToKebabcase', 'Transform to Kebab Case'),
1185+
alias: 'Transform to Kebab Case',
1186+
precondition: EditorContextKeys.writable
1187+
});
1188+
}
1189+
1190+
protected _modifyText(text: string, _: string): string {
1191+
const caseBoundary = KebabCaseAction.caseBoundary.get();
1192+
const singleLetters = KebabCaseAction.singleLetters.get();
1193+
const underscoreBoundary = KebabCaseAction.underscoreBoundary.get();
1194+
1195+
if (!caseBoundary || !singleLetters || !underscoreBoundary) {
1196+
// one or more regexps aren't supported
1197+
return text;
1198+
}
1199+
1200+
return text
1201+
.replace(underscoreBoundary, '$1-$3')
1202+
.replace(caseBoundary, '$1-$2')
1203+
.replace(singleLetters, '$1-$2')
1204+
.toLocaleLowerCase();
1205+
}
1206+
}
1207+
11651208
registerEditorAction(CopyLinesUpAction);
11661209
registerEditorAction(CopyLinesDownAction);
11671210
registerEditorAction(DuplicateSelectionAction);
@@ -1189,3 +1232,7 @@ if (SnakeCaseAction.caseBoundary.isSupported() && SnakeCaseAction.singleLetters.
11891232
if (TitleCaseAction.titleBoundary.isSupported()) {
11901233
registerEditorAction(TitleCaseAction);
11911234
}
1235+
1236+
if (KebabCaseAction.isSupported()) {
1237+
registerEditorAction(KebabCaseAction);
1238+
}

src/vs/editor/contrib/linesOperations/test/browser/linesOperations.test.ts

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Selection } from 'vs/editor/common/core/selection';
1111
import { Handler } from 'vs/editor/common/editorCommon';
1212
import { ITextModel } from 'vs/editor/common/model';
1313
import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl';
14-
import { DeleteAllLeftAction, DeleteAllRightAction, DeleteDuplicateLinesAction, DeleteLinesAction, IndentLinesAction, InsertLineAfterAction, InsertLineBeforeAction, JoinLinesAction, LowerCaseAction, SnakeCaseAction, SortLinesAscendingAction, SortLinesDescendingAction, TitleCaseAction, TransposeAction, UpperCaseAction } from 'vs/editor/contrib/linesOperations/browser/linesOperations';
14+
import { DeleteAllLeftAction, DeleteAllRightAction, DeleteDuplicateLinesAction, DeleteLinesAction, IndentLinesAction, InsertLineAfterAction, InsertLineBeforeAction, JoinLinesAction, KebabCaseAction, LowerCaseAction, SnakeCaseAction, SortLinesAscendingAction, SortLinesDescendingAction, TitleCaseAction, TransposeAction, UpperCaseAction } from 'vs/editor/contrib/linesOperations/browser/linesOperations';
1515
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
1616
import { createTextModel } from 'vs/editor/test/common/testTextModel';
1717

@@ -814,6 +814,80 @@ suite('Editor Contrib - Line Operations', () => {
814814
assertSelection(editor, new Selection(2, 2, 2, 2));
815815
}
816816
);
817+
818+
withTestCodeEditor(
819+
[
820+
'hello world',
821+
'öçşğü',
822+
'parseHTMLString',
823+
'getElementById',
824+
'PascalCase',
825+
'öçşÖÇŞğüĞÜ',
826+
'audioConverter.convertM4AToMP3();',
827+
'Capital_Snake_Case',
828+
'parseHTML4String',
829+
'_accessor: ServicesAccessor',
830+
'Kebab-Case',
831+
], {}, (editor) => {
832+
const model = editor.getModel()!;
833+
const kebabCaseAction = new KebabCaseAction();
834+
835+
editor.setSelection(new Selection(1, 1, 1, 12));
836+
executeAction(kebabCaseAction, editor);
837+
assert.strictEqual(model.getLineContent(1), 'hello world');
838+
assertSelection(editor, new Selection(1, 1, 1, 12));
839+
840+
editor.setSelection(new Selection(2, 1, 2, 6));
841+
executeAction(kebabCaseAction, editor);
842+
assert.strictEqual(model.getLineContent(2), 'öçşğü');
843+
assertSelection(editor, new Selection(2, 1, 2, 6));
844+
845+
editor.setSelection(new Selection(3, 1, 3, 16));
846+
executeAction(kebabCaseAction, editor);
847+
assert.strictEqual(model.getLineContent(3), 'parse-html-string');
848+
assertSelection(editor, new Selection(3, 1, 3, 18));
849+
850+
editor.setSelection(new Selection(4, 1, 4, 15));
851+
executeAction(kebabCaseAction, editor);
852+
assert.strictEqual(model.getLineContent(4), 'get-element-by-id');
853+
assertSelection(editor, new Selection(4, 1, 4, 18));
854+
855+
editor.setSelection(new Selection(5, 1, 5, 11));
856+
executeAction(kebabCaseAction, editor);
857+
assert.strictEqual(model.getLineContent(5), 'pascal-case');
858+
assertSelection(editor, new Selection(5, 1, 5, 12));
859+
860+
editor.setSelection(new Selection(6, 1, 6, 11));
861+
executeAction(kebabCaseAction, editor);
862+
assert.strictEqual(model.getLineContent(6), 'öçş-öç-şğü-ğü');
863+
assertSelection(editor, new Selection(6, 1, 6, 14));
864+
865+
editor.setSelection(new Selection(7, 1, 7, 34));
866+
executeAction(kebabCaseAction, editor);
867+
assert.strictEqual(model.getLineContent(7), 'audio-converter.convert-m4a-to-mp3();');
868+
assertSelection(editor, new Selection(7, 1, 7, 38));
869+
870+
editor.setSelection(new Selection(8, 1, 8, 19));
871+
executeAction(kebabCaseAction, editor);
872+
assert.strictEqual(model.getLineContent(8), 'capital-snake-case');
873+
assertSelection(editor, new Selection(8, 1, 8, 19));
874+
875+
editor.setSelection(new Selection(9, 1, 9, 17));
876+
executeAction(kebabCaseAction, editor);
877+
assert.strictEqual(model.getLineContent(9), 'parse-html4-string');
878+
assertSelection(editor, new Selection(9, 1, 9, 19));
879+
880+
editor.setSelection(new Selection(10, 1, 10, 28));
881+
executeAction(kebabCaseAction, editor);
882+
assert.strictEqual(model.getLineContent(10), '_accessor: services-accessor');
883+
assertSelection(editor, new Selection(10, 1, 10, 29));
884+
885+
editor.setSelection(new Selection(11, 1, 11, 11));
886+
executeAction(kebabCaseAction, editor);
887+
assert.strictEqual(model.getLineContent(11), 'kebab-case');
888+
assertSelection(editor, new Selection(11, 1, 11, 11));
889+
}
890+
);
817891
});
818892

819893
suite('DeleteAllRightAction', () => {

0 commit comments

Comments
 (0)