1
0
Code Issues Pull Requests Packages Projects Releases Wiki Activity GitHub Gitee

Merge branch 'feature-path-conversion'

This commit is contained in:
程序员小墨 2024-12-15 00:02:18 +08:00
commit a03dd73727
27 changed files with 2263 additions and 1333 deletions

View File

@ -23,6 +23,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
--> -->
## 2.0.0
### Added
- New: Support path conversions via shortcut keys `Ctrl + Alt + /` and `Ctrl + Shift + Alt + /` (also supports multi-selection conversion). (支持通过 `Ctrl + Alt + /`, `Ctrl + Shift + Alt + /` 快捷键进行路径转换 (同时支持多选区转换))
- New: Support following path conversion type: QuickPick menu conversion, context menu conversion, status bar button conversion, shortcut key conversion. (支持以下路径转换方式QuickPick 菜单转换、右键菜单转换、状态栏按钮转换、快捷键转换)
### Changed
- Do not display the editor context menu `Variable Conversion` option when text is not selected. (当未选中文本时,不显示右键菜单 `变量转换` 选项)
### Improvement
- Adjust the project code directory structure. (项目代码目录结构调整)
## 1.1.0 ## 1.1.0
### Added ### Added
@ -46,7 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- New: Supports multi-selection conversion (支持多选区转换) - New: Supports multi-selection conversion (支持多选区转换)
- New: Supports scrolling conversion via shortcut keys `Ctrl + Alt + [` and `Ctrl + Alt + ]` (also supports multi-selection conversion) 支持通过快捷键循环转换 (同时支持多选区转换) - New: Supports scrolling variable conversion via shortcut keys `Ctrl + Alt + [` and `Ctrl + Alt + ]` (also supports multi-selection conversion). (支持通过 `Ctrl + Alt + [`, `Ctrl + Alt + ]` 快捷键进行变量循环转换 (同时支持多选区转换))
## 1.0.7 ## 1.0.7

View File

@ -4,7 +4,7 @@
"displayName": "Variable Conversion", "displayName": "Variable Conversion",
"description": "一个强大的变量名转换插件,支持右键菜单、快捷键、状态栏等多种方式使用,支持小驼峰、大驼峰(帕斯卡)、下划线(蛇形)、中划线(连字符/脊柱式)、空格分隔、点分隔、全小写、全大写等常用命名方式(及组合)转换。 \nA powerful variable naming conversion extension. You can use it through the editer menu, shortcut keys and bottom bar. Support camel, pascal, snake, kebab(spinal), space, dot, lower, upper case, and more.", "description": "一个强大的变量名转换插件,支持右键菜单、快捷键、状态栏等多种方式使用,支持小驼峰、大驼峰(帕斯卡)、下划线(蛇形)、中划线(连字符/脊柱式)、空格分隔、点分隔、全小写、全大写等常用命名方式(及组合)转换。 \nA powerful variable naming conversion extension. You can use it through the editer menu, shortcut keys and bottom bar. Support camel, pascal, snake, kebab(spinal), space, dot, lower, upper case, and more.",
// 版本号 // 版本号
"version": "1.1.0", "version": "2.0.0",
// logo // logo
"icon": "image/logo.png", "icon": "image/logo.png",
"publisher": "coder-xiaomo", "publisher": "coder-xiaomo",
@ -40,6 +40,7 @@
// docs: https://code.visualstudio.com/docs/getstarted/keybindings#_accepted-keys // docs: https://code.visualstudio.com/docs/getstarted/keybindings#_accepted-keys
"keybindings": [ "keybindings": [
// 绑定快捷键 // 绑定快捷键
// ↓ 变量转换快捷键
{ {
"command": "variable-conversion.convertCase", "command": "variable-conversion.convertCase",
"key": "shift+alt+t", "key": "shift+alt+t",
@ -62,6 +63,30 @@
"arrowKey": "]" "arrowKey": "]"
}, },
"when": "editorTextFocus" "when": "editorTextFocus"
},
// ↓ 路径转换快捷键
{
"command": "variable-conversion.convertPath",
"key": "shift+alt+/",
"when": "editorTextFocus"
},
// 循环转换 上一个
{
"command": "variable-conversion.cyclicConvertPath.previous",
"key": "ctrl+alt+shift+/",
"args": {
"direction": "<-"
},
"when": "editorTextFocus"
},
// 循环转换 下一个
{
"command": "variable-conversion.cyclicConvertPath.next",
"key": "ctrl+alt+/",
"args": {
"direction": "->"
},
"when": "editorTextFocus"
} }
], ],
"commands": [ "commands": [
@ -171,7 +196,7 @@
{ {
"command": "variable-conversion.toUpperCase", "command": "variable-conversion.toUpperCase",
"title": "全大写 (Upper Case) [ FOOBAR ]" "title": "全大写 (Upper Case) [ FOOBAR ]"
} },
// 隐藏命令 // 隐藏命令
// { // {
// "command": "editor.action.transformToCamelcase", // "command": "editor.action.transformToCamelcase",
@ -202,26 +227,61 @@
// "command": "editor.action.transformToSnakecase", // "command": "editor.action.transformToSnakecase",
// "title": "[VSCode 自带] 转换为蛇形命名法 (Snake Case) [ foo_bar ]", // "title": "[VSCode 自带] 转换为蛇形命名法 (Snake Case) [ foo_bar ]",
// "enablement": "false" // "enablement": "false"
// } // },
/**
* 右键菜单
*/
{
"command": "variable-conversion.convertPath",
"title": "路径转换"
},
/**
* 右键菜单 - 子菜单
*/
// group-1-common-style
{
"command": "variable-conversion.pathFormat.toWindowsStyle",
"title": "Windows 风格 [ C:\\Windows\\System32 ]"
},
{
"command": "variable-conversion.pathFormat.toUnixStyle",
"title": "Unix 风格 [ /usr/bin ]"
}
], ],
// docs: https://code.visualstudio.com/api/references/contribution-points#contributes.menus // docs: https://code.visualstudio.com/api/references/contribution-points#contributes.menus
"menus": { "menus": {
// 编辑器右键菜单 // 编辑器右键菜单
"editor/context": [ "editor/context": [
// 变量转换
{ {
// "when": "editorTextFocus", // "when": "editorTextFocus",
// 2024.12.07 当未选中文字时,隐藏 [变量转换] 右键菜单 // 2024.12.07 当未选中文字时,隐藏 [变量转换] 右键菜单
"when": "editorTextFocus && _textSelectionLength >= 1", "when": "editorTextFocus && _textSelectionLength >= 1",
"command": "variable-conversion.convertCase", "command": "variable-conversion.convertCase",
// "group": "1_modification@9" // "group": "1_modification@9"
"group": "navigation@9" "group": "navigation@10"
}, },
// 将变量转换为...
{ {
"when": "editorTextFocus && _textSelectionLength >= 1", "when": "editorTextFocus && _textSelectionLength >= 1",
"submenu": "variable-conversion.stringConversionMenu", "submenu": "variable-conversion.stringConversionMenu",
// docs: https://code.visualstudio.com/api/references/contribution-points#Sorting-of-groups // docs: https://code.visualstudio.com/api/references/contribution-points#Sorting-of-groups
// "group": "1_modification@9" // "group": "1_modification@9"
"group": "navigation@9" "group": "navigation@11"
},
// 路径转换
{
// "when": "editorTextFocus",
// 2024.12.07 当未选中文字时,隐藏 [变量转换] 右键菜单
"when": "editorTextFocus && _textSelectionLength >= 1",
"command": "variable-conversion.convertPath",
"group": "navigation@12"
},
// 将路径转换为...
{
"when": "editorTextFocus && _textSelectionLength >= 1",
"submenu": "variable-conversion.pathConversionMenu",
"group": "navigation@13"
} }
], ],
"variable-conversion.stringConversionMenu": [ "variable-conversion.stringConversionMenu": [
@ -362,6 +422,21 @@
// "group": "group-vscode", // "group": "group-vscode",
// "when": "false" // "when": "false"
// } // }
],
"variable-conversion.pathConversionMenu": [
// group-1-common-style
{
// Windows 风格
"when": "!_isHideSubMenuItem_windows_style",
"command": "variable-conversion.pathFormat.toWindowsStyle",
"group": "group-1-common-style@1"
},
{
// Unix 风格
"when": "!_isHideSubMenuItem_unix_style",
"command": "variable-conversion.pathFormat.toUnixStyle",
"group": "group-1-common-style@2"
}
] ]
}, },
// docs: https://code.visualstudio.com/api/references/contribution-points#contributes.submenus // docs: https://code.visualstudio.com/api/references/contribution-points#contributes.submenus
@ -369,6 +444,10 @@
{ {
"id": "variable-conversion.stringConversionMenu", "id": "variable-conversion.stringConversionMenu",
"label": "将变量转换为..." "label": "将变量转换为..."
},
{
"id": "variable-conversion.pathConversionMenu",
"label": "将路径转换为..."
} }
], ],
// docs: https://code.visualstudio.com/api/references/contribution-points#contributes.configuration // docs: https://code.visualstudio.com/api/references/contribution-points#contributes.configuration
@ -407,7 +486,7 @@
"variable-conversion.disableFormat": { "variable-conversion.disableFormat": {
"order": 1, "order": 1,
// markdownDescription 最多配置 11 行 // markdownDescription 最多配置 11 行
"markdownDescription": "定义哪些格式是禁用的\n\nDefine which formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disableFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)", "markdownDescription": "定义哪些变量命名方式是禁用的\n\nDefine which variable formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disableFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)",
"type": "array", "type": "array",
"items": { "items": {
"type": "string", "type": "string",
@ -537,6 +616,25 @@
"lower_case", "lower_case",
"upper_case" "upper_case"
] ]
},
// TODO
"variable-conversion.disablePathFormat": {
"order": 3,
// markdownDescription 最多配置 11 行
"markdownDescription": "定义哪些路径风格是禁用的\n\nDefine which path formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disablePathFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)",
"type": "array",
"items": {
"type": "string",
"enum": [
"windows_style",
"unix_style"
],
"enumDescriptions": [
"Windows 风格",
"Unix 风格"
]
},
"default": []
} }
} }
} }

View File

