Skip to content

Commit

Permalink
version 0.0.5
Browse files Browse the repository at this point in the history
alwaysShow, choices/cases do not disappear
canSelectMany, multiple choices/cases are possible
-> remove @ALL choice
save/restore selected cases

remove all @
Use removeDuplicates + join instead of reduce
Some tests
  • Loading branch information
wsbak committed Mar 9, 2024
1 parent 8fc4dfb commit 025bc1e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 70 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@
## 0.0.4

- fix: Chinese be transformed to empty.

## 0.0.5

- feat: can select multiple cases.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ The extension based on native search component. It is used to search for multipl
* kebab-case
* camelCase
* PascalCase
* UPPER_SNAKE_CASE
* snake_case
* UPPER_SNAKE_CASE

If no case is specified, it defaults to **all cases**.

## Usage

The fastest way to use it is to use shortcut keys `⌘+F1`. You can then select the appropriate case from the drop-down options and input your query string for custom searching.
The fastest way to use it is to use shortcut keys `⌘+F1`. You can then select one or many appropriate cases from the drop-down options and input your query string for custom searching.

![screenshot1](resources/screenshot1.gif)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "case-search",
"displayName": "Case Search",
"description": "A VS Code search extension based on native search component.",
"version": "0.0.4",
"version": "0.0.5",
"engines": {
"vscode": "^1.40.0"
},
Expand Down
139 changes: 79 additions & 60 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,107 @@ import { commands, QuickPickItem, window } from "vscode";
import type { ExtensionContext } from "vscode";
import { paramCase, pascalCase, constantCase, snakeCase, camelCase } from "change-case";

const quickPickItems: QuickPickItem[] = [
{
label: "@all"
},
{
label: "@kebab-case"
},
{
label: "@camelCase"
},
{
label: "@PascalCase"
},
{
label: "@UPPER_SNAKE_CASE"
},
{
label: "@snake_case"
}
];

const kebabCaseQPI: QuickPickItem = { label: "kebab-case", alwaysShow: true, };
const camelCaseQPI: QuickPickItem = { label: "camelCase", alwaysShow: true, };
const pascalCaseQPI: QuickPickItem = { label: "PascalCase", alwaysShow: true, };
const snakeCaseQPI: QuickPickItem = { label: "snake_case", alwaysShow: true, };
const snakeUpperCaseQPI: QuickPickItem = { label: "UPPER_SNAKE_CASE", alwaysShow: true, };
const quickPickItems: QuickPickItem[] = [ kebabCaseQPI, camelCaseQPI, pascalCaseQPI, snakeCaseQPI, snakeUpperCaseQPI ];

function transformQuery2RegExp(query: string, scope: string) {
switch(scope) {
case "@all":
return [
paramCase(query),
camelCase(query),
pascalCase(query),
constantCase(query),
snakeCase(query)
].reduce((pre, cur) => {
pre += pre.indexOf(cur) === -1 ? `|${cur}` : "";
return pre;
}, "").substring(1);
case "@kebab-case":
case "kebab-case":
return paramCase(query);
case "@camelCase":
case "camelCase":
return camelCase(query);
case "@PascalCase":
case "PascalCase":
return pascalCase(query);
case "@UPPER_SNAKE_CASE":
return constantCase(query);
case "@snake_case":
case "snake_case":
return snakeCase(query);
case "UPPER_SNAKE_CASE":
return constantCase(query);
}
}

// build regex query with all cases selected
function buildRegexQuery(query: string, selectedItems: readonly QuickPickItem[]): string {
let queries: String[] = [];
for (let item of selectedItems) {
let queryScope = transformQuery2RegExp(query, item.label) || query;
queries.push(queryScope);
}

return removeDuplicates(queries).join("|");
}

/**
* Construct a copy of an array with duplicate items removed.
* Where duplicate items exist, only the first instance will be kept.
*/
function removeDuplicates<T>(array: T[]): T[] {
return [...new Set(array)];
}

// Read selectedItems (cases) from context.workspaceState
function readSelectedItems(context: ExtensionContext): QuickPickItem[] {
let selectedItems: QuickPickItem[] = [];
for (let quickPickItem of quickPickItems) {
if (context.workspaceState.get<boolean>(quickPickItem.label, false) === true) {
selectedItems.push(quickPickItem);
}
}
console.log("readSelectedItems", selectedItems);
return selectedItems;
}

// Save selectedItems (cases) into context.workspaceState
function saveSelectedItems(context: ExtensionContext, selectedItems: readonly QuickPickItem[]) {
for (let quickPickItem of quickPickItems) {
let selected = selectedItems.findIndex(item=> item === quickPickItem) >= 0;
context.workspaceState.update(quickPickItem.label, selected);
// console.log("previouslySelectedItems", previouslySelectedItems);
}
}

