Skip to content

Commit 9ec3b5a

Browse files
Refactor: Reorganize commands into separate files and update README
1 parent bc0cc8b commit 9ec3b5a

File tree

12 files changed

+233
-141
lines changed

12 files changed

+233
-141
lines changed

README.md

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,43 @@ as multiple selections.
77

88
Current string functions available:
99

10-
1. camelize
11-
1. capitalize
12-
1. classify
13-
1. chop - split into groups provided n # of characters
14-
1. clean
15-
1. clean diacritics
16-
1. dasherize
17-
1. decapitalize
18-
1. humanize
19-
1. reverse
20-
1. screaming snake
21-
1. sentence
22-
1. slugify
23-
1. snake
24-
1. underscore
25-
1. swap case
26-
1. titleize
27-
1. titleize (AP Style)
28-
1. titleize (Chicago Style)
10+
1. camelize - converts hyphenated strings to camelCase
11+
1. capitalize - capitalizes the first character of each selection
12+
1. classify - converts underscored text to PascalCase
13+
1. chop - splits into groups provided n # of characters
14+
1. clean - collapses multiple spaces into one
15+
1. clean diacritics - removes diacritic marks from characters
16+
1. dasherize - converts camelCase to kebab-case
17+
1. decapitalize - lowercases the first character of each selection
18+
1. humanize - converts text to human-readable form
19+
1. reverse - reverses the characters in the selection
20+
1. screaming snake - converts text to SCREAMING_SNAKE_CASE
21+
1. sentence - transforms text to sentence case
22+
1. slugify - converts text to a URL-friendly slug
23+
1. snake - converts text to snake_case
24+
1. swap case - inverts the case of each character
25+
1. titleize - capitalizes the first letter of each word
26+
1. titleize (AP Style) - capitalizes titles according to AP style
27+
1. titleize (Chicago Style) - capitalizes titles according to Chicago style
2928
1. truncate - trims string to n # of characters and appends ellipsis
3029
1. prune - truncate but keeps ellipsis within character count provided
31-
1. repeat - repeat selection n #of times
32-
1. convert between unicode and readable characters.
30+
1. repeat - repeat selection n # of times
31+
1. random case - randomly changes the case of characters
32+
1. swap quotes - swaps between single and double quotes
33+
1. utf8ToChar - converts Unicode escapes to characters
34+
1. charToUtf8 - converts characters to Unicode escapes
3335

3436
Number related functions:
3537

36-
1. increment all numbers in selection
37-
1. decrement all numbers in selection
38-
1. duplicate selection and increment all number
39-
1. duplicate selection and decrement all number
40-
1. sequence all numbers in selection from first number
38+
1. increment - increases all numbers in the selection by 1
39+
1. decrement - decreases all numbers in the selection by 1
40+
1. duplicate and increment - duplicates selection and increments all numbers
41+
1. duplicate and decrement - duplicates selection and decrements all numbers
42+
1. sequence - replaces numbers with a sequence starting from the first number
43+
44+
Additional utility commands:
45+
46+
1. repeat last action - repeats the last string manipulation command that was executed
4147

4248
## Use
4349

@@ -49,7 +55,7 @@ To use these commands, press ⌘+p and enter any of the commands above while tex
4955

5056
Introducing String Manipulation Labs
5157

52-
Were excited to announce the launch of String Manipulation Labs—a collection of (really just one at this moment) experimental features designed to enhance and expand the capabilities of the String Manipulation extension. Labs features are disabled by default to ensure a stable experience with the core functionalities.
58+
We're excited to announce the launch of String Manipulation Labs—a collection of (really just one at this moment) experimental features designed to enhance and expand the capabilities of the String Manipulation extension. Labs features are disabled by default to ensure a stable experience with the core functionalities.
5359

5460
### 🚀 How to Enable Labs Features
5561