@ -2,7 +2,7 @@
"name": "variable-conversion", "name": "variable-conversion",
"displayName": "Variable Conversion", "displayName": "Variable Conversion",
"description": "一个强大的变量名转换插件,支持右键菜单、快捷键、状态栏等多种方式使用,支持小驼峰、大驼峰(帕斯卡)、下划线(蛇形)、中划线(连字符/脊柱式)、空格分隔、点分隔、全小写、全大写等常用命名方式(及组合)转换。 \nA powerful variable naming conversion extension. You can use it through the editer menu, shortcut keys and bottom bar. Support camel, pascal, snake, kebab(spinal), space, dot, lower, upper case, and more.", "description": "一个强大的变量名转换插件,支持右键菜单、快捷键、状态栏等多种方式使用,支持小驼峰、大驼峰(帕斯卡)、下划线(蛇形)、中划线(连字符/脊柱式)、空格分隔、点分隔、全小写、全大写等常用命名方式(及组合)转换。 \nA powerful variable naming conversion extension. You can use it through the editer menu, shortcut keys and bottom bar. Support camel, pascal, snake, kebab(spinal), space, dot, lower, upper case, and more.",
"version": "1.1.0", "version": "2.0.0",
"icon": "image/logo.png", "icon": "image/logo.png",
"publisher": "coder-xiaomo", "publisher": "coder-xiaomo",
"engines": { "engines": {
@ -52,6 +52,27 @@
"arrowKey": "]" "arrowKey": "]"
}, },
"when": "editorTextFocus" "when": "editorTextFocus"
},
{
"command": "variable-conversion.convertPath",
"key": "shift+alt+/",
"when": "editorTextFocus"
},
{
"command": "variable-conversion.cyclicConvertPath.previous",
"key": "ctrl+alt+shift+/",
"args": {
"direction": "<-"
},
"when": "editorTextFocus"
},
{
"command": "variable-conversion.cyclicConvertPath.next",
"key": "ctrl+alt+/",
"args": {
"direction": "->"
},
"when": "editorTextFocus"
} }
], ],
"commands": [ "commands": [
@ -138,6 +159,18 @@
{ {
"command": "variable-conversion.toUpperCase", "command": "variable-conversion.toUpperCase",
"title": "全大写 (Upper Case) [ FOOBAR ]" "title": "全大写 (Upper Case) [ FOOBAR ]"
},
{
"command": "variable-conversion.convertPath",
"title": "路径转换"
},
{
"command": "variable-conversion.pathFormat.toWindowsStyle",
"title": "Windows 风格 [ C:\\Windows\\System32 ]"
},
{
"command": "variable-conversion.pathFormat.toUnixStyle",
"title": "Unix 风格 [ /usr/bin ]"
} }
], ],
"menus": { "menus": {
@ -145,12 +178,22 @@
{ {
"when": "editorTextFocus && _textSelectionLength >= 1", "when": "editorTextFocus && _textSelectionLength >= 1",
"command": "variable-conversion.convertCase", "command": "variable-conversion.convertCase",
"group": "navigation@9" "group": "navigation@10"
}, },
{ {
"when": "editorTextFocus && _textSelectionLength >= 1", "when": "editorTextFocus && _textSelectionLength >= 1",
"submenu": "variable-conversion.stringConversionMenu", "submenu": "variable-conversion.stringConversionMenu",
"group": "navigation@9" "group": "navigation@11"
},
{
"when": "editorTextFocus && _textSelectionLength >= 1",
"command": "variable-conversion.convertPath",
"group": "navigation@12"
},
{
"when": "editorTextFocus && _textSelectionLength >= 1",
"submenu": "variable-conversion.pathConversionMenu",
"group": "navigation@13"
} }
], ],
"variable-conversion.stringConversionMenu": [ "variable-conversion.stringConversionMenu": [
@ -254,12 +297,28 @@
"command": "variable-conversion.toUpperCase", "command": "variable-conversion.toUpperCase",
"group": "group-6-upper-lower@2" "group": "group-6-upper-lower@2"
} }
],
"variable-conversion.pathConversionMenu": [
{
"when": "!_isHideSubMenuItem_windows_style",
"command": "variable-conversion.pathFormat.toWindowsStyle",
"group": "group-1-common-style@1"
},
{
"when": "!_isHideSubMenuItem_unix_style",
"command": "variable-conversion.pathFormat.toUnixStyle",
"group": "group-1-common-style@2"
}
] ]
}, },
"submenus": [ "submenus": [
{ {
"id": "variable-conversion.stringConversionMenu", "id": "variable-conversion.stringConversionMenu",
"label": "将变量转换为..." "label": "将变量转换为..."
},
{
"id": "variable-conversion.pathConversionMenu",
"label": "将路径转换为..."
} }
], ],
"configuration": { "configuration": {
@ -267,7 +326,7 @@
"properties": { "properties": {
"variable-conversion.disableFormat": { "variable-conversion.disableFormat": {
"order": 1, "order": 1,
"markdownDescription": "定义哪些格式是禁用的\n\nDefine which formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disableFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)", "markdownDescription": "定义哪些变量命名方式是禁用的\n\nDefine which variable formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disableFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)",
"type": "array", "type": "array",
"items": { "items": {
"type": "string", "type": "string",
@ -317,6 +376,23 @@
] ]
}, },
"default": [] "default": []
},
"variable-conversion.disablePathFormat": {
"order": 3,
"markdownDescription": "定义哪些路径风格是禁用的\n\nDefine which path formats are disabled.\n\n若您感觉以下配置比较麻烦也可以选择在 `settings.json` 中编辑:\n\nIf you find the following configuration troublesome, you can also edit this configuration item in `settings.json`:\n\n`\"variable-conversion.disablePathFormat\": [ ... ],`\n\n[在 settings.json 中编辑 (Edit in settings.json)](command:workbench.action.openSettingsJson)\n\n配置后您可能需要*重启扩展宿主*,或*重启当前窗口*才可使该配置完全生效(二选一即可):\n\nYou may need to *restart extension host* or *reload window* after configuration to take full effect (either):\n\n[重启扩展宿主 (Restart Extension Host)](command:workbench.action.restartExtensionHost), [重启当前窗口 (Reload Window)](command:workbench.action.reloadWindow)",
"type": "array",
"items": {
"type": "string",
"enum": [
"windows_style",
"unix_style"
],
"enumDescriptions": [
"Windows 风格",
"Unix 风格"
]
},
"default": []
} }
} }
} }

View File

@ -0,0 +1,62 @@
import { EOL } from "../../types/EOLType";
import { SupportPathFormat } from "./types/SupportPathFormatType";
import { TransformTextResult } from '../../types/TransformTextResultType';
/** / */
const LEFT_SLASH = '/';
/** \ */
const RIGHT_SLASH = '\\';
/** \\ */
const DOUBLE_RIGHT_SLASH = '\\\\';
export function pathConversion(targetPathType: SupportPathFormat, input: string, eol: EOL, cutText: Array<TransformTextResult> | undefined = undefined): string {
let resultPath;
let isSeperator = false;
switch (targetPathType) {
case SupportPathFormat.Windows:
// 将其中的 / 替换为 \
resultPath = Array.from(input).map((char: string) => {
if (char !== LEFT_SLASH) {
// 当前字符不是 /
isSeperator = false;
return char;
} else {
// 当前字符是 /
if (!isSeperator) {
// 上一字符不是 /
isSeperator = true;
return RIGHT_SLASH; // 替换成 \
}
// 上一字符是 /
return '';
}
}).join('');
break;
case SupportPathFormat.Unix:
// 将其中的 \\ 和 \ 替换为 /
resultPath = Array.from(input).map((char: string) => {
if (char !== RIGHT_SLASH) {
// 当前字符不是 \
isSeperator = false;
return char;
} else {
// 当前字符是 \
if (!isSeperator) {
// 上一字符不是 \
isSeperator = true;
return LEFT_SLASH; // 替换成 /
}
// 上一字符是 \
return '';
}
}).join('');
break;
// case SupportPathFormat.WindowsGitBash:
// break;
default:
return input;
}
return resultPath;
}

View File

@ -0,0 +1,116 @@
import * as vscode from 'vscode';
import { EOL } from "../../types/EOLType";
import { cyclicConvertPathOrder } from "./types/SupportPathFormatType";
import { pathConversion } from "./conversion";
import { isStringArrayEqual, stringListArrayDuplicateRemoval } from '../../utils/utils';
import { getUserConfigurations } from '../../utils/user-configuration';
interface UserSelection {
currentEol: EOL
currentSelections?: readonly vscode.Selection[]
currentSelectionsText: string[]
currentIndex: number
isConverted: boolean
conversionsTarget: Array<string[]>
lastConvertedSelectionsText: string[] // 按快捷键后转换的值(如果下次触发 onUserSelectionUpdated 后传入值是这个,那么跳过,避免丢失当前循环转换记录)
}
const userSelection: UserSelection = {
currentEol: '\n',
// currentSelections: undefined,
currentSelectionsText: [],
currentIndex: 0,
isConverted: false,
conversionsTarget: [], // 转换后去重 剩余转换目标
lastConvertedSelectionsText: [],
};
export function onUserSelectionUpdated(selections: readonly vscode.Selection[], textList: string[], eol: EOL): void {
userSelection.currentSelections = selections;
if (textList.length !== 0 && isStringArrayEqual(textList, userSelection.lastConvertedSelectionsText)) {
// console.log('skip onUserSelectionUpdated');
return;
}
// console.log('onUserSelectionUpdated', textList, userSelection.lastConvertedSelectionsText);
userSelection.currentEol = eol;
userSelection.currentSelectionsText = textList;
userSelection.currentIndex = 0;
userSelection.isConverted = false;
userSelection.conversionsTarget = [textList];
userSelection.lastConvertedSelectionsText = textList;
}
export function previousOne() {
lazyConvert();
const length = userSelection.conversionsTarget.length;
const oldIndex = userSelection.currentIndex;
const newIndex = oldIndex === 0 ? (length - 1) : (oldIndex - 1);
userSelection.currentIndex = newIndex;
console.log('previousOne oldIndex', oldIndex, 'newIndex', newIndex);
replaceTextEditorSelectedText();
}
export function nextOne() {
lazyConvert();
const length = userSelection.conversionsTarget.length;
const oldIndex = userSelection.currentIndex;
const newIndex = oldIndex >= length - 1 ? 0 : (oldIndex + 1);
userSelection.currentIndex = newIndex;
console.log('nextOne oldIndex', oldIndex, 'newIndex', newIndex);
replaceTextEditorSelectedText();
}
function lazyConvert() {
if (userSelection.isConverted) {
return;
}
// 获取用户配置
// TODO
// const disablePathFormatList = getUserConfigurations<Array<string>>('disablePathFormat') || [];
const textList = userSelection.currentSelectionsText;
// vscode.window.showInformationMessage('lazyConvert' + textList.join('\n'));
const eol = userSelection.currentEol;
const conversionsTarget: Array<string[]> = [textList];
for (const cyclicConvertCase of cyclicConvertPathOrder) {
// 跳过禁用的目标格式
// TODO
// if (disablePathFormatList.includes(cyclicConvertCase.settingsKey)) {
// continue;
// }
// 每一个类型
const conversionsTargetItem: string[] = [];
for (const line of textList) {
// 选中区块的每一行
const conversionResult: string = pathConversion(cyclicConvertCase.type, line, eol);
conversionsTargetItem.push(conversionResult);
}
conversionsTarget.push(conversionsTargetItem);
}
// 按数组去重
const noDuplicate = stringListArrayDuplicateRemoval(conversionsTarget);
// console.log('noDuplicate', noDuplicate);
userSelection.conversionsTarget = noDuplicate;
userSelection.isConverted = true;
}
function replaceTextEditorSelectedText() {
let editor = vscode.window.activeTextEditor;
if (editor) {
const selections = userSelection.currentSelections || [];
const textList = userSelection.conversionsTarget[userSelection.currentIndex];
console.log('selections', selections, 'textList', textList);
editor.edit(editBuilder => {
for (let i = 0; i < selections.length; i++) {
const selection = selections[i];
const converted = textList[i];
editBuilder.replace(selection, converted);
}
});
userSelection.lastConvertedSelectionsText = textList;
}
}