export function activate(context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand('case-search.showSearchBox', async () => {

const quickPick = window.createQuickPick();
quickPick.items = quickPickItems;
quickPick.placeholder = "please input camelCased query text , default scope is @all";
quickPick.onDidChangeSelection(e => {
const item = e[0];
if (item) {
quickPick.value = item.label + ": ";
}
});
quickPick.canSelectMany = true;
quickPick.selectedItems = readSelectedItems(context);
quickPick.placeholder = "please input query text, default scope is all cases";
quickPick.onDidAccept(() => {
let scope = "";
let query = "";
const reg = /@[^\s]*:/;
let regMatchResult = quickPick.value.match(reg);
if (regMatchResult) {
scope = regMatchResult[0].substring(0, regMatchResult[0].length - 1);
query = quickPick.value.replace(reg, "").trim();
} else {
scope = "@all";
query = quickPick.value.trim();
}
// console.log("onDidAccept", "value", quickPick.value, "selectedItems", quickPick.selectedItems);
saveSelectedItems(context, quickPick.selectedItems);

if (quickPick.value) {
// If no selectedItems, we take all quickPickItems
let items = quickPick.selectedItems.length <= 0 ? quickPickItems : quickPick.selectedItems;
let query = buildRegexQuery(quickPick.value, items);
// console.log("query", query);

if (query) {
commands.executeCommand("workbench.action.findInFiles", { query: transformQuery2RegExp(query, scope) || query, triggerSearch: true, isRegex: true, isCaseSensitive: true });
quickPick.hide();
commands.executeCommand("workbench.action.findInFiles", {
query: query, triggerSearch: true, isRegex: true, isCaseSensitive: true
});
}
quickPick.hide();
});

quickPick.show();

}));

}

export function deactivate() {}

// Exports for test only
export const exportedForTesting = {
kebabCaseQPI,
camelCaseQPI,
pascalCaseQPI,
snakeCaseQPI,
snakeUpperCaseQPI,
transformQuery2RegExp,
buildRegexQuery,
};
48 changes: 41 additions & 7 deletions src/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
import * as assert from 'assert';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
// import * as myExtension from '../../extension';

import { exportedForTesting } from '../../extension';
const { kebabCaseQPI, camelCaseQPI, pascalCaseQPI, snakeCaseQPI, snakeUpperCaseQPI } = exportedForTesting;
const { transformQuery2RegExp, buildRegexQuery } = exportedForTesting;


suite('Extension Test Suite', () => {
vscode.window.showInformationMessage('Start all tests.');

test('Sample test', () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
test('transformQuery2RegExp', () => {
assert.strictEqual("one-two-three-four", transformQuery2RegExp("oneTwoThreeFour", "kebab-case"));
assert.strictEqual("one-two-three-four", transformQuery2RegExp("one two_three-Four", "kebab-case"));
assert.strictEqual("oneTwoThreeFour", transformQuery2RegExp("oneTwoThreeFour", "camelCase"));
assert.strictEqual("oneTwoThreeFour", transformQuery2RegExp("one two_three-Four", "camelCase"));
assert.strictEqual("OneTwoThreeFour", transformQuery2RegExp("oneTwoThreeFour", "PascalCase"));
assert.strictEqual("OneTwoThreeFour", transformQuery2RegExp("one two_three-Four", "PascalCase"));
assert.strictEqual("one_two_three_four", transformQuery2RegExp("oneTwoThreeFour", "snake_case"));
assert.strictEqual("one_two_three_four", transformQuery2RegExp("one two_three-Four", "snake_case"));
assert.strictEqual("ONE_TWO_THREE_FOUR", transformQuery2RegExp("oneTwoThreeFour", "UPPER_SNAKE_CASE"));
assert.strictEqual("ONE_TWO_THREE_FOUR", transformQuery2RegExp("one two_three-Four", "UPPER_SNAKE_CASE"));
});

test('buildRegexQuery', () => {
const query = "one two_three-Four";

assert.strictEqual("", buildRegexQuery(query, []));

assert.strictEqual("one-two-three-four", buildRegexQuery(query, [kebabCaseQPI]));
assert.strictEqual("oneTwoThreeFour", buildRegexQuery(query, [camelCaseQPI]));
assert.strictEqual("OneTwoThreeFour", buildRegexQuery(query, [pascalCaseQPI]));
assert.strictEqual("one_two_three_four", buildRegexQuery(query, [snakeCaseQPI]));
assert.strictEqual("ONE_TWO_THREE_FOUR", buildRegexQuery(query, [snakeUpperCaseQPI]));

assert.strictEqual("one-two-three-four|oneTwoThreeFour",
buildRegexQuery(query, [kebabCaseQPI, camelCaseQPI]));

assert.strictEqual("OneTwoThreeFour|one_two_three_four|ONE_TWO_THREE_FOUR",
buildRegexQuery(query, [pascalCaseQPI, snakeCaseQPI, snakeUpperCaseQPI]));

assert.strictEqual("OneTwoThreeFour|one_two_three_four|ONE_TWO_THREE_FOUR|oneTwoThreeFour|one-two-three-four",
buildRegexQuery(query, [pascalCaseQPI, snakeCaseQPI, snakeUpperCaseQPI, camelCaseQPI, kebabCaseQPI]));

// Duplicates are removed
assert.strictEqual("OneTwoThreeFour|ONE_TWO_THREE_FOUR",
buildRegexQuery(query, [pascalCaseQPI,snakeUpperCaseQPI,pascalCaseQPI]));
});
});

0 comments on commit 025bc1e

Please sign in to comment.