src/commands/default-functions.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as underscore from "underscore.string";
2+
import { CommandFunction } from "./types";
3+
4+
export const defaultFunction =
5+
(commandName: string, option?: any) => (str: string) =>
6+
(underscore as any)[commandName](str, option);
7+
8+
export const snake = (str: string) =>
9+
underscore
10+
.underscored(str)
11+
.replace(/([A-Z])[^A-Z]/g, " $1")
12+
.replace(/[^a-z0-9]+/gi, " ")
13+
.trim()
14+
.replace(/\s/gi, "_");
15+
16+
export const screamingSnake: CommandFunction = (str: string) =>
17+
snake(str).toUpperCase();
18+
19+
export const camelize: CommandFunction = (str: string) =>
20+
underscore.camelize(/[a-z]/.test(str) ? str : str.toLowerCase());
21+
22+
// Default functions
23+
export const titleize: CommandFunction = defaultFunction("titleize");
24+
export const classify: CommandFunction = defaultFunction("classify");
25+
export const clean: CommandFunction = defaultFunction("clean");
26+
export const cleanDiacritics: CommandFunction =
27+
defaultFunction("cleanDiacritics");
28+
export const dasherize: CommandFunction = defaultFunction("dasherize");
29+
export const humanize: CommandFunction = defaultFunction("humanize");
30+
export const reverse: CommandFunction = defaultFunction("reverse");
31+
export const decapitalize: CommandFunction = defaultFunction("decapitalize");
32+
export const capitalize: CommandFunction = defaultFunction("capitalize");
33+
export const sentence: CommandFunction = defaultFunction("capitalize", true);
34+
export const swapCase: CommandFunction = defaultFunction("swapCase");
35+
36+
// Functions with arguments
37+
export const chop: CommandFunction = (n: number) => defaultFunction("chop", n);
38+
export const truncate: CommandFunction = (n: number) =>
39+
defaultFunction("truncate", n);
40+
export const prune: CommandFunction = (n: number) => (str: string) =>
41+
str.slice(0, n - 3).trim() + "...";
42+
export const repeat: CommandFunction = (n: number) =>
43+
defaultFunction("repeat", n);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { CommandFunction } from "./types";
2+
3+
export const increment: CommandFunction = (str: string) =>
4+
str.replace(/-?\d+/g, (n) => String(Number(n) + 1));
5+
6+
export const decrement: CommandFunction = (str: string) =>
7+
str.replace(/-?\d+/g, (n) => String(Number(n) - 1));
8+
9+
export const duplicateAndIncrement: CommandFunction = () => "";
10+
export const duplicateAndDecrement: CommandFunction = () => "";
Lines changed: 61 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,70 @@
11
import * as vscode from "vscode";
2-
import * as underscore from "underscore.string";
3-
import { swapQuotes } from "./commands/swap_quotes";
4-
const apStyleTitleCase = require("ap-style-title-case");
5-
const chicagoStyleTitleCase = require("chicago-capitalize");
6-
const slugify = require("@sindresorhus/slugify");
7-
8-
interface MultiSelectData {
9-
offset?: number;
10-
}
11-
12-
const defaultFunction = (commandName: string, option?: any) => (str: string) =>
13-
(underscore as any)[commandName](str, option);
14-
15-
const sequence = (str: string, multiselectData: MultiSelectData = {}) => {
16-
return str.replace(/-?\d+/g, (n) => {
17-
const isFirst = typeof multiselectData.offset !== "number";
18-
multiselectData.offset = isFirst
19-
? Number(n)
20-
: (multiselectData.offset || 0) + 1;
21-
return String(multiselectData.offset);
22-
});
23-
};
24-
25-
const increment = (str: string) =>
26-
str.replace(/-?\d+/g, (n) => String(Number(n) + 1));
27-
28-
const decrement = (str: string) =>
29-
str.replace(/-?\d+/g, (n) => String(Number(n) - 1));
30-
31-
const randomCase = (input: string): string => {
32-
let result = "";
33-
for (const char of input) {
34-
if (Math.random() < 0.5) {
35-
result += char.toLowerCase();
36-
} else {
37-
result += char.toUpperCase();
38-
}
39-
}
40-
return result;
41-
};
42-
43-
const snake = (str: string) =>
44-
underscore
45-
.underscored(str)
46-
.replace(/([A-Z])[^A-Z]/g, " $1")
47-
.replace(/[^a-z0-9]+/gi, " ")
48-
.trim()
49-
.replace(/\s/gi, "_");
50-
51-
export type StringFunction = (
52-
str: string,
53-
multiselectData?: MultiSelectData
54-
) => string;
55-
export type CommandFunction =
56-
| StringFunction
57-
| ((...args: any[]) => StringFunction);
58-
59-
const commandNameFunctionMap: { [key: string]: CommandFunction } = {
60-
titleize: defaultFunction("titleize"),
61-
chop: (n: number) => defaultFunction("chop", n),
62-
classify: defaultFunction("classify"),
63-
clean: defaultFunction("clean"),
64-
cleanDiacritics: defaultFunction("cleanDiacritics"),
65-
underscored: snake,
66-
dasherize: defaultFunction("dasherize"),
67-
humanize: defaultFunction("humanize"),
68-
reverse: defaultFunction("reverse"),
69-
decapitalize: defaultFunction("decapitalize"),
70-
capitalize: defaultFunction("capitalize"),
71-
sentence: defaultFunction("capitalize", true),
72-
camelize: (str: string) =>
73-
underscore.camelize(/[a-z]/.test(str) ? str : str.toLowerCase()),
74-
slugify: slugify,
75-
swapCase: defaultFunction("swapCase"),
76-
snake,
77-
screamingSnake: (str: string) => snake(str).toUpperCase(),
78-
titleizeApStyle: apStyleTitleCase,
79-
titleizeChicagoStyle: chicagoStyleTitleCase,
80-
truncate: (n: number) => defaultFunction("truncate", n),
81-
prune: (n: number) => (str: string) => str.slice(0, n - 3).trim() + "...",
82-
repeat: (n: number) => defaultFunction("repeat", n),
2+
import {
3+
CommandRegistry,
4+
functionNamesWithArgument,
5+
numberFunctionNames,
6+
CommandFunction,
7+
} from "./types";
8+
import * as defaultFunctions from "./default-functions";
9+
import {
8310
increment,
8411
decrement,
85-
duplicateAndIncrement: () => "",
86-
duplicateAndDecrement: () => "",
12+
duplicateAndIncrement,
13+
duplicateAndDecrement,
14+
} from "./increment-decrement";
15+
import { sequence } from "./sequence";
16+
import { randomCase } from "./random-case";
17+
import { utf8ToChar, charToUtf8 } from "./utf8-conversion";
18+
import { titleizeApStyle, titleizeChicagoStyle } from "./title-case";
19+
import { slugify } from "./slugify";
20+
import { swapQuotes } from "./swap_quotes";
21+
22+
// Combine all commands into a single registry
23+
export const commandNameFunctionMap: CommandRegistry = {
24+
// Default functions
25+
titleize: defaultFunctions.titleize,
26+
chop: defaultFunctions.chop,
27+
classify: defaultFunctions.classify,
28+
clean: defaultFunctions.clean,
29+
cleanDiacritics: defaultFunctions.cleanDiacritics,
30+
underscored: defaultFunctions.snake,
31+
dasherize: defaultFunctions.dasherize,
32+
humanize: defaultFunctions.humanize,
33+
reverse: defaultFunctions.reverse,
34+
decapitalize: defaultFunctions.decapitalize,
35+
capitalize: defaultFunctions.capitalize,
36+
sentence: defaultFunctions.sentence,
37+
camelize: defaultFunctions.camelize,
38+
swapCase: defaultFunctions.swapCase,
39+
snake: defaultFunctions.snake,
40+
screamingSnake: defaultFunctions.screamingSnake,
41+
truncate: defaultFunctions.truncate,
42+
prune: defaultFunctions.prune,
43+
repeat: defaultFunctions.repeat,
44+
45+
// Specialized functions
46+
increment,
47+
decrement,
48+
duplicateAndIncrement,
49+
duplicateAndDecrement,
8750
sequence,
88-
utf8ToChar: (str: string) =>
89-
str
90-
.match(/\\u[\dA-Fa-f]{4}/g)
91-
?.map((x) => x.slice(2))
92-
.map((x) => String.fromCharCode(parseInt(x, 16)))
93-
.join("") || "",
94-
charToUtf8: (str: string) =>
95-
str
96-
.split("")
97-
.map((x) => `\\u${x.charCodeAt(0).toString(16).padStart(4, "0")}`)
98-
.join(""),
51+
utf8ToChar,
52+
charToUtf8,
9953
randomCase,
54+
titleizeApStyle,
55+
titleizeChicagoStyle,
56+
slugify,
10057
swapQuotes,
10158
};
10259

103-
const numberFunctionNames = [
104-
"increment",
105-
"decrement",
106-
"sequence",
107-
"duplicateAndIncrement",
108-
"duplicateAndDecrement",
109-
];
110-
111-
export const functionNamesWithArgument = [
112-
"chop",
113-
"truncate",
114-
"prune",
115-
"repeat",
116-
];
60+
// Re-export types and constants
61+
export {
62+
functionNamesWithArgument,
63+
numberFunctionNames,
64+
CommandFunction,
65+
} from "./types";
11766

67+
// Main string function that applies the transformations
11868
export const stringFunction = async (
11969
commandName: string,
12070
context: vscode.ExtensionContext,
@@ -129,7 +79,7 @@ export const stringFunction = async (
12979
[key: number]: { selection: vscode.Selection; replaced: string };
13080
} = {};
13181

132-
let multiselectData: MultiSelectData = {};
82+
let multiselectData = {};
13383

13484
let stringFunc: (str: string) => string;
13585

@@ -150,7 +100,7 @@ export const stringFunction = async (
150100
stringFunc = (str: string) =>
151101
(commandNameFunctionMap[commandName] as Function)(str, multiselectData);
152102
} else {
153-
stringFunc = commandNameFunctionMap[commandName] as StringFunction;
103+
stringFunc = commandNameFunctionMap[commandName] as (str: string) => string;
154104
}
155105

156106
if (
@@ -221,6 +171,7 @@ export const stringFunction = async (
221171
return await Promise.resolve({ replacedSelections });
222172
};
223173

174+
// Activation function
224175
export function activate(context: vscode.ExtensionContext) {
225176
context.globalState.setKeysForSync(["lastAction"]);
226177

@@ -245,5 +196,3 @@ export function activate(context: vscode.ExtensionContext) {
245196
);
246197
});
247198
}
248-
249-
export { commandNameFunctionMap };

src/commands/random-case.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { CommandFunction } from "./types";
2+
3+
export const randomCase: CommandFunction = (input: string): string => {
4+
let result = "";
5+
for (const char of input) {
6+
if (Math.random() < 0.5) {
7+
result += char.toLowerCase();
8+
} else {
9+
result += char.toUpperCase();
10+
}
11+
}
12+
return result;
13+
};

src/commands/sequence.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { CommandFunction, MultiSelectData } from "./types";
2+
3+
export const sequence: CommandFunction = (
4+
str: string,
5+
multiselectData: MultiSelectData = {}
6+
) => {
7+
return str.replace(/-?\d+/g, (n) => {
8+
const isFirst = typeof multiselectData.offset !== "number";
9+
multiselectData.offset = isFirst
10+
? Number(n)
11+
: (multiselectData.offset || 0) + 1;
12+
return String(multiselectData.offset);
13+
});
14+
};

src/commands/slugify.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { CommandFunction } from "./types";
2+
const slugifyLib = require("@sindresorhus/slugify");
3+
4+
export const slugify: CommandFunction = slugifyLib;

src/commands/title-case.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { CommandFunction } from "./types";
2+
const apStyleTitleCase = require("ap-style-title-case");
3+
const chicagoStyleTitleCase = require("chicago-capitalize");
4+
5+
export const titleizeApStyle: CommandFunction = apStyleTitleCase;
6+
export const titleizeChicagoStyle: CommandFunction = chicagoStyleTitleCase;

0 commit comments

Comments
 (0)