View File

@ -0,0 +1,101 @@
/**
*
*
* @since 2024-12-14
*/
export enum SupportPathFormat {
/**
* Windows
*
* @alias: windows / Windows
* @since 2024-12-07
*/
Windows,
/**
* Unix
*
* @alias: unix / Unix
* @since 2024-12-07
*/
Unix,
};
const keyword = {
windows: [
'Windows', 'win',
],
unix: [
'Unix',
'Linux',
'macOS',
],
};
/**
*
*
* @since 2024-12-14
*/
export const commands: Array<{ command: string; targetCase: SupportPathFormat; settingsKey: string }> = [
{
command: 'variable-conversion.pathFormat.toWindowsStyle',
targetCase: SupportPathFormat.Windows,
settingsKey: 'windows_style'
},
{
command: 'variable-conversion.pathFormat.toUnixStyle',
targetCase: SupportPathFormat.Unix,
settingsKey: 'unix_style'
},
];
/**
* @since 2024-12-14
*/
export interface QuickPickSupportCaseItem {
type: SupportPathFormat,
name: string,
shortName: string,
keyword: string[],
settingsKey: string,
}
/**
*
* @since 2024-12-14
*/
export const quickPickSupportCases: Array<QuickPickSupportCaseItem> = [
{
type: SupportPathFormat.Windows,
name: 'Microsoft Windows 风格',
shortName: 'Windows 风格',
keyword: keyword.windows,
settingsKey: 'windows_style',
},
{
type: SupportPathFormat.Unix,
name: 'Unix / 类 Unix 风格 (Linux, macOS, ...)',
shortName: 'Unix 风格',
keyword: keyword.unix,
settingsKey: 'unix_style',
},
];
/**
* @since 2024-12-14
*/
export interface CyclicConvertPathOrderItem {
type: SupportPathFormat,
settingsKey: string,
}
/**
*
* @since 2024-12-14
*/
export const cyclicConvertPathOrder: Array<CyclicConvertPathOrderItem> = [
{ type: SupportPathFormat.Windows, settingsKey: 'windows' },
{ type: SupportPathFormat.Unix, settingsKey: 'unix' },
];

View File

@ -1,52 +1,53 @@
import { EOL } from '../../type-definition/EOLType'; import { EOL } from '../../types/EOLType';
import { SupportCase } from '../../type-definition/SupportCaseType'; import { SupportVariableCase } from './types/SupportVariableCaseType';
import { TransformTextResult } from '../../type-definition/TransformTextResultType'; import { TransformTextResult } from '../../types/TransformTextResultType';
import { transformMutliLineText, transformText } from './transform'; import { transformMutliLineText, transformText } from '../../utils/transform';
/** /**
* *
* *
* @param {SupportCase} targetCase * @param {SupportVariableCase} targetCase
* @param {string} str user selection * @param {string} str user selection
* @param {EOL} eol * @param {EOL} eol
* @param {Array<TransformTextResult>?} cutText
* @returns * @returns
* @since 2024-04-04 * @since 2024-04-04
*/ */
export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, cutText: Array<TransformTextResult> | undefined = undefined): string { export function caseConversion(targetCase: SupportVariableCase, str: string, eol: EOL, cutText: Array<TransformTextResult> | undefined = undefined): string {
let spaceCharacter: '-' | '_' | ' ' | '.' | undefined = undefined; let spaceCharacter: '-' | '_' | ' ' | '.' | undefined = undefined;
switch (targetCase) { switch (targetCase) {
default: default:
case SupportCase.CAMEL_CASE: // 小驼峰(驼峰)命名 case SupportVariableCase.CAMEL_CASE: // 小驼峰(驼峰)命名
case SupportCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名 case SupportVariableCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名
spaceCharacter = undefined; spaceCharacter = undefined;
break; break;
case SupportCase.SNAKE_CASE: // 下划线(蛇形)命名 case SupportVariableCase.SNAKE_CASE: // 下划线(蛇形)命名
case SupportCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名 case SupportVariableCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名
case SupportCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名 case SupportVariableCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名 case SupportVariableCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
spaceCharacter = '_'; spaceCharacter = '_';
break; break;
case SupportCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名 case SupportVariableCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名
case SupportCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名 case SupportVariableCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名
case SupportCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名 case SupportVariableCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名
case SupportCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名 case SupportVariableCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名
spaceCharacter = '-'; spaceCharacter = '-';
break; break;
case SupportCase.SPACE_CASE: // 空格分隔命名 case SupportVariableCase.SPACE_CASE: // 空格分隔命名
case SupportCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名 case SupportVariableCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名
case SupportCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名 case SupportVariableCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名
case SupportCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名 case SupportVariableCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名
spaceCharacter = ' '; spaceCharacter = ' ';
break; break;
case SupportCase.DOT_CASE: // 点分隔命名 case SupportVariableCase.DOT_CASE: // 点分隔命名
case SupportCase.DOT_CAMEL_CASE: // 点分隔 + 小驼峰(驼峰)命名 case SupportVariableCase.DOT_CAMEL_CASE: // 点分隔 + 小驼峰(驼峰)命名
case SupportCase.DOT_PASCAL_CASE: // 点分隔 + 大驼峰(帕斯卡)命名 case SupportVariableCase.DOT_PASCAL_CASE: // 点分隔 + 大驼峰(帕斯卡)命名
case SupportCase.DOT_UPPER_CASE: // 点分隔 + 全大写命名 case SupportVariableCase.DOT_UPPER_CASE: // 点分隔 + 全大写命名
spaceCharacter = '.'; spaceCharacter = '.';
break; break;
case SupportCase.LOWER_CASE: // 全小写 case SupportVariableCase.LOWER_CASE: // 全小写
return str.toLowerCase(); return str.toLowerCase();
case SupportCase.UPPER_CASE: // 全大写 case SupportVariableCase.UPPER_CASE: // 全大写
return str.toUpperCase(); return str.toUpperCase();
} }
@ -84,11 +85,11 @@ export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, c
// 根据目标情况转换单词 // 根据目标情况转换单词
switch (targetCase) { switch (targetCase) {
case SupportCase.CAMEL_CASE: // 小驼峰(驼峰)命名 case SupportVariableCase.CAMEL_CASE: // 小驼峰(驼峰)命名
case SupportCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名 case SupportVariableCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名
case SupportCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名 case SupportVariableCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名
case SupportCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名 case SupportVariableCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名
case SupportCase.DOT_CAMEL_CASE: // 点分隔 + 小驼峰(驼峰)命名 case SupportVariableCase.DOT_CAMEL_CASE: // 点分隔 + 小驼峰(驼峰)命名
if (isFirstWord) { if (isFirstWord) {
transformedWords.push(word); transformedWords.push(word);
if (isCurrentWordNormal) { if (isCurrentWordNormal) {
@ -98,23 +99,23 @@ export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, c
transformedWords.push(pascalCaseWord); transformedWords.push(pascalCaseWord);
} }
break; break;
case SupportCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名 case SupportVariableCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名
case SupportCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名 case SupportVariableCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名
case SupportCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名 case SupportVariableCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名
case SupportCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名 case SupportVariableCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名
case SupportCase.DOT_PASCAL_CASE: // 点分隔 + 大驼峰(帕斯卡)命名 case SupportVariableCase.DOT_PASCAL_CASE: // 点分隔 + 大驼峰(帕斯卡)命名
transformedWords.push(pascalCaseWord); transformedWords.push(pascalCaseWord);
break; break;
case SupportCase.SNAKE_CASE: // 下划线(蛇形)命名 case SupportVariableCase.SNAKE_CASE: // 下划线(蛇形)命名
case SupportCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名 case SupportVariableCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名
case SupportCase.SPACE_CASE: // 空格分隔命名 case SupportVariableCase.SPACE_CASE: // 空格分隔命名
case SupportCase.DOT_CASE: // 点分隔命名x case SupportVariableCase.DOT_CASE: // 点分隔命名x
transformedWords.push(word); transformedWords.push(word);
break; break;
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名 case SupportVariableCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
case SupportCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名 case SupportVariableCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名
case SupportCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名 case SupportVariableCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名
case SupportCase.DOT_UPPER_CASE: // 点分隔 + 全大写命名 case SupportVariableCase.DOT_UPPER_CASE: // 点分隔 + 全大写命名
transformedWords.push(word.toUpperCase()); transformedWords.push(word.toUpperCase());
break; break;
default: default:

View File

@ -1,9 +1,9 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { EOL } from "../../type-definition/EOLType"; import { EOL } from "../../types/EOLType";
import { cyclicConvertCaseOrder } from "../../type-definition/SupportCaseType"; import { cyclicConvertCaseOrder } from "./types/SupportVariableCaseType";
import { caseConversion } from "./conversion"; import { caseConversion } from "./conversion";
import { isStringArrayEqual, stringListArrayDuplicateRemoval } from '../utils'; import { isStringArrayEqual, stringListArrayDuplicateRemoval } from '../../utils/utils';
import { getUserConfigurations } from '../user-configuration'; import { getUserConfigurations } from '../../utils/user-configuration';
interface UserSelection { interface UserSelection {
currentEol: EOL currentEol: EOL

View File

@ -1,13 +1,13 @@
/** /**
* When support a new case, there's something we need to do. * When support a new variable case, there's something we need to do.
* *
* Code: * Code:
* - Add type definition in below `SupportCase` enum and following array * - Add type definition in below `SupportCase` enum and following array
* - Add `commands`, `menus`, `configuration` parts in [package.json] and [package-comment.jsonc] * - Add `commands`, `menus`, `configuration` parts in [package.json] and [package-comment.jsonc]
* - Add main conversion logic in [src/main-code/conversion.ts] * - Add main conversion logic in [src/core/variable-convert/conversion.ts]
* *
* Test: * Test:
* - Add test case type definition in [src/type-definition/TestCaseType.ts] * - Add test case type definition in [src/test/types/TestCaseType.ts]
* - Add test case in [src/test/test-case.ts] * - Add test case in [src/test/test-case.ts]
* - Add test code in [src/test/extension.test.ts] * - Add test code in [src/test/extension.test.ts]
* *
@ -15,7 +15,7 @@
* - Modify `description` in [package.json] and [package-comment.jsonc] * - Modify `description` in [package.json] and [package-comment.jsonc]
* - Add changes in [CHANGELOG.md] and [README.md] * - Add changes in [CHANGELOG.md] and [README.md]
*/ */
export enum SupportCase { export enum SupportVariableCase {
/** /**
* () * ()
@ -281,116 +281,116 @@ const keyword = {
/** /**
* *
*/ */
export const commands: Array<{ command: string; targetCase: SupportCase; settingsKey: string }> = [ export const commands: Array<{ command: string; targetCase: SupportVariableCase; settingsKey: string }> = [
{ {
command: 'variable-conversion.toCamelCase', command: 'variable-conversion.toCamelCase',
targetCase: SupportCase.CAMEL_CASE, targetCase: SupportVariableCase.CAMEL_CASE,
settingsKey: 'camel_case' settingsKey: 'camel_case'
}, },
{ {
command: 'variable-conversion.toPascalCase', command: 'variable-conversion.toPascalCase',
targetCase: SupportCase.PASCAL_CASE, targetCase: SupportVariableCase.PASCAL_CASE,
settingsKey: 'pascal_case' settingsKey: 'pascal_case'
}, },
// +++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++
{ {
command: 'variable-conversion.toSnakeCase', command: 'variable-conversion.toSnakeCase',
targetCase: SupportCase.SNAKE_CASE, targetCase: SupportVariableCase.SNAKE_CASE,
settingsKey: 'snake_case' settingsKey: 'snake_case'
}, },
{ {
command: 'variable-conversion.toSnakeUpperCase', command: 'variable-conversion.toSnakeUpperCase',
targetCase: SupportCase.SNAKE_UPPER_CASE, targetCase: SupportVariableCase.SNAKE_UPPER_CASE,
settingsKey: 'snake_upper_case' settingsKey: 'snake_upper_case'
}, },
{ {
command: 'variable-conversion.toSnakePascalCase', command: 'variable-conversion.toSnakePascalCase',
targetCase: SupportCase.SNAKE_PASCAL_CASE, targetCase: SupportVariableCase.SNAKE_PASCAL_CASE,
settingsKey: 'snake_pascal_case' settingsKey: 'snake_pascal_case'
}, },
{ {
command: 'variable-conversion.toSnakeCamelCase', command: 'variable-conversion.toSnakeCamelCase',
targetCase: SupportCase.SNAKE_CAMEL_CASE, targetCase: SupportVariableCase.SNAKE_CAMEL_CASE,
settingsKey: 'snake_camel_case' settingsKey: 'snake_camel_case'
}, },
// +++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++
{ {
command: 'variable-conversion.toKebabCase', command: 'variable-conversion.toKebabCase',
targetCase: SupportCase.KEBAB_CASE, targetCase: SupportVariableCase.KEBAB_CASE,
settingsKey: 'kebab_case' settingsKey: 'kebab_case'
}, },
{ {
command: 'variable-conversion.toKebabUpperCase', command: 'variable-conversion.toKebabUpperCase',
targetCase: SupportCase.KEBAB_UPPER_CASE, targetCase: SupportVariableCase.KEBAB_UPPER_CASE,
settingsKey: 'kebab_upper_case' settingsKey: 'kebab_upper_case'
}, },
{ {
command: 'variable-conversion.toKebabPascalCase', command: 'variable-conversion.toKebabPascalCase',
targetCase: SupportCase.KEBAB_PASCAL_CASE, targetCase: SupportVariableCase.KEBAB_PASCAL_CASE,
settingsKey: 'kebab_pascal_case' settingsKey: 'kebab_pascal_case'
}, },
{ {
command: 'variable-conversion.toKebabCamelCase', command: 'variable-conversion.toKebabCamelCase',
targetCase: SupportCase.KEBAB_CAMEL_CASE, targetCase: SupportVariableCase.KEBAB_CAMEL_CASE,
settingsKey: 'kebab_camel_case' settingsKey: 'kebab_camel_case'
}, },
// +++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++
{ {
command: 'variable-conversion.toSpaceCase', command: 'variable-conversion.toSpaceCase',
targetCase: SupportCase.SPACE_CASE, targetCase: SupportVariableCase.SPACE_CASE,
settingsKey: 'space_case' settingsKey: 'space_case'
}, },
{ {
command: 'variable-conversion.toSpaceUpperCase', command: 'variable-conversion.toSpaceUpperCase',
targetCase: SupportCase.SPACE_UPPER_CASE, targetCase: SupportVariableCase.SPACE_UPPER_CASE,
settingsKey: 'space_upper_case' settingsKey: 'space_upper_case'
}, },
{ {
command: 'variable-conversion.toSpacePascalCase', command: 'variable-conversion.toSpacePascalCase',
targetCase: SupportCase.SPACE_PASCAL_CASE, targetCase: SupportVariableCase.SPACE_PASCAL_CASE,
settingsKey: 'space_pascal_case' settingsKey: 'space_pascal_case'
}, },
{ {
command: 'variable-conversion.toSpaceCamelCase', command: 'variable-conversion.toSpaceCamelCase',
targetCase: SupportCase.SPACE_CAMEL_CASE, targetCase: SupportVariableCase.SPACE_CAMEL_CASE,
settingsKey: 'space_camel_case' settingsKey: 'space_camel_case'
}, },
// +++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++
{ {
command: 'variable-conversion.toDotCase', command: 'variable-conversion.toDotCase',
targetCase: SupportCase.DOT_CASE, targetCase: SupportVariableCase.DOT_CASE,
settingsKey: 'dot_case' settingsKey: 'dot_case'
}, },
{ {
command: 'variable-conversion.toDotUpperCase', command: 'variable-conversion.toDotUpperCase',
targetCase: SupportCase.DOT_UPPER_CASE, targetCase: SupportVariableCase.DOT_UPPER_CASE,
settingsKey: 'dot_upper_case' settingsKey: 'dot_upper_case'
}, },
{ {
command: 'variable-conversion.toDotPascalCase', command: 'variable-conversion.toDotPascalCase',
targetCase: SupportCase.DOT_PASCAL_CASE, targetCase: SupportVariableCase.DOT_PASCAL_CASE,
settingsKey: 'dot_pascal_case' settingsKey: 'dot_pascal_case'
}, },
{ {
command: 'variable-conversion.toDotCamelCase', command: 'variable-conversion.toDotCamelCase',
targetCase: SupportCase.DOT_CAMEL_CASE, targetCase: SupportVariableCase.DOT_CAMEL_CASE,
settingsKey: 'dot_camel_case' settingsKey: 'dot_camel_case'
}, },
// +++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++
{ {
command: 'variable-conversion.toLowerCase', command: 'variable-conversion.toLowerCase',
targetCase: SupportCase.LOWER_CASE, targetCase: SupportVariableCase.LOWER_CASE,
settingsKey: 'lower_case' settingsKey: 'lower_case'
}, },
{ {
command: 'variable-conversion.toUpperCase', command: 'variable-conversion.toUpperCase',
targetCase: SupportCase.UPPER_CASE, targetCase: SupportVariableCase.UPPER_CASE,
settingsKey: 'upper_case' settingsKey: 'upper_case'
}, },
]; ];
export interface QuickPickSupportCaseItem { export interface QuickPickSupportCaseItem {
type: SupportCase, type: SupportVariableCase,
name: string, name: string,
shortName: string, shortName: string,
keyword: string[], keyword: string[],
@ -403,140 +403,140 @@ export interface QuickPickSupportCaseItem {
*/ */
export const quickPickSupportCases: Array<QuickPickSupportCaseItem> = [ export const quickPickSupportCases: Array<QuickPickSupportCaseItem> = [
{ {
type: SupportCase.CAMEL_CASE, type: SupportVariableCase.CAMEL_CASE,
name: '小驼峰(驼峰)命名', name: '小驼峰(驼峰)命名',
shortName: '小驼峰', shortName: '小驼峰',
keyword: keyword.camel, keyword: keyword.camel,
settingsKey: 'camel_case', settingsKey: 'camel_case',
}, },
{ {
type: SupportCase.PASCAL_CASE, type: SupportVariableCase.PASCAL_CASE,
name: '大驼峰(帕斯卡)命名', name: '大驼峰(帕斯卡)命名',
shortName: '帕斯卡', shortName: '帕斯卡',
keyword: keyword.pascal, keyword: keyword.pascal,
settingsKey: 'pascal_case', settingsKey: 'pascal_case',
}, },
{ {
type: SupportCase.SNAKE_CASE, type: SupportVariableCase.SNAKE_CASE,
name: '下划线(蛇形)命名', name: '下划线(蛇形)命名',
shortName: '蛇形', shortName: '蛇形',
keyword: [...keyword.snake, ...keyword.lower], keyword: [...keyword.snake, ...keyword.lower],
settingsKey: 'snake_case', settingsKey: 'snake_case',
}, },
{ {
type: SupportCase.SNAKE_CAMEL_CASE, type: SupportVariableCase.SNAKE_CAMEL_CASE,
name: '下划线(蛇形) + 小驼峰(驼峰)命名', name: '下划线(蛇形) + 小驼峰(驼峰)命名',
shortName: '蛇形驼峰', shortName: '蛇形驼峰',
keyword: [...keyword.snake, ...keyword.camel], keyword: [...keyword.snake, ...keyword.camel],
settingsKey: 'snake_camel_case', settingsKey: 'snake_camel_case',
}, },
{ {
type: SupportCase.SNAKE_PASCAL_CASE, type: SupportVariableCase.SNAKE_PASCAL_CASE,
name: '下划线(蛇形) + 大驼峰(帕斯卡)命名', name: '下划线(蛇形) + 大驼峰(帕斯卡)命名',
shortName: '蛇形帕斯卡', shortName: '蛇形帕斯卡',
keyword: [...keyword.snake, ...keyword.pascal], keyword: [...keyword.snake, ...keyword.pascal],
settingsKey: 'snake_pascal_case', settingsKey: 'snake_pascal_case',
}, },
{ {
type: SupportCase.SNAKE_UPPER_CASE, type: SupportVariableCase.SNAKE_UPPER_CASE,
name: '下划线(蛇形) + 全大写命名', name: '下划线(蛇形) + 全大写命名',
shortName: '蛇形大写', shortName: '蛇形大写',
keyword: [...keyword.snake, ...keyword.upper], keyword: [...keyword.snake, ...keyword.upper],
settingsKey: 'snake_upper_case', settingsKey: 'snake_upper_case',
}, },
{ {
type: SupportCase.KEBAB_CASE, type: SupportVariableCase.KEBAB_CASE,
name: '中划线(连字符/脊柱式)命名', name: '中划线(连字符/脊柱式)命名',
shortName: '脊柱', shortName: '脊柱',
keyword: [...keyword.kebab, ...keyword.lower], keyword: [...keyword.kebab, ...keyword.lower],
settingsKey: 'kebab_case', settingsKey: 'kebab_case',
}, },
{ {
type: SupportCase.KEBAB_CAMEL_CASE, type: SupportVariableCase.KEBAB_CAMEL_CASE,
name: '中划线(连字符/脊柱式) + 小驼峰(驼峰)命名', name: '中划线(连字符/脊柱式) + 小驼峰(驼峰)命名',
shortName: '脊柱驼峰', shortName: '脊柱驼峰',
keyword: [...keyword.kebab, ...keyword.camel], keyword: [...keyword.kebab, ...keyword.camel],
settingsKey: 'kebab_camel_case', settingsKey: 'kebab_camel_case',
}, },
{ {
type: SupportCase.KEBAB_PASCAL_CASE, type: SupportVariableCase.KEBAB_PASCAL_CASE,
name: '中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名', name: '中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名',
shortName: '脊柱帕斯卡', shortName: '脊柱帕斯卡',
keyword: [...keyword.kebab, ...keyword.pascal], keyword: [...keyword.kebab, ...keyword.pascal],
settingsKey: 'kebab_pascal_case', settingsKey: 'kebab_pascal_case',
}, },
{ {
type: SupportCase.KEBAB_UPPER_CASE, type: SupportVariableCase.KEBAB_UPPER_CASE,
name: '中划线(连字符/脊柱式) + 全大写命名', name: '中划线(连字符/脊柱式) + 全大写命名',
shortName: '脊柱大写', shortName: '脊柱大写',
keyword: [...keyword.kebab, ...keyword.upper], keyword: [...keyword.kebab, ...keyword.upper],
settingsKey: 'kebab_upper_case', settingsKey: 'kebab_upper_case',
}, },
{ {
type: SupportCase.SPACE_CASE, type: SupportVariableCase.SPACE_CASE,
name: '空格分隔命名', name: '空格分隔命名',
shortName: '脊柱', shortName: '脊柱',
keyword: [...keyword.space, ...keyword.lower], keyword: [...keyword.space, ...keyword.lower],
settingsKey: 'space_case', settingsKey: 'space_case',
}, },
{ {
type: SupportCase.SPACE_CAMEL_CASE, type: SupportVariableCase.SPACE_CAMEL_CASE,
name: '空格分隔 + 小驼峰(驼峰)命名', name: '空格分隔 + 小驼峰(驼峰)命名',
shortName: '脊柱驼峰', shortName: '脊柱驼峰',
keyword: [...keyword.space, ...keyword.camel], keyword: [...keyword.space, ...keyword.camel],
settingsKey: 'space_camel_case', settingsKey: 'space_camel_case',
}, },
{ {
type: SupportCase.SPACE_PASCAL_CASE, type: SupportVariableCase.SPACE_PASCAL_CASE,
name: '空格分隔 + 大驼峰(帕斯卡)命名', name: '空格分隔 + 大驼峰(帕斯卡)命名',
shortName: '脊柱帕斯卡', shortName: '脊柱帕斯卡',
keyword: [...keyword.space, ...keyword.pascal], keyword: [...keyword.space, ...keyword.pascal],
settingsKey: 'space_pascal_case', settingsKey: 'space_pascal_case',
}, },
{ {
type: SupportCase.SPACE_UPPER_CASE, type: SupportVariableCase.SPACE_UPPER_CASE,
name: '空格分隔 + 全大写命名', name: '空格分隔 + 全大写命名',
shortName: '脊柱大写', shortName: '脊柱大写',
keyword: [...keyword.space, ...keyword.upper], keyword: [...keyword.space, ...keyword.upper],
settingsKey: 'space_upper_case', settingsKey: 'space_upper_case',
}, },
{ {
type: SupportCase.DOT_CASE, type: SupportVariableCase.DOT_CASE,
name: '点分隔命名', name: '点分隔命名',
shortName: '脊柱', shortName: '脊柱',
keyword: [...keyword.dot, ...keyword.lower], keyword: [...keyword.dot, ...keyword.lower],
settingsKey: 'dot_case', settingsKey: 'dot_case',
}, },
{ {
type: SupportCase.DOT_CAMEL_CASE, type: SupportVariableCase.DOT_CAMEL_CASE,
name: '点分隔 + 小驼峰(驼峰)命名', name: '点分隔 + 小驼峰(驼峰)命名',
shortName: '脊柱驼峰', shortName: '脊柱驼峰',
keyword: [...keyword.dot, ...keyword.camel], keyword: [...keyword.dot, ...keyword.camel],
settingsKey: 'dot_camel_case', settingsKey: 'dot_camel_case',
}, },
{ {
type: SupportCase.DOT_PASCAL_CASE, type: SupportVariableCase.DOT_PASCAL_CASE,
name: '点分隔 + 大驼峰(帕斯卡)命名', name: '点分隔 + 大驼峰(帕斯卡)命名',
shortName: '脊柱帕斯卡', shortName: '脊柱帕斯卡',
keyword: [...keyword.dot, ...keyword.pascal], keyword: [...keyword.dot, ...keyword.pascal],
settingsKey: 'dot_pascal_case', settingsKey: 'dot_pascal_case',
}, },
{ {
type: SupportCase.DOT_UPPER_CASE, type: SupportVariableCase.DOT_UPPER_CASE,
name: '点分隔 + 全大写命名', name: '点分隔 + 全大写命名',
shortName: '脊柱大写', shortName: '脊柱大写',
keyword: [...keyword.dot, ...keyword.upper], keyword: [...keyword.dot, ...keyword.upper],
settingsKey: 'dot_upper_case', settingsKey: 'dot_upper_case',
}, },
{ {
type: SupportCase.LOWER_CASE, type: SupportVariableCase.LOWER_CASE,
name: '全小写', name: '全小写',
shortName: '小写', shortName: '小写',
keyword: keyword.lower, keyword: keyword.lower,
settingsKey: 'lower_case', settingsKey: 'lower_case',
}, },
{ {
type: SupportCase.UPPER_CASE, type: SupportVariableCase.UPPER_CASE,
name: '全大写', name: '全大写',
shortName: '大写', shortName: '大写',
keyword: keyword.upper, keyword: keyword.upper,
@ -545,7 +545,7 @@ export const quickPickSupportCases: Array<QuickPickSupportCaseItem> = [
]; ];
export interface CyclicConvertCaseOrderItem { export interface CyclicConvertCaseOrderItem {
type: SupportCase, type: SupportVariableCase,
settingsKey: string, settingsKey: string,
} }
@ -554,28 +554,28 @@ export interface CyclicConvertCaseOrderItem {
* @since 2024-04-08 * @since 2024-04-08
*/ */
export const cyclicConvertCaseOrder: Array<CyclicConvertCaseOrderItem> = [ export const cyclicConvertCaseOrder: Array<CyclicConvertCaseOrderItem> = [
{ type: SupportCase.CAMEL_CASE, settingsKey: 'camel_case' }, { type: SupportVariableCase.CAMEL_CASE, settingsKey: 'camel_case' },
{ type: SupportCase.SNAKE_CASE, settingsKey: 'snake_case' }, { type: SupportVariableCase.SNAKE_CASE, settingsKey: 'snake_case' },
{ type: SupportCase.PASCAL_CASE, settingsKey: 'pascal_case' }, { type: SupportVariableCase.PASCAL_CASE, settingsKey: 'pascal_case' },
{ type: SupportCase.KEBAB_CASE, settingsKey: 'kebab_case' }, { type: SupportVariableCase.KEBAB_CASE, settingsKey: 'kebab_case' },
{ type: SupportCase.SPACE_CASE, settingsKey: 'space_case' }, { type: SupportVariableCase.SPACE_CASE, settingsKey: 'space_case' },
{ type: SupportCase.DOT_CASE, settingsKey: 'dot_case' }, { type: SupportVariableCase.DOT_CASE, settingsKey: 'dot_case' },
{ type: SupportCase.SNAKE_UPPER_CASE, settingsKey: 'snake_upper_case' }, { type: SupportVariableCase.SNAKE_UPPER_CASE, settingsKey: 'snake_upper_case' },
{ type: SupportCase.KEBAB_UPPER_CASE, settingsKey: 'kebab_upper_case' }, { type: SupportVariableCase.KEBAB_UPPER_CASE, settingsKey: 'kebab_upper_case' },
{ type: SupportCase.SPACE_UPPER_CASE, settingsKey: 'space_upper_case' }, { type: SupportVariableCase.SPACE_UPPER_CASE, settingsKey: 'space_upper_case' },
{ type: SupportCase.DOT_UPPER_CASE, settingsKey: 'dot_upper_case' }, { type: SupportVariableCase.DOT_UPPER_CASE, settingsKey: 'dot_upper_case' },
{ type: SupportCase.SNAKE_PASCAL_CASE, settingsKey: 'snake_pascal_case' }, { type: SupportVariableCase.SNAKE_PASCAL_CASE, settingsKey: 'snake_pascal_case' },
{ type: SupportCase.KEBAB_PASCAL_CASE, settingsKey: 'kebab_pascal_case' }, { type: SupportVariableCase.KEBAB_PASCAL_CASE, settingsKey: 'kebab_pascal_case' },
{ type: SupportCase.SPACE_PASCAL_CASE, settingsKey: 'space_pascal_case' }, { type: SupportVariableCase.SPACE_PASCAL_CASE, settingsKey: 'space_pascal_case' },
{ type: SupportCase.DOT_PASCAL_CASE, settingsKey: 'dot_pascal_case' }, { type: SupportVariableCase.DOT_PASCAL_CASE, settingsKey: 'dot_pascal_case' },
{ type: SupportCase.SNAKE_CAMEL_CASE, settingsKey: 'snake_camel_case' }, { type: SupportVariableCase.SNAKE_CAMEL_CASE, settingsKey: 'snake_camel_case' },
{ type: SupportCase.KEBAB_CAMEL_CASE, settingsKey: 'kebab_camel_case' }, { type: SupportVariableCase.KEBAB_CAMEL_CASE, settingsKey: 'kebab_camel_case' },
{ type: SupportCase.SPACE_CAMEL_CASE, settingsKey: 'space_camel_case' }, { type: SupportVariableCase.SPACE_CAMEL_CASE, settingsKey: 'space_camel_case' },
{ type: SupportCase.DOT_CAMEL_CASE, settingsKey: 'dot_camel_case' }, { type: SupportVariableCase.DOT_CAMEL_CASE, settingsKey: 'dot_camel_case' },
{ type: SupportCase.LOWER_CASE, settingsKey: 'lower_case' }, { type: SupportVariableCase.LOWER_CASE, settingsKey: 'lower_case' },
{ type: SupportCase.UPPER_CASE, settingsKey: 'upper_case' }, { type: SupportVariableCase.UPPER_CASE, settingsKey: 'upper_case' },
]; ];

View File

@ -1,36 +0,0 @@
import * as vscode from 'vscode';
// docs: https://code.visualstudio.com/api/references/vscode-api#StatusBarItem
let statusBar: vscode.StatusBarItem;
/**
*
*
* @since 2024-04-07
*/
export function createStatusBarItem() {
statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
statusBar.text = '$(find-replace)变量转换';
statusBar.command = 'variable-conversion.convertCase';
// statusBar.color = 'red';
// statusBar.show();
}
/**
*
*
* @since 2024-04-07
*/
export function updateStatusBarItemVisable(selectTextLength: number) {
if (!statusBar) {
return;
}
let editor = vscode.window.activeTextEditor;
if (editor && selectTextLength > 0) {
statusBar.show();
return;
}
statusBar.hide();
}

View File

@ -1,13 +1,33 @@
// The module 'vscode' contains the VS Code extensibility API /**
// Import the module and reference it with the alias vscode in your code below * @file extension.ts
* @description VS Code
* @author coder-xiaomo
* @version 1.0.0
* @license MIT
*
*
*
*
* @see https://code.visualstudio.com/api
*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import handleEditorReplace from './extension-handler/editor-submenu-handler';
import { handleQuickPick } from './extension-handler/quick-pick-handler'; // Variable Convert
import { commands } from './type-definition/SupportCaseType'; import handleEditorReplaceVariable from './handler/variable-convert/editor-submenu-handler';
import { createStatusBarItem, updateStatusBarItemVisable } from './extension-handler/status-bar-handler'; import { handleQuickPick as handleQuickPickVariable } from './handler/variable-convert/quick-pick-handler';
import * as CyclicConversion from './main-code/variable-convert/cyclic-conversion'; import { commands as variableCommands } from './core/variable-convert/types/SupportVariableCaseType';
import { EOL } from './type-definition/EOLType'; import * as CyclicConversionVariable from './core/variable-convert/cyclic-conversion';
import { getUserConfigurations } from './main-code/user-configuration';
// Path Convert
import handleEditorReplacePath from './handler/path-convert/editor-submenu-handler';
import { handleQuickPick as handleQuickPickPath } from './handler/path-convert/quick-pick-handler';
import { commands as pathCommands } from './core/path-convert/types/SupportPathFormatType';
import * as CyclicConversionPath from './core/path-convert/cyclic-conversion';
// Common
import { createStatusBarItem, updateStatusBarItemVisable } from './handler/status-bar-handler';
import { EOL } from './types/EOLType';
import { getUserConfigurations } from './utils/user-configuration';
// This method is called when your extension is activated // This method is called when your extension is activated
// Your extension is activated the very first time the command is executed // Your extension is activated the very first time the command is executed
@ -45,17 +65,26 @@ export function activate(context: vscode.ExtensionContext) {
// issue: #1 https://github.com/coder-xiaomo/variable-conversion-vscode-extension/issues/1 // issue: #1 https://github.com/coder-xiaomo/variable-conversion-vscode-extension/issues/1
// 获取用户配置 // 获取用户配置
const disableFormatList = getUserConfigurations<Array<string>>('disableFormat') || []; const disableFormatList = getUserConfigurations<Array<string>>('disableFormat') || [];
const disablePathFormatList = getUserConfigurations<Array<string>>('disablePathFormat') || [];
// 更新右键菜单每一项是否展示 // 更新右键菜单每一项是否展示
for (const { settingsKey } of commands) { // 变量转换右键菜单visible 2024.07.29
for (const { settingsKey } of variableCommands) {
vscode.commands.executeCommand('setContext', '_isHideSubMenuItem_' + settingsKey, disableFormatList.includes(settingsKey)); vscode.commands.executeCommand('setContext', '_isHideSubMenuItem_' + settingsKey, disableFormatList.includes(settingsKey));
} }
// 路径转换右键菜单visible 2024.12.14
for (const { settingsKey } of pathCommands) {
vscode.commands.executeCommand('setContext', '_isHideSubMenuItem_' + settingsKey, disablePathFormatList.includes(settingsKey));
}
// 判断是否展示状态栏按钮 // 判断是否展示状态栏按钮
updateStatusBarItemVisable(selectTextLength); updateStatusBarItemVisable(selectTextLength);
// 循环转换:记录当前选中内容,并且进行转换 // 循环转换:记录当前选中内容,并且进行转换
let eol: EOL = textEditor.document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n'; let eol: EOL = textEditor.document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
CyclicConversion.onUserSelectionUpdated(selections, textList, eol); // 变量循环转换 2024.04.09
CyclicConversionVariable.onUserSelectionUpdated(selections, textList, eol);
// 路径循环转换 2024.12.14
CyclicConversionPath.onUserSelectionUpdated(selections, textList, eol);
}; };
// 创建状态栏按钮 // 创建状态栏按钮
@ -95,29 +124,70 @@ export function activate(context: vscode.ExtensionContext) {
onTextEditorSelectionChangeCallback(editor, editor.selections); onTextEditorSelectionChangeCallback(editor, editor.selections);
} }
/**
*
*
* @since 2024-04
*/
// 逐一注册右键菜单-子菜单项 command // 逐一注册右键菜单-子菜单项 command
for (const { command, targetCase } of commands) { for (const { command, targetCase } of variableCommands) {
let disposable = vscode.commands.registerCommand(command, () => { let disposable = vscode.commands.registerCommand(command, () => {
handleEditorReplace(targetCase); // 变量转换右键菜单 2024.04.05
handleEditorReplaceVariable(targetCase);
}); });
context.subscriptions.push(disposable); context.subscriptions.push(disposable);
} }
// 注册变量转换 command 状态栏/快捷键/右键[变量转换]菜单均有用到 // 注册变量转换 command 状态栏/快捷键/右键[变量转换]菜单均有用到
let convertCaseDisposable = vscode.commands.registerCommand('variable-conversion.convertCase', handleQuickPick); let convertCaseDisposable = vscode.commands.registerCommand('variable-conversion.convertCase', handleQuickPickVariable);
context.subscriptions.push(convertCaseDisposable); context.subscriptions.push(convertCaseDisposable);
// 注册循环转换 command // 注册循环转换 command
let disposableLoopConversionPrev = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => { let loopConvertCasePrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => {
console.log('variable-conversion.convertCase', arrowKey); console.log('variable-conversion.cyclicConvertCase.previous', arrowKey);
CyclicConversion.previousOne(); CyclicConversionVariable.previousOne();
}); });
context.subscriptions.push(disposableLoopConversionPrev); context.subscriptions.push(loopConvertCasePrevDisposable);
let disposableLoopConversionNext = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => { let loopConvertCaseNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => {
console.log('variable-conversion.convertCase', arrowKey); console.log('variable-conversion.cyclicConvertCase.next', arrowKey);
CyclicConversion.nextOne(); CyclicConversionVariable.nextOne();
}); });
context.subscriptions.push(disposableLoopConversionNext); context.subscriptions.push(loopConvertCaseNextDisposable);
/**
*
* issue: #3 https://github.com/coder-xiaomo/variable-conversion-vscode-extension/issues/3
*
* @since 2024-12
*/
// 逐一注册右键菜单-子菜单项 command
for (const { command, targetCase } of pathCommands) {
let disposable = vscode.commands.registerCommand(command, () => {
// 变量转换右键菜单 2024.12.14
handleEditorReplacePath(targetCase);
});
context.subscriptions.push(disposable);
}
// 注册路径转换 command 状态栏/快捷键/右键[路径转换]菜单均有用到
let convertPathDisposable = vscode.commands.registerCommand('variable-conversion.convertPath', handleQuickPickPath);
context.subscriptions.push(convertPathDisposable);
// 注册循环转换 command
let loopConvertPathPrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.previous', ({ direction }) => {
console.log('variable-conversion.cyclicConvertPath.previous', direction);
CyclicConversionPath.previousOne();
});
context.subscriptions.push(loopConvertPathPrevDisposable);
let loopConvertPathNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.next', ({ direction }) => {
console.log('variable-conversion.cyclicConvertPath.next', direction);
CyclicConversionPath.nextOne();
});
context.subscriptions.push(loopConvertPathNextDisposable);
} }
// This method is called when your extension is deactivated // This method is called when your extension is deactivated

View File

@ -0,0 +1,59 @@
import * as vscode from 'vscode';
import { EOL } from '../../types/EOLType';
import { pathConversion } from '../../core/path-convert/conversion';
import { SupportPathFormat } from '../../core/path-convert/types/SupportPathFormatType';
import { isStringArrayEqual } from '../../utils/utils';
/**
*
*
* @param convertFunction
* @returns
*/
const handleEditorReplace = (targetCase: SupportPathFormat) => {
// 获取当前编辑器
let editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const document = editor.document;
const selections = editor.selections;
const eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
// 获取选中的文本
const textList = selections.map(selection => document.getText(selection));
if (textList.filter(text => text.length > 0).length === 0) {
vscode.window.showInformationMessage('请选择需要转换的路径后重试\nPlease select the path you want to convert and try again.');
return;
}
// 转换文本
const convertedList = textList.map(text => pathConversion(targetCase, text, eol));
console.log('convertedList', convertedList);
// 无法转换时,跳过转换
if (convertedList.filter(converted => converted !== undefined).length === 0) {
console.log('converted text is undefined, skip replace contents.');
return;
}
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
if (isStringArrayEqual(convertedList, textList)) {
console.log('selection text is same to converted text, skip replace contents.');
return;
}
// 替换文本
console.log('replace selection text', textList, 'to', convertedList);
editor.edit(editBuilder => {
for (let i = 0; i < selections.length; i++) {
const selection = selections[i];
const converted = convertedList[i];
editBuilder.replace(selection, converted);
}
});
};
export default handleEditorReplace;

View File

@ -0,0 +1,144 @@
import * as vscode from 'vscode';
import QuickPickItemEx from "../types/QuickPickItemExType";
import { QuickPickSupportCaseItem, quickPickSupportCases } from '../../core/path-convert/types/SupportPathFormatType';
import { TransformTextResult } from '../../types/TransformTextResultType';
import { transformMutliSelectionText } from '../../utils/transform';
import { EOL } from '../../types/EOLType';
import { pathConversion } from '../../core/path-convert/conversion';
import { isStringArrayEqual } from '../../utils/utils';
import { getUserConfigurations } from '../../utils/user-configuration';
const QuickPickLabelMaxLength = 60;
interface RecommendItem {
conversionText: Array<string>
transforTo: string[]
keyword: string[]
}
/**
*
*
* @since 2024-12-14
*/
function generateOptionsBasedOnText(textList: string[], eol: EOL, enabledQuickPickSupportCases: Array<QuickPickSupportCaseItem>): Array<QuickPickItemEx> {
// Cut text 切割文本
const resultsList: Array<TransformTextResult[]> = transformMutliSelectionText(textList);
const mergeResultList: Array<RecommendItem> = [];
for (const quickPick of enabledQuickPickSupportCases) {
const conversionResults: Array<string> = [];
for (let i = 0; i < textList.length; i++) {
const text = textList[i];
const results = resultsList[i];
const conversionResult: string = pathConversion(quickPick.type, text, eol, results);
conversionResults.push(conversionResult);
}
const recommendItem: RecommendItem | undefined = mergeResultList.find(item => isStringArrayEqual(item.conversionText, conversionResults));
if (recommendItem === undefined) {
let item: RecommendItem = {
conversionText: conversionResults,
transforTo: [quickPick.shortName], // quickPick.name
keyword: quickPick.keyword,
};
mergeResultList.push(item);
continue;
}
recommendItem.transforTo.push(quickPick.shortName); // quickPick.name
recommendItem.keyword = Array.from(new Set(recommendItem.keyword.concat(quickPick.keyword))); // 关键词去重
}
// 根据文本生成选项的逻辑
const quickPickList = [];
for (const recommendItem of mergeResultList) {
if (isStringArrayEqual(textList, recommendItem.conversionText)) {
continue; // 如果转换后与转换前相同,那么跳过这一项
}
const conversionTextForDisplay = recommendItem.conversionText.join(' ').replace(/\s+/g, " "); // 友好展示 将连续空格 \n \t 等替换为单一空格
let quickPickItem: QuickPickItemEx = {
label: conversionTextForDisplay.length >= QuickPickLabelMaxLength
? (conversionTextForDisplay.substring(0, QuickPickLabelMaxLength - 3) + '...')
: conversionTextForDisplay,
description: `转换为 ${recommendItem.transforTo.join(' / ')}`,
detail: `关键词 ${recommendItem.keyword.join(' ')}`,
value: recommendItem.conversionText,
};
quickPickList.push(quickPickItem);
}
return quickPickList;
}
export function handleQuickPick() {
// 获取当前编辑器
let editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const document = editor.document;
const selections = editor.selections;
const eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
// 获取选中的文本
const textList = selections.map(selection => document.getText(selection));
if (textList.filter(text => text.length > 0).length === 0) {
vscode.window.showInformationMessage('请选择需要转换的路径后重试\nPlease select the path you want to convert and try again.');
return;
}
// TODO
// 获取用户配置
const disablePathFormatList = getUserConfigurations<Array<string>>('disablePathFormat') || [];
// 排除禁用的选项
const enabledQuickPickSupportCases = [];
for (const quickPick of quickPickSupportCases) {
if (disablePathFormatList.includes(quickPick.settingsKey)) {
continue;
}
enabledQuickPickSupportCases.push(quickPick);
}
if (enabledQuickPickSupportCases.length === 0) {
vscode.window.showInformationMessage('所有格式都已被配置为禁用,请修改配置 `variable-conversion.disablePathFormat` 后重试\nAll formats have been configured to disable. Modify the `variable-conversion.disablePathFormat` configuration and try again.');
return;
}
// 基于选中的文本生成选项
const options = generateOptionsBasedOnText(textList, eol, enabledQuickPickSupportCases);
if (options.length === 0) {
vscode.window.showInformationMessage('所选内容暂无可选转换,请尝试重新选择\nNo conversion candidates are available for the selected content, please try to select another text.');
return;
}
// 显示推荐项列表
vscode.window.showQuickPick(options, {
matchOnDetail: true,
title: '请选择需要转换的路径风格...',
placeHolder: '点击转换,输入关键词可快速选择'
}).then(pickItem => {
if (!editor || pickItem === undefined) {
return;
}
const convertedList = pickItem.value;
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
if (isStringArrayEqual(convertedList, textList)) {
console.log('selection text is same to converted text, skip replace contents.');
return;
}
// 替换文本
console.log('replace selection text', textList, 'to', convertedList);
editor.edit(editBuilder => {
for (let i = 0; i < selections.length; i++) {
const selection = selections[i];
const converted = convertedList[i];
editBuilder.replace(selection, converted);
}
});
});
}

View File

@ -0,0 +1,54 @@
import * as vscode from 'vscode';
// docs: https://code.visualstudio.com/api/references/vscode-api#StatusBarItem
let statusBarItemList: Array<vscode.StatusBarItem> = [];
/**
*
*
* @since 2024-04-07
*/
export function createStatusBarItem() {
// 变量转换状态栏 2024.04.07
const createVariableConvertStatusBarItem = () => {
const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
// Icon Listing docs: https://code.visualstudio.com/api/references/icons-in-labels#icon-listing
statusBarItem.text = '$(find-replace)变量转换';
statusBarItem.command = 'variable-conversion.convertCase';
// statusBarItem.color = 'red';
// statusBarItem.show();
return statusBarItem;
};
// 路径转换状态栏 2024.12.14
const createPathConvertStatusBarItem = () => {
const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
statusBarItem.text = '$(sync-ignored)路径转换'; // italic symbol-null
statusBarItem.command = 'variable-conversion.convertPath';
statusBarItemList.push(statusBarItem);
return statusBarItem;
};
statusBarItemList.push(
createVariableConvertStatusBarItem(),
createPathConvertStatusBarItem(),
);
}
/**
*
*
* @since 2024-04-07
*/
export function updateStatusBarItemVisable(selectTextLength: number) {
let editor = vscode.window.activeTextEditor;
if (editor && selectTextLength > 0) {
statusBarItemList.forEach(statusBarItem => {
statusBarItem.show();
});
return;
}
statusBarItemList.forEach(statusBarItem => {
statusBarItem.hide();
});
}

View File

@ -1,8 +1,8 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { EOL } from '../type-definition/EOLType'; import { EOL } from '../../types/EOLType';
import { caseConversion } from '../main-code/variable-convert/conversion'; import { caseConversion } from '../../core/variable-convert/conversion';
import { SupportCase } from '../type-definition/SupportCaseType'; import { SupportVariableCase } from '../../core/variable-convert/types/SupportVariableCaseType';
import { isStringArrayEqual } from '../main-code/utils'; import { isStringArrayEqual } from '../../utils/utils';
/** /**
* *
@ -10,7 +10,7 @@ import { isStringArrayEqual } from '../main-code/utils';
* @param convertFunction * @param convertFunction
* @returns * @returns
*/ */
const handleEditorReplace = (targetCase: SupportCase) => { const handleEditorReplace = (targetCase: SupportVariableCase) => {
// 获取当前编辑器 // 获取当前编辑器
let editor = vscode.window.activeTextEditor; let editor = vscode.window.activeTextEditor;
if (!editor) { if (!editor) {

View File

@ -1,12 +1,12 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import QuickPickItemEx from "../type-definition/QuickPickItemExType"; import QuickPickItemEx from "../types/QuickPickItemExType";
import { QuickPickSupportCaseItem, quickPickSupportCases } from '../type-definition/SupportCaseType'; import { QuickPickSupportCaseItem, quickPickSupportCases } from '../../core/variable-convert/types/SupportVariableCaseType';
import { TransformTextResult } from '../type-definition/TransformTextResultType'; import { TransformTextResult } from '../../types/TransformTextResultType';
import { transformMutliSelectionText } from '../main-code/variable-convert/transform'; import { transformMutliSelectionText } from '../../utils/transform';
import { EOL } from '../type-definition/EOLType'; import { EOL } from '../../types/EOLType';
import { caseConversion } from '../main-code/variable-convert/conversion'; import { caseConversion } from '../../core/variable-convert/conversion';
import { isStringArrayEqual } from '../main-code/utils'; import { isStringArrayEqual } from '../../utils/utils';
import { getUserConfigurations } from '../main-code/user-configuration'; import { getUserConfigurations } from '../../utils/user-configuration';
const QuickPickLabelMaxLength = 60; const QuickPickLabelMaxLength = 60;

View File

@ -3,12 +3,16 @@ import * as assert from 'assert';
// You can import and use all API from the 'vscode' module // You can import and use all API from the 'vscode' module
// as well as import your extension to test it // as well as import your extension to test it
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import testGroups from './test-case'; import { variableConvertTestGroups } from './test-case/variable-convert-test-case';
import { TestCase, TestCaseGroup } from '../type-definition/TestCaseType'; import { pathConvertTestGroups } from './test-case/path-convert-test-case';
import { transformMutliLineText, transformText } from '../main-code/transform'; import { VariableTestCase, VariableTestCaseGroup } from './test-case/types/VariableTestCaseType';
import { caseConversion } from '../main-code/conversion'; import { PathTestCase, PathTestCaseGroup } from './test-case/types/PathTestCaseType';
import { SupportCase } from '../type-definition/SupportCaseType'; import { transformMutliLineText, transformText } from '../utils/transform';
import { TransformTextResult } from '../type-definition/TransformTextResultType'; import { caseConversion } from '../core/variable-convert/conversion';
import { pathConversion } from '../core/path-convert/conversion';
import { SupportVariableCase } from '../core/variable-convert/types/SupportVariableCaseType';
import { SupportPathFormat } from '../core/path-convert/types/SupportPathFormatType';
import { TransformTextResult } from '../types/TransformTextResultType';
// import * as myExtension from '../../extension'; // import * as myExtension from '../../extension';
/* /*
@ -22,13 +26,18 @@ suite('Extension Test Suite', () => {
}); });
*/ */
suite('Extension Test: run test case', () => { /**
vscode.window.showInformationMessage('Start all tests.'); *
*
* @since 2024-04-02
*/
suite('Extension Test: run variable convert test case', () => {
vscode.window.showInformationMessage('Start all tests for variable conversion.');
const groups: Array<TestCaseGroup> = testGroups; const groups: Array<VariableTestCaseGroup> = variableConvertTestGroups;
for (const testGroup of groups) { for (const testGroup of groups) {
const testTitle = testGroup.testTitle; const testTitle = testGroup.testTitle;
const testCases: Array<TestCase> = testGroup.cases; const testCases: Array<VariableTestCase> = testGroup.cases;
for (const testCase of testCases) { for (const testCase of testCases) {
// // 临时 // // 临时
// if (testCase.title !== '') { // if (testCase.title !== '') {
@ -48,35 +57,35 @@ suite('Extension Test: run test case', () => {
assert.strictEqual(correctValue, currentValue); assert.strictEqual(correctValue, currentValue);
} }
// 验证转换 // 验证转换
for (let eol of eolList) { for (const eol of eolList) {
assert.strictEqual(testCase.output.camelCase, caseConversion(SupportCase.CAMEL_CASE, input, eol), 'camel case test failed.'); assert.strictEqual(testCase.output.camelCase, caseConversion(SupportVariableCase.CAMEL_CASE, input, eol), 'camel case test failed.');
assert.strictEqual(testCase.output.pascalCase, caseConversion(SupportCase.PASCAL_CASE, input, eol), 'pascal case test failed.'); assert.strictEqual(testCase.output.pascalCase, caseConversion(SupportVariableCase.PASCAL_CASE, input, eol), 'pascal case test failed.');
assert.strictEqual(testCase.output.snakeCase, caseConversion(SupportCase.SNAKE_CASE, input, eol), 'snake case test failed.'); assert.strictEqual(testCase.output.snakeCase, caseConversion(SupportVariableCase.SNAKE_CASE, input, eol), 'snake case test failed.');
assert.strictEqual(testCase.output.snakeCamelCase, caseConversion(SupportCase.SNAKE_CAMEL_CASE, input, eol), 'snake camel case test failed.'); assert.strictEqual(testCase.output.snakeCamelCase, caseConversion(SupportVariableCase.SNAKE_CAMEL_CASE, input, eol), 'snake camel case test failed.');
assert.strictEqual(testCase.output.snakePascalCase, caseConversion(SupportCase.SNAKE_PASCAL_CASE, input, eol), 'snake pascal case test failed.'); assert.strictEqual(testCase.output.snakePascalCase, caseConversion(SupportVariableCase.SNAKE_PASCAL_CASE, input, eol), 'snake pascal case test failed.');
assert.strictEqual(testCase.output.snakeUpperCase, caseConversion(SupportCase.SNAKE_UPPER_CASE, input, eol), 'snake upper case test failed.'); assert.strictEqual(testCase.output.snakeUpperCase, caseConversion(SupportVariableCase.SNAKE_UPPER_CASE, input, eol), 'snake upper case test failed.');
assert.strictEqual(testCase.output.kebabCase, caseConversion(SupportCase.KEBAB_CASE, input, eol), 'kebab case test failed.'); assert.strictEqual(testCase.output.kebabCase, caseConversion(SupportVariableCase.KEBAB_CASE, input, eol), 'kebab case test failed.');
assert.strictEqual(testCase.output.kebabCamelCase, caseConversion(SupportCase.KEBAB_CAMEL_CASE, input, eol), 'kebab camel case test failed.'); assert.strictEqual(testCase.output.kebabCamelCase, caseConversion(SupportVariableCase.KEBAB_CAMEL_CASE, input, eol), 'kebab camel case test failed.');
assert.strictEqual(testCase.output.kebabPascalCase, caseConversion(SupportCase.KEBAB_PASCAL_CASE, input, eol), 'kebab pascal case test failed.'); assert.strictEqual(testCase.output.kebabPascalCase, caseConversion(SupportVariableCase.KEBAB_PASCAL_CASE, input, eol), 'kebab pascal case test failed.');
assert.strictEqual(testCase.output.kebabUpperCase, caseConversion(SupportCase.KEBAB_UPPER_CASE, input, eol), 'kebab upper case test failed.'); assert.strictEqual(testCase.output.kebabUpperCase, caseConversion(SupportVariableCase.KEBAB_UPPER_CASE, input, eol), 'kebab upper case test failed.');
assert.strictEqual(testCase.output.spaceCase, caseConversion(SupportCase.SPACE_CASE, input, eol), 'space case test failed.'); assert.strictEqual(testCase.output.spaceCase, caseConversion(SupportVariableCase.SPACE_CASE, input, eol), 'space case test failed.');
assert.strictEqual(testCase.output.spaceCamelCase, caseConversion(SupportCase.SPACE_CAMEL_CASE, input, eol), 'space camel case test failed.'); assert.strictEqual(testCase.output.spaceCamelCase, caseConversion(SupportVariableCase.SPACE_CAMEL_CASE, input, eol), 'space camel case test failed.');
assert.strictEqual(testCase.output.spacePascalCase, caseConversion(SupportCase.SPACE_PASCAL_CASE, input, eol), 'space pascal case test failed.'); assert.strictEqual(testCase.output.spacePascalCase, caseConversion(SupportVariableCase.SPACE_PASCAL_CASE, input, eol), 'space pascal case test failed.');
assert.strictEqual(testCase.output.spaceUpperCase, caseConversion(SupportCase.SPACE_UPPER_CASE, input, eol), 'space upper case test failed.'); assert.strictEqual(testCase.output.spaceUpperCase, caseConversion(SupportVariableCase.SPACE_UPPER_CASE, input, eol), 'space upper case test failed.');
assert.strictEqual(testCase.output.dotCase, caseConversion(SupportCase.DOT_CASE, input, eol), 'dot case test failed.'); assert.strictEqual(testCase.output.dotCase, caseConversion(SupportVariableCase.DOT_CASE, input, eol), 'dot case test failed.');
assert.strictEqual(testCase.output.dotCamelCase, caseConversion(SupportCase.DOT_CAMEL_CASE, input, eol), 'dot camel case test failed.'); assert.strictEqual(testCase.output.dotCamelCase, caseConversion(SupportVariableCase.DOT_CAMEL_CASE, input, eol), 'dot camel case test failed.');
assert.strictEqual(testCase.output.dotPascalCase, caseConversion(SupportCase.DOT_PASCAL_CASE, input, eol), 'dot pascal case test failed.'); assert.strictEqual(testCase.output.dotPascalCase, caseConversion(SupportVariableCase.DOT_PASCAL_CASE, input, eol), 'dot pascal case test failed.');
assert.strictEqual(testCase.output.dotUpperCase, caseConversion(SupportCase.DOT_UPPER_CASE, input, eol), 'dot upper case test failed.'); assert.strictEqual(testCase.output.dotUpperCase, caseConversion(SupportVariableCase.DOT_UPPER_CASE, input, eol), 'dot upper case test failed.');
if (testCase.output.lowerCase !== undefined) { if (testCase.output.lowerCase !== undefined) {
assert.strictEqual(testCase.output.lowerCase, caseConversion(SupportCase.LOWER_CASE, input, eol), 'lower case test failed.'); assert.strictEqual(testCase.output.lowerCase, caseConversion(SupportVariableCase.LOWER_CASE, input, eol), 'lower case test failed.');
} }
if (testCase.output.upperCase !== undefined) { if (testCase.output.upperCase !== undefined) {
assert.strictEqual(testCase.output.upperCase, caseConversion(SupportCase.UPPER_CASE, input, eol), 'upper case test failed.'); assert.strictEqual(testCase.output.upperCase, caseConversion(SupportVariableCase.UPPER_CASE, input, eol), 'upper case test failed.');
} }
} }
} }
@ -84,3 +93,36 @@ suite('Extension Test: run test case', () => {
} }
} }
}); });
/**
*
*
* @since 2024-12-07
*/
suite('Extension Test: run path convert test case', () => {
vscode.window.showInformationMessage('Start all tests for path conversion.');
const groups: Array<PathTestCaseGroup> = pathConvertTestGroups;
for (const testGroup of groups) {
const testTitle = testGroup.testTitle;
const testCases: Array<PathTestCase> = testGroup.cases;
for (const testCase of testCases) {
// // 临时
// if (testCase.title !== '') {
// continue;
// }
test(testTitle + ' - ' + testCase.title, () => {
const inputList = Array.isArray(testCase.input) ? testCase.input : [testCase.input];
const eolList = Array.isArray(testCase.eol) ? testCase.eol : [testCase.eol];
for (const input of inputList) {
// console.log('input', '->' + input + '<-');
// 验证转换
for (const eol of eolList) {
assert.strictEqual(testCase.output.Windows.unEscape, pathConversion(SupportPathFormat.Windows, input, eol), 'Windows path format test failed.');
assert.strictEqual(testCase.output.Unix.unEscape, pathConversion(SupportPathFormat.Unix, input, eol), 'Unix path format test failed.');
}
}
});
}
}
});

View File

@ -0,0 +1,108 @@
import { PathTestCaseGroup } from "./types/PathTestCaseType";
const LF = '\n';
const CRLF = '\r\n';
export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
{
group: 'Normal Path Format Convert',
testTitle: 'Normal Path Format Convert (常规路径风格转换)',
cases: [
{
title: 'Windows 风格',
input: // E:\Project\variable-conversion-vscode-extension
'E:\\Project\\variable-conversion-vscode-extension',
eol: [LF, CRLF],
output: {
Windows: {
unEscape: // E:\Project\variable-conversion-vscode-extension
'E:\\Project\\variable-conversion-vscode-extension',
escape: // E:\\Project\\variable-conversion-vscode-extension
'E:\\\\Project\\\\variable-conversion-vscode-extension',
},
Unix: {
unEscape:
'E:/Project/variable-conversion-vscode-extension',
escape: // E:\/Project\/variable-conversion-vscode-extension
'E:\\/Project\\/variable-conversion-vscode-extension',
},
},
},
{
title: 'Unix 风格',
input: '/home/user/file.txt',
eol: [LF, CRLF],
output: {
Windows: {
unEscape: // \home\user\file.txt
'\\home\\user\\file.txt',
escape: // \\home\\user\\file.txt
'\\\\home\\\\user\\\\file.txt',
},
Unix: {
unEscape:
'/home/user/file.txt',
escape: // \/home\/user\/file.txt
'\\/home\\/user\\/file.txt',
},
},
},
{
title: 'Windows (Git Bash) 风格',
input: '/c/Users/test/file.txt',
eol: [LF, CRLF],
output: {
Windows: {
unEscape: // \c\Users\test/file.txt
'\\c\\Users\\test\\file.txt',
escape: // \\c\\Users\\test\\file.txt
'\\\\c\\\\Users\\\\test\\\\file.txt',
// TODO need to transform to ↓
/*
unEscape: // C:\Users\test\file.txt
'C:\\Users\\test\\file.txt',
escape: // C:\\Users\\test\\file.txt
'C:\\\\Users\\\\test\\\\file.txt',
*/
},
Unix: {
unEscape:
'/c/Users/test/file.txt',
escape: // \/c\/Users\/test\/file.txt
'\\/c\\/Users\\/test\\/file.txt',
},
},
},
// TODO
// Windows 局域网主机名风格
// \\ComputerName
// 路径带空格
// /home/user/hello world.txt
// /home/user/hello world.txt
// and more ...
// {
// title: '',
// input: //
// '',
// eol: [LF, CRLF],
// output: {
// Windows: {
// unEscape: //
// '',
// escape: //
// '',
// },
// Unix: {
// unEscape: //
// '',
// escape: //
// '',
// },
// },
// },
],
},
];

View File

@ -0,0 +1,22 @@
import { EOL } from "../../../types/EOLType";
export type PathTestCaseGroup = {
group: string
testTitle: string
cases: Array<PathTestCase>
};
export type PathTestOutputResult = {
unEscape: string;
escape: string;
};
export type PathTestCase = {
title: string
input: string | Array<string>
eol: EOL | Array<EOL>
output: {
Windows: PathTestOutputResult
Unix: PathTestOutputResult
}
};

View File

@ -1,12 +1,12 @@
import { EOL } from "./EOLType"; import { EOL } from "../../../types/EOLType";
export type TestCaseGroup = { export type VariableTestCaseGroup = {
group: string group: string
testTitle: string testTitle: string
cases: Array<TestCase> cases: Array<VariableTestCase>
}; };
export type TestCase = { export type VariableTestCase = {
title: string title: string
input: string | Array<string> input: string | Array<string>
eol: EOL | Array<EOL> eol: EOL | Array<EOL>

View File

@ -1,4 +1,4 @@
import { TransformTextResult } from "../../type-definition/TransformTextResultType"; import { TransformTextResult } from "../types/TransformTextResultType";
const logDebugInfo = false; const logDebugInfo = false;

View File

@ -11,7 +11,7 @@ function getUserConfigurations<T>(configKey: string): T | undefined {
const config = vscode.workspace.getConfiguration('variable-conversion'); const config = vscode.workspace.getConfiguration('variable-conversion');
const configValue = config.get<T>(configKey); const configValue = config.get<T>(configKey);
console.log('configValue:', configValue); // console.log('configValue:', configValue);
return configValue; return configValue;
} }