Merge branch 'main' into release
This commit is contained in:
commit
0d92fbe4ec
14
CHANGELOG.md
14
CHANGELOG.md
@ -17,14 +17,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## 1.0.8
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- New: Supports multi-selection conversion (支持多选区转换)
|
||||||
|
- New: Supports scrolling conversion via shortcut keys `Ctrl + Alt + [` and `Ctrl + Alt + ]` (also supports multi-selection conversion) 支持通过快捷键循环转换 (同时支持多选区转换)
|
||||||
|
|
||||||
## 1.0.7
|
## 1.0.7
|
||||||
|
|
||||||
@ -34,14 +38,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Optimize QickPick conversion value display (优化 QickPick 转换值展示)
|
- Optimize QuickPick conversion value display (优化 QuickPick 转换值展示)
|
||||||
- Fixed typo: keyword of KEBAB_PASCAL_CASE, KEBAB_UPPER_CASE (修正 KEBAB_PASCAL_CASE, KEBAB_UPPER_CASE 关键词错误)
|
- Fixed typo: keyword of KEBAB_PASCAL_CASE, KEBAB_UPPER_CASE (修正 KEBAB_PASCAL_CASE, KEBAB_UPPER_CASE 关键词错误)
|
||||||
|
|
||||||
## 1.0.6
|
## 1.0.6
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add a status bar button to trigger string conversion (添加底栏按钮,支持通过底栏按钮触发字符串转换)
|
- Add a status bar button to trigger string conversion (添加状态栏按钮,支持通过状态栏按钮触发变量转换)
|
||||||
|
|
||||||
## 1.0.5
|
## 1.0.5
|
||||||
|
|
||||||
@ -54,7 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Add shortcut key `Shift + Alt + T` to show vscode QickPick window (添加快捷键 Shift + Alt + T 来显示 vscode QickPick 弹窗)
|
- Add shortcut key `Shift + Alt + T` to show vscode QuickPick window (添加快捷键 Shift + Alt + T 来显示 vscode QuickPick 弹窗)
|
||||||
- Write `README.md` (完善 README 文档)
|
- Write `README.md` (完善 README 文档)
|
||||||
|
|
||||||
## 1.0.3
|
## 1.0.3
|
||||||
|
87
README.md
87
README.md
@ -1,63 +1,88 @@
|
|||||||
# 命名方式转换插件 Variable Conversion
|
# 命名方式转换插件 Variable Conversion
|
||||||
|
|
||||||
一个强大的变量名转换插件,支持常用命名方式间一键转换,支持右键菜单、快捷键、底栏等多种方式使用。<br>
|
一个强大的变量名转换插件,支持一键转换、循环转换,支持右键菜单、快捷键、状态栏等多种方式使用。<br>
|
||||||
A powerful variable naming conversion extension. You can use it through the editer menu, shortcut keys and bottom bar.
|
A powerful variable naming conversion extension. Supports one-key conversion & cyclic conversion. You can use it through the editer menu, shortcut keys and bottom bar.
|
||||||
|
|
||||||
|
- [x] 支持多选区 Support multi-selection
|
||||||
|
- [x] 支持多窗口 (不支持子窗口状态栏) Support subwindow (subwindow status bar are not supported)
|
||||||
|
- [x] 支持撤回 & 重做 Support undo & redo (Ctrl + Z / Ctrl + Y)
|
||||||
|
|
||||||
## 如何使用? How to Use?
|
## 如何使用? How to Use?
|
||||||
|
|
||||||
> 🔭 Tips for Chinese users: 如果您无法看到下文图片,请[点击这里查看](https://gitee.com/coder-xiaomo/variable-conversion-vscode-extension/blob/main/README.md)
|
> 🔭 Tips for Chinese users: 如果您无法看到下文图片,请[点击这里查看](https://gitee.com/coder-xiaomo/variable-conversion-vscode-extension/blob/main/README.md)
|
||||||
|
|
||||||
#### 1. 选中代码中需要转换的内容 <br>Select The Text To Convert
|
### 循环转换(Beta) Cyclic conversion(Beta)
|
||||||
|
|
||||||
|
选中代码中需要转换的内容,然后按下 `Ctrl + Alt + [` and `Ctrl + Alt + ]` 即可前后灵活切换变量命名方式。
|
||||||
|
|
||||||
|
![](image/cyclic-conversion.gif)
|
||||||
|
|
||||||
|
### 基础转换
|
||||||
|
|
||||||
|
**1. 选中代码中需要转换的内容** **Select The Text To Convert**
|
||||||
|
|
||||||
![Step1. Select The Text To Convert](image/step1-select-the-text-to-convert.gif)
|
![Step1. Select The Text To Convert](image/step1-select-the-text-to-convert.gif)
|
||||||
|
|
||||||
> Tips:<br>
|
> 小提示: <br>
|
||||||
> 可以通过 `Ctrl + D` 快捷键选中光标所在的单词<br>
|
> 1. 可以先按住 `Alt` 键不放,再鼠标先后选中多个选区 <br>
|
||||||
> You can press `Ctrl + D` to select the word near the cursor
|
> 2. 可以先按住 `Shift + Alt` 键不放,再按下鼠标左键,使用鼠标滑过需要选中的区块 <br>
|
||||||
|
> 3. 可以通过 `Ctrl + D` 快捷键选中光标所在的单词 <br>
|
||||||
|
> Tips: <br>
|
||||||
|
> 1. You can first hold down `Alt`, and then use the mouse to select multiple selection <br>
|
||||||
|
> 2. You can first hold down `Shift + Alt`, then press the left mouse button, and use the mouse to slide over the block that needs to be selected <br>
|
||||||
|
> 3. You can press `Ctrl + D` to select the word near the cursor <br>
|
||||||
|
|
||||||
#### 2. 按 `Shift + Alt + T`<br>Press `Shift + Alt + T`
|
**2. 按 `Shift + Alt + T`** **Press `Shift + Alt + T`**
|
||||||
|
|
||||||
![Step2. Press Shift + Alt + T](image/step2-press-shift-alt-t.gif)
|
![Step2. Press Shift + Alt + T](image/step2-press-shift-alt-t.gif)
|
||||||
|
|
||||||
或者点击状态栏的 `字符串转换` 按钮<br>
|
或者点击状态栏的 `变量转换` 按钮<br>
|
||||||
Or click the `String Conversion` button in the status bar
|
Or click the `String Conversion` button in the status bar
|
||||||
|
|
||||||
![Step2. Press Status Bar Button](image/step2-press-status-bar-button.png)
|
![Step2. Press Status Bar Button](image/step2-press-status-bar-button.png)
|
||||||
|
|
||||||
或者右键 -> `字符串转换`<br>
|
或者右键 -> `变量转换`<br>
|
||||||
Or right-click -> `String Conversion`
|
Or right-click -> `String Conversion`
|
||||||
|
|
||||||
![Step2. Variable conversion on the context menu](image/step2-variable-conversion-on-context-menu.png)
|
![Step2. Variable conversion on the context menu](image/step2-variable-conversion-on-context-menu.png)
|
||||||
|
|
||||||
或者右键 -> 将字符串转换为... <br>
|
或者右键 -> 将变量转换为... <br>
|
||||||
Or right-click on the selected text -> Convert string to...
|
Or right-click on the selected text -> Convert string to...
|
||||||
|
|
||||||
![Step2. Right-click on the selected text](image/step2-right-click-on-the-selected-text.gif)
|
![Step2. Right-click on the selected text](image/step2-right-click-on-the-selected-text.gif)
|
||||||
|
|
||||||
#### 3. 选择转换目标,转换完成 <br>Select the conversion target and complete
|
**3. 选择转换目标,转换完成** **Select the conversion target and complete**
|
||||||
|
|
||||||
|
## 快捷键
|
||||||
|
|
||||||
|
| 功能 Feature | 快捷键 shortcut key |
|
||||||
|
| ------------------------------------------------ | ------------------- |
|
||||||
|
| 变量转换 快速选择 QuickPick | Shift + Alt + T |
|
||||||
|
| 循环转换→上一个 Cyclic conversion → Previous one | Ctrl + Alt + [ |
|
||||||
|
| 循环转换→下一个 Cyclic conversion → Next one | Ctrl + Alt + ] |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 支持的类型 Support Case
|
## 支持的类型 Support Case
|
||||||
|
|
||||||
| 类型 | Case | 举例 e.g. |
|
| 类型 | Case | 举例 e.g. |
|
||||||
| ----------------------------------- | ------------------------ | ---------------- |
|
| ------------------------------------------ | ------------------------ | ---------------- |
|
||||||
| 小驼峰(驼峰)命名 | Camel Case | fooBar |
|
| 小驼峰(驼峰)命名 | Camel Case | fooBar |
|
||||||
| 大驼峰(帕斯卡)命名 | Pascal Case | FooBar |
|
| 大驼峰(帕斯卡)命名 | Pascal Case | FooBar |
|
||||||
| 下划线(蛇形)命名 | Snake Case | foo_bar |
|
| 下划线(蛇形)命名 | Snake Case | foo_bar |
|
||||||
| 下划线(蛇形) + 小驼峰(驼峰)命名 | Snake Camel Case | foo_Bar |
|
| 下划线(蛇形) + 小驼峰(驼峰)命名 | Snake Camel Case | foo_Bar |
|
||||||
| 下划线(蛇形) + 大驼峰(帕斯卡)命名 | Snake Pascal Case | Foo_Bar |
|
| 下划线(蛇形) + 大驼峰(帕斯卡)命名 | Snake Pascal Case | Foo_Bar |
|
||||||
| 下划线(蛇形) + 全大写命名 | Snake Upper Case | FOO_BAR |
|
| 下划线(蛇形) + 全大写命名 | Snake Upper Case | FOO_BAR |
|
||||||
| 连字符(脊柱式)命名 | Kebab Case / Spinal Case | foo-bar |
|
| 中划线(连字符/脊柱式)命名 | Kebab Case / Spinal Case | foo-bar |
|
||||||
| 连字符(脊柱式) + 小驼峰(驼峰)命名 | Kebab Camel Case | foo-Bar |
|
| 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名 | Kebab Camel Case | foo-Bar |
|
||||||
| 连字符(脊柱式) + 大驼峰(帕斯卡)命名 | Kebab Pascal Case | Foo-Bar |
|
| 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名 | Kebab Pascal Case | Foo-Bar |
|
||||||
| 连字符(脊柱式) + 全大写命名 | Kebab Upper Case | FOO-BAR |
|
| 中划线(连字符/脊柱式) + 全大写命名 | Kebab Upper Case | FOO-BAR |
|
||||||
| 空格分隔命名 | Space Case | foo bar |
|
| 空格分隔命名 | Space Case | foo bar |
|
||||||
| 空格分隔 + 小驼峰(驼峰)命名 | Space Camel Case | foo Bar |
|
| 空格分隔 + 小驼峰(驼峰)命名 | Space Camel Case | foo Bar |
|
||||||
| 空格分隔 + 大驼峰(帕斯卡)命名 | Space Pascal Case | Foo Bar |
|
| 空格分隔 + 大驼峰(帕斯卡)命名 | Space Pascal Case | Foo Bar |
|
||||||
| 空格分隔 + 全大写命名 | Space Upper Case | FOO BAR |
|
| 空格分隔 + 全大写命名 | Space Upper Case | FOO BAR |
|
||||||
| 全小写 | Lower Case | foo_bar / foobar |
|
| 全小写 | Lower Case | foo_bar / foobar |
|
||||||
| 全大写 | Upper Case | FOO_BAR / FOOBAR |
|
| 全大写 | Upper Case | FOO_BAR / FOOBAR |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 反馈 Feedback
|
## 反馈 Feedback
|
||||||
|
|
||||||
|
BIN
image/cyclic-conversion.gif
Normal file
BIN
image/cyclic-conversion.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
46
package.json
46
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"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, 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, lower, upper case, and more.",
|
||||||
"version": "1.0.7",
|
"version": "1.0.8",
|
||||||
"icon": "image/logo.png",
|
"icon": "image/logo.png",
|
||||||
"publisher": "coder-xiaomo",
|
"publisher": "coder-xiaomo",
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -31,10 +31,33 @@
|
|||||||
"onTextSelected"
|
"onTextSelected"
|
||||||
],
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
|
"keybindings": [
|
||||||
|
{
|
||||||
|
"command": "variable-conversion.convertCase",
|
||||||
|
"key": "shift+alt+t",
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "variable-conversion.cyclicConvertCase.previous",
|
||||||
|
"key": "ctrl+alt+[",
|
||||||
|
"args": {
|
||||||
|
"arrowKey": "["
|
||||||
|
},
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "variable-conversion.cyclicConvertCase.next",
|
||||||
|
"key": "ctrl+alt+]",
|
||||||
|
"args": {
|
||||||
|
"arrowKey": "]"
|
||||||
|
},
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
}
|
||||||
|
],
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.convertCase",
|
"command": "variable-conversion.convertCase",
|
||||||
"title": "字符串转换"
|
"title": "变量转换"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toCamelCase",
|
"command": "variable-conversion.toCamelCase",
|
||||||
@ -62,19 +85,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toKebabCase",
|
"command": "variable-conversion.toKebabCase",
|
||||||
"title": "连字符(脊柱式)命名 (Kebab/Spinal Case) [ foo-bar ]"
|
"title": "中划线(连字符/脊柱式)命名 (Kebab/Spinal Case) [ foo-bar ]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toKebabUpperCase",
|
"command": "variable-conversion.toKebabUpperCase",
|
||||||
"title": "连字符(脊柱式) + 全大写命名 (Kebab Upper Case) [ FOO-BAR ]"
|
"title": "中划线(连字符/脊柱式) + 全大写命名 (Kebab Upper Case) [ FOO-BAR ]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toKebabPascalCase",
|
"command": "variable-conversion.toKebabPascalCase",
|
||||||
"title": "连字符(脊柱式) + 大驼峰(帕斯卡)命名 (Kebab Pascal Case) [ Foo-Bar ]"
|
"title": "中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名 (Kebab Pascal Case) [ Foo-Bar ]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toKebabCamelCase",
|
"command": "variable-conversion.toKebabCamelCase",
|
||||||
"title": "连字符(脊柱式) + 小驼峰(驼峰)命名 (Kebab Camel Case) [ foo-Bar ]"
|
"title": "中划线(连字符/脊柱式) + 小驼峰(驼峰)命名 (Kebab Camel Case) [ foo-Bar ]"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "variable-conversion.toSpaceCase",
|
"command": "variable-conversion.toSpaceCase",
|
||||||
@ -101,13 +124,6 @@
|
|||||||
"title": "全大写 (Upper Case) [ FOOBAR ]"
|
"title": "全大写 (Upper Case) [ FOOBAR ]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"keybindings": [
|
|
||||||
{
|
|
||||||
"command": "variable-conversion.convertCase",
|
|
||||||
"key": "shift+alt+t",
|
|
||||||
"when": "editorTextFocus"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"menus": {
|
"menus": {
|
||||||
"editor/context": [
|
"editor/context": [
|
||||||
{
|
{
|
||||||
@ -191,7 +207,7 @@
|
|||||||
"submenus": [
|
"submenus": [
|
||||||
{
|
{
|
||||||
"id": "variable-conversion.stringConversionMenu",
|
"id": "variable-conversion.stringConversionMenu",
|
||||||
"label": "将字符串转换为..."
|
"label": "将变量转换为..."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2,6 +2,7 @@ import * as vscode from 'vscode';
|
|||||||
import { EOL } from '../type-definition/EOLType';
|
import { EOL } from '../type-definition/EOLType';
|
||||||
import { caseConversion } from '../main-code/conversion';
|
import { caseConversion } from '../main-code/conversion';
|
||||||
import { SupportCase } from '../type-definition/SupportCaseType';
|
import { SupportCase } from '../type-definition/SupportCaseType';
|
||||||
|
import { isStringArrayEqual } from '../main-code/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑器右键菜单
|
* 编辑器右键菜单
|
||||||
@ -16,36 +17,43 @@ const handleEditorReplace = (targetCase: SupportCase) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('============ start convert ============');
|
const document = editor.document;
|
||||||
let document = editor.document;
|
const selections = editor.selections;
|
||||||
let selection = editor.selection;
|
const eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
|
||||||
let eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
|
|
||||||
|
|
||||||
// 获取选中的文本
|
// 获取选中的文本
|
||||||
let text = document.getText(selection);
|
const textList = selections.map(selection => document.getText(selection));
|
||||||
|
|
||||||
|
if (textList.filter(text => text.length > 0).length === 0) {
|
||||||
|
vscode.window.showInformationMessage('请选择需要转换的变量后重试\nPlease select the variable you want to convert and try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 转换文本
|
// 转换文本
|
||||||
const converted = caseConversion(targetCase, text, eol);
|
const convertedList = textList.map(text => caseConversion(targetCase, text, eol));
|
||||||
console.log('converted', converted);
|
console.log('convertedList', convertedList);
|
||||||
|
|
||||||
// 无法转换时,跳过转换
|
// 无法转换时,跳过转换
|
||||||
if (converted === undefined) {
|
if (convertedList.filter(converted => converted !== undefined).length === 0) {
|
||||||
console.log('converted text is undefined, skip replace contents.');
|
console.log('converted text is undefined, skip replace contents.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
|
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
|
||||||
if (converted === text) {
|
if (isStringArrayEqual(convertedList, textList)) {
|
||||||
console.log('selection text is same to converted text, skip replace contents.');
|
console.log('selection text is same to converted text, skip replace contents.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换文本
|
// 替换文本
|
||||||
console.log('replace selection text', text, 'to', converted);
|
console.log('replace selection text', textList, 'to', convertedList);
|
||||||
editor.edit(editBuilder => {
|
editor.edit(editBuilder => {
|
||||||
editBuilder.replace(selection, converted);
|
for (let i = 0; i < selections.length; i++) {
|
||||||
|
const selection = selections[i];
|
||||||
|
const converted = convertedList[i];
|
||||||
|
editBuilder.replace(selection, converted);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// console.log('============ finish convert ============');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default handleEditorReplace;
|
export default handleEditorReplace;
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import QuickPickItemEx from "../type-definition/QuickPickItemExType";
|
import QuickPickItemEx from "../type-definition/QuickPickItemExType";
|
||||||
import { qickPickSupportCases } from '../type-definition/SupportCaseType';
|
import { quickPickSupportCases } from '../type-definition/SupportCaseType';
|
||||||
import { TransformTextResult } from '../type-definition/TransformTextResultType';
|
import { TransformTextResult } from '../type-definition/TransformTextResultType';
|
||||||
import { transformMutliLineText } from '../main-code/transform';
|
import { transformMutliLineText, transformMutliSelectionText } from '../main-code/transform';
|
||||||
import { EOL } from '../type-definition/EOLType';
|
import { EOL } from '../type-definition/EOLType';
|
||||||
import { caseConversion } from '../main-code/conversion';
|
import { caseConversion } from '../main-code/conversion';
|
||||||
|
import { isStringArrayEqual } from '../main-code/utils';
|
||||||
|
|
||||||
const QuickPickLabelMaxLength = 60;
|
const QuickPickLabelMaxLength = 60;
|
||||||
|
|
||||||
interface RecommendItem {
|
interface RecommendItem {
|
||||||
conversionText: string
|
conversionText: Array<string>
|
||||||
transforTo: string[]
|
transforTo: string[]
|
||||||
keyword: string[]
|
keyword: string[]
|
||||||
}
|
}
|
||||||
@ -17,27 +18,33 @@ interface RecommendItem {
|
|||||||
/**
|
/**
|
||||||
* 弹出的提示
|
* 弹出的提示
|
||||||
*/
|
*/
|
||||||
function generateOptionsBasedOnText(text: string, eol: EOL): Array<QuickPickItemEx> {
|
function generateOptionsBasedOnText(textList: string[], eol: EOL): Array<QuickPickItemEx> {
|
||||||
// Cut text 切割文本
|
// Cut text 切割文本
|
||||||
const results: Array<TransformTextResult> = transformMutliLineText(text);
|
const resultsList: Array<TransformTextResult[]> = transformMutliSelectionText(textList);
|
||||||
|
|
||||||
const mergeResultList: Array<RecommendItem> = [];
|
const mergeResultList: Array<RecommendItem> = [];
|
||||||
for (const qickPick of qickPickSupportCases) {
|
for (const quickPick of quickPickSupportCases) {
|
||||||
const conversionResult: string = caseConversion(qickPick.type, text, eol, results);
|
const conversionResults: Array<string> = [];
|
||||||
const recommendItem: RecommendItem | undefined = mergeResultList.find(item => item.conversionText === conversionResult);
|
for (let i = 0; i < textList.length; i++) {
|
||||||
|
const text = textList[i];
|
||||||
|
const results = resultsList[i];
|
||||||
|
const conversionResult: string = caseConversion(quickPick.type, text, eol, results);
|
||||||
|
conversionResults.push(conversionResult);
|
||||||
|
}
|
||||||
|
const recommendItem: RecommendItem | undefined = mergeResultList.find(item => isStringArrayEqual(item.conversionText, conversionResults));
|
||||||
|
|
||||||
if (recommendItem === undefined) {
|
if (recommendItem === undefined) {
|
||||||
let item: RecommendItem = {
|
let item: RecommendItem = {
|
||||||
conversionText: conversionResult,
|
conversionText: conversionResults,
|
||||||
transforTo: [qickPick.shortName], // qickPick.name
|
transforTo: [quickPick.shortName], // quickPick.name
|
||||||
keyword: qickPick.keyword,
|
keyword: quickPick.keyword,
|
||||||
};
|
};
|
||||||
mergeResultList.push(item);
|
mergeResultList.push(item);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
recommendItem.transforTo.push(qickPick.shortName); // qickPick.name
|
recommendItem.transforTo.push(quickPick.shortName); // quickPick.name
|
||||||
recommendItem.keyword = Array.from(new Set(recommendItem.keyword.concat(qickPick.keyword))); // 关键词去重
|
recommendItem.keyword = Array.from(new Set(recommendItem.keyword.concat(quickPick.keyword))); // 关键词去重
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据文本生成选项的逻辑
|
// 根据文本生成选项的逻辑
|
||||||
@ -52,10 +59,10 @@ function generateOptionsBasedOnText(text: string, eol: EOL): Array<QuickPickItem
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const recommendItem of mergeResultList) {
|
for (const recommendItem of mergeResultList) {
|
||||||
if (text === recommendItem.conversionText) {
|
if (isStringArrayEqual(textList, recommendItem.conversionText)) {
|
||||||
continue; // 如果转换后与转换前相同,那么跳过这一项
|
continue; // 如果转换后与转换前相同,那么跳过这一项
|
||||||
}
|
}
|
||||||
const conversionTextForDisplay = recommendItem.conversionText.trim();
|
const conversionTextForDisplay = recommendItem.conversionText.join(' ').replace(/\s+/g, " "); // 友好展示 将连续空格 \n \t 等替换为单一空格
|
||||||
let quickPickItem: QuickPickItemEx = {
|
let quickPickItem: QuickPickItemEx = {
|
||||||
label: conversionTextForDisplay.length >= QuickPickLabelMaxLength
|
label: conversionTextForDisplay.length >= QuickPickLabelMaxLength
|
||||||
? (conversionTextForDisplay.substring(0, QuickPickLabelMaxLength - 3) + '...')
|
? (conversionTextForDisplay.substring(0, QuickPickLabelMaxLength - 3) + '...')
|
||||||
@ -76,20 +83,25 @@ export function handleQuickPick() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let document = editor.document;
|
const document = editor.document;
|
||||||
let selection = editor.selection;
|
const selections = editor.selections;
|
||||||
let eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
|
const eol: EOL = document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
|
||||||
|
|
||||||
// 获取选中的文本
|
// 获取选中的文本
|
||||||
let text = document.getText(selection);
|
const textList = selections.map(selection => document.getText(selection));
|
||||||
|
|
||||||
if (text.length === 0) {
|
if (textList.filter(text => text.length > 0).length === 0) {
|
||||||
vscode.window.showInformationMessage('请选择需要转换的变量后重试\nPlease select the variable you want to convert and try again.');
|
vscode.window.showInformationMessage('请选择需要转换的变量后重试\nPlease select the variable you want to convert and try again.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基于选中的文本生成选项
|
// 基于选中的文本生成选项
|
||||||
const options = generateOptionsBasedOnText(text, eol);
|
const options = generateOptionsBasedOnText(textList, eol);
|
||||||
|
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, {
|
vscode.window.showQuickPick(options, {
|
||||||
matchOnDetail: true,
|
matchOnDetail: true,
|
||||||
@ -100,21 +112,22 @@ export function handleQuickPick() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理用户的选择
|
const convertedList = pickItem.value;
|
||||||
// vscode.window.showInformationMessage(`你选择了: ${JSON.stringify(selection)}`);
|
|
||||||
|
|
||||||
const converted = pickItem.value;
|
|
||||||
|
|
||||||
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
|
// 当转换后文本与转换前相同时,跳过转换,避免形成 Ctrl + Z 撤销历史记录
|
||||||
if (converted === text) {
|
if (isStringArrayEqual(convertedList, textList)) {
|
||||||
console.log('selection text is same to converted text, skip replace contents.');
|
console.log('selection text is same to converted text, skip replace contents.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 替换文本
|
// 替换文本
|
||||||
console.log('replace selection text', text, 'to', converted);
|
console.log('replace selection text', textList, 'to', convertedList);
|
||||||
editor.edit(editBuilder => {
|
editor.edit(editBuilder => {
|
||||||
editBuilder.replace(selection, converted);
|
for (let i = 0; i < selections.length; i++) {
|
||||||
|
const selection = selections[i];
|
||||||
|
const converted = convertedList[i];
|
||||||
|
editBuilder.replace(selection, converted);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,21 @@ import * as vscode from 'vscode';
|
|||||||
let statusBar: vscode.StatusBarItem;
|
let statusBar: vscode.StatusBarItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 创建状态栏按钮
|
||||||
|
*
|
||||||
* @since 2024-04-07
|
* @since 2024-04-07
|
||||||
*/
|
*/
|
||||||
export function createStatusBarItem() {
|
export function createStatusBarItem() {
|
||||||
statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
|
||||||
statusBar.text = '$(find-replace)字符串转换';
|
statusBar.text = '$(find-replace)变量转换';
|
||||||
statusBar.command = 'variable-conversion.convertCase';
|
statusBar.command = 'variable-conversion.convertCase';
|
||||||
// statusBar.color = 'red';
|
// statusBar.color = 'red';
|
||||||
// statusBar.show();
|
// statusBar.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 判断是否展示状态栏按钮
|
||||||
|
*
|
||||||
* @since 2024-04-07
|
* @since 2024-04-07
|
||||||
*/
|
*/
|
||||||
export function updateStatusBarItemVisable(selectTextLength: number) {
|
export function updateStatusBarItemVisable(selectTextLength: number) {
|
||||||
|
100
src/extension.ts
100
src/extension.ts
@ -3,58 +3,81 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import handleEditorReplace from './extension-handler/editor-submenu-handler';
|
import handleEditorReplace from './extension-handler/editor-submenu-handler';
|
||||||
import { handleQuickPick } from './extension-handler/quick-pick-handler';
|
import { handleQuickPick } from './extension-handler/quick-pick-handler';
|
||||||
import { SupportCase, commands } from './type-definition/SupportCaseType';
|
import { commands } from './type-definition/SupportCaseType';
|
||||||
import { createStatusBarItem, updateStatusBarItemVisable } from './extension-handler/status-bar-handler';
|
import { createStatusBarItem, updateStatusBarItemVisable } from './extension-handler/status-bar-handler';
|
||||||
|
import * as CyclicConversion from './main-code/cyclic-conversion';
|
||||||
|
import { EOL } from './type-definition/EOLType';
|
||||||
|
|
||||||
// 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
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
|
try {
|
||||||
|
// 获取当前插件的扩展对象
|
||||||
|
const currentExtension = vscode.extensions.getExtension('coder-xiaomo.variable-conversion');
|
||||||
|
if (currentExtension) {
|
||||||
|
// 获取版本号
|
||||||
|
const version = currentExtension.packageJSON.version;
|
||||||
|
console.log('[Variable Conversion] current version:', version);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('get current extension failed', err);
|
||||||
|
}
|
||||||
|
|
||||||
// // Use the console to output diagnostic information (console.log) and errors (console.error)
|
// 用于记录当前选中的文本的长度
|
||||||
// // This line of code will only be executed once when your extension is activated
|
|
||||||
// console.log('Congratulations, your extension "variable-conversion" is now active!');
|
|
||||||
|
|
||||||
// // The command has been defined in the package.json file
|
|
||||||
// // Now provide the implementation of the command with registerCommand
|
|
||||||
// // The commandId parameter must match the command field in package.json
|
|
||||||
// let disposable = vscode.commands.registerCommand('variable-conversion.helloWorld', () => {
|
|
||||||
// // The code you place here will be executed every time your command is executed
|
|
||||||
// // Display a message box to the user
|
|
||||||
// vscode.window.showInformationMessage('Hello World from variable-conversion!');
|
|
||||||
// });
|
|
||||||
|
|
||||||
let selectTextLength = 0;
|
let selectTextLength = 0;
|
||||||
|
|
||||||
|
// 选中文本改变时触发
|
||||||
|
const onTextEditorSelectionChangeCallback = (textEditor: vscode.TextEditor, selections: readonly vscode.Selection[]) => {
|
||||||
|
// 获取选中的文本块
|
||||||
|
const textList: string[] = [];
|
||||||
|
let tmp_selectTextLength = 0;
|
||||||
|
for (const selection of selections) {
|
||||||
|
const text = textEditor.document.getText(selection);
|
||||||
|
textList.push(text);
|
||||||
|
tmp_selectTextLength += text.length;
|
||||||
|
}
|
||||||
|
selectTextLength = tmp_selectTextLength;
|
||||||
|
|
||||||
|
// 更新 _textSelectionLength (用于判断是否展示右键菜单)
|
||||||
|
vscode.commands.executeCommand('setContext', '_textSelectionLength', selectTextLength);
|
||||||
|
|
||||||
|
// 判断是否展示状态栏按钮
|
||||||
|
updateStatusBarItemVisable(selectTextLength);
|
||||||
|
|
||||||
|
// 循环转换:记录当前选中内容,并且进行转换
|
||||||
|
let eol: EOL = textEditor.document.eol === vscode.EndOfLine.CRLF ? '\r\n' : '\n';
|
||||||
|
CyclicConversion.onUserSelectionUpdated(selections, textList, eol);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建状态栏按钮
|
||||||
createStatusBarItem();
|
createStatusBarItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换编辑器 Tab 时触发
|
||||||
|
*/
|
||||||
vscode.window.onDidChangeActiveTextEditor(event => {
|
vscode.window.onDidChangeActiveTextEditor(event => {
|
||||||
|
console.log('onDidChangeActiveTextEditor', event);
|
||||||
|
// 判断是否展示状态栏按钮
|
||||||
updateStatusBarItemVisable(selectTextLength);
|
updateStatusBarItemVisable(selectTextLength);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 用于判断是否展示右键菜单
|
/**
|
||||||
|
* 编辑器中光标选中位置改变触发
|
||||||
|
*/
|
||||||
vscode.window.onDidChangeTextEditorSelection(event => {
|
vscode.window.onDidChangeTextEditorSelection(event => {
|
||||||
const text = event.textEditor.document.getText(event.selections[0]);
|
// console.log('光标选中位置改变 onDidChangeTextEditorSelection', event);
|
||||||
// console.log('text.length', text.length);
|
// 执行 Callback
|
||||||
vscode.commands.executeCommand('setContext', '_textSelectionLength', text.length);
|
onTextEditorSelectionChangeCallback(event.textEditor, event.selections);
|
||||||
|
|
||||||
selectTextLength = text.length;
|
|
||||||
updateStatusBarItemVisable(selectTextLength);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始(VSCode 插件初始化)时也判断一次 (考虑上次关闭 VSCode 有选区,重新打开后 VSCode 回复选区但用户未重新切换选区的场景)
|
// 初始(VSCode 插件初始化)时也判断一次 (考虑上次关闭 VSCode 有选区,重新打开后 VSCode 回复选区但用户未重新切换选区的场景)
|
||||||
let editor = vscode.window.activeTextEditor;
|
let editor = vscode.window.activeTextEditor;
|
||||||
if (editor) {
|
if (editor) {
|
||||||
let document = editor.document;
|
// VSCode 启动时打开的 Tab 不是编辑器 Tab, 执行 Callback (如果不是则跳过)
|
||||||
let selection = editor.selection;
|
onTextEditorSelectionChangeCallback(editor, editor.selections);
|
||||||
// 获取选中的文本
|
|
||||||
let text = document.getText(selection);
|
|
||||||
vscode.commands.executeCommand('setContext', '_textSelectionLength', text.length);
|
|
||||||
|
|
||||||
selectTextLength = text.length;
|
|
||||||
updateStatusBarItemVisable(selectTextLength);
|
|
||||||
} else {
|
|
||||||
// vscode.window.showInformationMessage('editor is undefined');
|
|
||||||
console.log('editor is undefined');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 逐一注册右键菜单-子菜单项 command
|
||||||
for (const { command, targetCase } of commands) {
|
for (const { command, targetCase } of commands) {
|
||||||
let disposable = vscode.commands.registerCommand(command, () => {
|
let disposable = vscode.commands.registerCommand(command, () => {
|
||||||
handleEditorReplace(targetCase);
|
handleEditorReplace(targetCase);
|
||||||
@ -62,8 +85,21 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
context.subscriptions.push(disposable);
|
context.subscriptions.push(disposable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注册变量转换 command 状态栏/快捷键/右键[变量转换]菜单均有用到
|
||||||
let convertCaseDisposable = vscode.commands.registerCommand('variable-conversion.convertCase', handleQuickPick);
|
let convertCaseDisposable = vscode.commands.registerCommand('variable-conversion.convertCase', handleQuickPick);
|
||||||
context.subscriptions.push(convertCaseDisposable);
|
context.subscriptions.push(convertCaseDisposable);
|
||||||
|
|
||||||
|
// 注册循环转换 command
|
||||||
|
let disposableLoopConversionPrev = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => {
|
||||||
|
console.log('variable-conversion.convertCase', arrowKey);
|
||||||
|
CyclicConversion.previousOne();
|
||||||
|
});
|
||||||
|
context.subscriptions.push(disposableLoopConversionPrev);
|
||||||
|
let disposableLoopConversionNext = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => {
|
||||||
|
console.log('variable-conversion.convertCase', arrowKey);
|
||||||
|
CyclicConversion.nextOne();
|
||||||
|
});
|
||||||
|
context.subscriptions.push(disposableLoopConversionNext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method is called when your extension is deactivated
|
// This method is called when your extension is deactivated
|
||||||
|
@ -26,10 +26,10 @@ export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, c
|
|||||||
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
|
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
|
||||||
spaceCharacter = '_';
|
spaceCharacter = '_';
|
||||||
break;
|
break;
|
||||||
case SupportCase.KEBAB_CASE: // 连字符(脊柱式)命名
|
case SupportCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名
|
||||||
case SupportCase.KEBAB_CAMEL_CASE: // 连字符(脊柱式) + 小驼峰(驼峰)命名
|
case SupportCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名
|
||||||
case SupportCase.KEBAB_PASCAL_CASE: // 连字符(脊柱式) + 大驼峰(帕斯卡)命名
|
case SupportCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名
|
||||||
case SupportCase.KEBAB_UPPER_CASE: // 连字符(脊柱式) + 全大写命名
|
case SupportCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名
|
||||||
spaceCharacter = '-';
|
spaceCharacter = '-';
|
||||||
break;
|
break;
|
||||||
case SupportCase.SPACE_CASE: // 空格分隔命名
|
case SupportCase.SPACE_CASE: // 空格分隔命名
|
||||||
@ -80,7 +80,7 @@ export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, c
|
|||||||
switch (targetCase) {
|
switch (targetCase) {
|
||||||
case SupportCase.CAMEL_CASE: // 小驼峰(驼峰)命名
|
case SupportCase.CAMEL_CASE: // 小驼峰(驼峰)命名
|
||||||
case SupportCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名
|
case SupportCase.SNAKE_CAMEL_CASE: // 下划线(蛇形) + 小驼峰(驼峰)命名
|
||||||
case SupportCase.KEBAB_CAMEL_CASE: // 连字符(脊柱式) + 小驼峰(驼峰)命名
|
case SupportCase.KEBAB_CAMEL_CASE: // 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名
|
||||||
case SupportCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名
|
case SupportCase.SPACE_CAMEL_CASE: // 空格分隔 + 小驼峰(驼峰)命名
|
||||||
if (isFirstWord) {
|
if (isFirstWord) {
|
||||||
transformedWords.push(word);
|
transformedWords.push(word);
|
||||||
@ -93,17 +93,17 @@ export function caseConversion(targetCase: SupportCase, str: string, eol: EOL, c
|
|||||||
break;
|
break;
|
||||||
case SupportCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名
|
case SupportCase.PASCAL_CASE: // 大驼峰(帕斯卡)命名
|
||||||
case SupportCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名
|
case SupportCase.SNAKE_PASCAL_CASE: // 下划线(蛇形) + 大驼峰(帕斯卡)命名
|
||||||
case SupportCase.KEBAB_PASCAL_CASE: // 连字符(脊柱式) + 大驼峰(帕斯卡)命名
|
case SupportCase.KEBAB_PASCAL_CASE: // 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名
|
||||||
case SupportCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名
|
case SupportCase.SPACE_PASCAL_CASE: // 空格分隔 + 大驼峰(帕斯卡)命名
|
||||||
transformedWords.push(pascalCaseWord);
|
transformedWords.push(pascalCaseWord);
|
||||||
break;
|
break;
|
||||||
case SupportCase.SNAKE_CASE: // 下划线(蛇形)命名
|
case SupportCase.SNAKE_CASE: // 下划线(蛇形)命名
|
||||||
case SupportCase.KEBAB_CASE: // 连字符(脊柱式)命名
|
case SupportCase.KEBAB_CASE: // 中划线(连字符/脊柱式)命名
|
||||||
case SupportCase.SPACE_CASE: // 空格分隔命名
|
case SupportCase.SPACE_CASE: // 空格分隔命名
|
||||||
transformedWords.push(word);
|
transformedWords.push(word);
|
||||||
break;
|
break;
|
||||||
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
|
case SupportCase.SNAKE_UPPER_CASE: // 下划线(蛇形) + 全大写命名
|
||||||
case SupportCase.KEBAB_UPPER_CASE: // 连字符(脊柱式) + 全大写命名
|
case SupportCase.KEBAB_UPPER_CASE: // 中划线(连字符/脊柱式) + 全大写命名
|
||||||
case SupportCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名
|
case SupportCase.SPACE_UPPER_CASE: // 空格分隔 + 全大写命名
|
||||||
transformedWords.push(word.toUpperCase());
|
transformedWords.push(word.toUpperCase());
|
||||||
break;
|
break;
|
||||||
|
105
src/main-code/cyclic-conversion.ts
Normal file
105
src/main-code/cyclic-conversion.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { EOL } from "../type-definition/EOLType";
|
||||||
|
import { cyclicConvertCaseOrder } from "../type-definition/SupportCaseType";
|
||||||
|
import { caseConversion } from "./conversion";
|
||||||
|
import { isStringArrayEqual, stringListArrayDuplicateRemoval } from './utils';
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const textList = userSelection.currentSelectionsText;
|
||||||
|
// vscode.window.showInformationMessage('lazyConvert' + textList.join('\n'));
|
||||||
|
const eol = userSelection.currentEol;
|
||||||
|
const conversionsTarget: Array<string[]> = [textList];
|
||||||
|
for (const cyclicConvertCase of cyclicConvertCaseOrder) {
|
||||||
|
// 每一个类型
|
||||||
|
const conversionsTargetItem: string[] = [];
|
||||||
|
for (const line of textList) {
|
||||||
|
// 选中区块的每一行
|
||||||
|
const conversionResult: string = caseConversion(cyclicConvertCase, 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;
|
||||||
|
}
|
||||||
|
}
|
@ -2,17 +2,36 @@ import { TransformTextResult } from "../type-definition/TransformTextResultType"
|
|||||||
|
|
||||||
const logDebugInfo = false;
|
const logDebugInfo = false;
|
||||||
|
|
||||||
export function transformMutliLineText(multilineInput: string): Array<TransformTextResult> {
|
/**
|
||||||
const results: Array<TransformTextResult> = [];
|
* 多选区分词
|
||||||
const lines = multilineInput.split(/\r?\n/);
|
*
|
||||||
|
* @param multiSelectionInputs
|
||||||
|
* @returns
|
||||||
|
* @since 2024-04-03
|
||||||
|
*/
|
||||||
|
export function transformMutliSelectionText(selectionInputs: string[]): Array<TransformTextResult[]> {
|
||||||
|
return selectionInputs.map(selectionInput => transformMutliLineText(selectionInput));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多行内容分词(单一选区)
|
||||||
|
*
|
||||||
|
* @param multiLineInput
|
||||||
|
* @returns
|
||||||
|
* @since 2024-04-03
|
||||||
|
*/
|
||||||
|
export function transformMutliLineText(multiLineInput: string): TransformTextResult[] {
|
||||||
|
const results: TransformTextResult[] = [];
|
||||||
|
const lines = multiLineInput.split(/\r?\n/);
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
// console.log('line', '->' + line + '<-');
|
// console.log('line', '->' + line + '<-');
|
||||||
results.push(transformText(line));
|
results.push(transformText(line));
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分词
|
* 独立段落单元分词 (不包含换行)
|
||||||
*
|
*
|
||||||
* @param str
|
* @param str
|
||||||
* @since 2024-04-02
|
* @since 2024-04-02
|
||||||
|
27
src/main-code/utils.ts
Normal file
27
src/main-code/utils.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export function isStringArrayEqual(array1: string[], array2: string[]) {
|
||||||
|
if (array1.length !== array2.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let index = 0; index < array1.length; index++) {
|
||||||
|
const element1 = array1[index];
|
||||||
|
const element2 = array2[index];
|
||||||
|
if (element1 !== element2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringListArrayDuplicateRemoval(stringArr: Array<string[]>): Array<string[]> {
|
||||||
|
const tempArr: Array<string> = [];
|
||||||
|
const newArr: Array<string[]> = [];
|
||||||
|
for (let index = 0; index < stringArr.length; index++) {
|
||||||
|
const element = stringArr[index];
|
||||||
|
const elementStr = JSON.stringify(element);
|
||||||
|
if (!tempArr.includes(elementStr)) {
|
||||||
|
newArr.push(element);
|
||||||
|
tempArr.push(elementStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArr;
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
interface ExtendedQuickPickItem extends vscode.QuickPickItem {
|
interface ExtendedQuickPickItem extends vscode.QuickPickItem {
|
||||||
value: string;
|
value: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// type QuickPickItemEx = ExtendedQuickPickItem | vscode.QuickPickItem;
|
// type QuickPickItemEx = ExtendedQuickPickItem | vscode.QuickPickItem;
|
||||||
|
@ -2,20 +2,18 @@
|
|||||||
* When support a new case, there's something we need to do.
|
* When support a new case, there's something we need to do.
|
||||||
*
|
*
|
||||||
* Code:
|
* Code:
|
||||||
* - Add `commands`, `menus` parts in package.json (and package-comment.jsonc)
|
* - Add type definition in below `SupportCase` enum and following array
|
||||||
* - Add main conversion logic in src/main-code/variable-conversion.ts
|
* - Add `commands`, `menus` parts in [package.json] and [package-comment.jsonc]
|
||||||
* - Add disposable in src/extension.ts
|
* - Add main conversion logic in [src/main-code/conversion.ts]
|
||||||
*
|
*
|
||||||
* Test:
|
* Test:
|
||||||
* - Add test case type definition in src/type-definition/test-case-type.ts
|
* - Add test case type definition in [src/type-definition/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]
|
||||||
*
|
*
|
||||||
* Docs:
|
* Docs:
|
||||||
* - Add type definition in below `SupportCase` enum
|
* - Modify `description` in [package.json] and [package-comment.jsonc]
|
||||||
* - Modify `description` in package.json
|
* - Add changes in [CHANGELOG.md] and [README.md]
|
||||||
* - Add changes in CHANGELOG.md
|
|
||||||
* - Add changes in README.md
|
|
||||||
*/
|
*/
|
||||||
export enum SupportCase {
|
export enum SupportCase {
|
||||||
|
|
||||||
@ -80,7 +78,7 @@ export enum SupportCase {
|
|||||||
SNAKE_UPPER_CASE,
|
SNAKE_UPPER_CASE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连字符(脊柱式)命名
|
* 中划线(连字符/脊柱式)命名
|
||||||
* Kebab Case / Spinal Case
|
* Kebab Case / Spinal Case
|
||||||
* e.g. foo-bar
|
* e.g. foo-bar
|
||||||
*
|
*
|
||||||
@ -91,7 +89,7 @@ export enum SupportCase {
|
|||||||
KEBAB_CASE,
|
KEBAB_CASE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连字符(脊柱式) + 小驼峰(驼峰)命名
|
* 中划线(连字符/脊柱式) + 小驼峰(驼峰)命名
|
||||||
* Kebab Camel Case
|
* Kebab Camel Case
|
||||||
* e.g. foo-Bar
|
* e.g. foo-Bar
|
||||||
*
|
*
|
||||||
@ -101,7 +99,7 @@ export enum SupportCase {
|
|||||||
KEBAB_CAMEL_CASE,
|
KEBAB_CAMEL_CASE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连字符(脊柱式) + 大驼峰(帕斯卡)命名
|
* 中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名
|
||||||
* Kebab Pascal Case
|
* Kebab Pascal Case
|
||||||
* e.g. Foo-Bar
|
* e.g. Foo-Bar
|
||||||
*
|
*
|
||||||
@ -111,7 +109,7 @@ export enum SupportCase {
|
|||||||
KEBAB_PASCAL_CASE,
|
KEBAB_PASCAL_CASE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连字符(脊柱式) + 全大写命名
|
* 中划线(连字符/脊柱式) + 全大写命名
|
||||||
* Kebab Upper Case
|
* Kebab Upper Case
|
||||||
* e.g. FOO-BAR
|
* e.g. FOO-BAR
|
||||||
*
|
*
|
||||||
@ -234,7 +232,7 @@ const keyword = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接管的字符串转换命令
|
* 接管的变量转换命令
|
||||||
*/
|
*/
|
||||||
export const commands: Array<{ command: string; targetCase: SupportCase }> = [
|
export const commands: Array<{ command: string; targetCase: SupportCase }> = [
|
||||||
{ command: 'variable-conversion.toCamelCase', targetCase: SupportCase.CAMEL_CASE },
|
{ command: 'variable-conversion.toCamelCase', targetCase: SupportCase.CAMEL_CASE },
|
||||||
@ -263,7 +261,7 @@ export const commands: Array<{ command: string; targetCase: SupportCase }> = [
|
|||||||
* 所有支持的命名方式
|
* 所有支持的命名方式
|
||||||
* @since 2024-04-06
|
* @since 2024-04-06
|
||||||
*/
|
*/
|
||||||
export const qickPickSupportCases = [
|
export const quickPickSupportCases = [
|
||||||
{
|
{
|
||||||
type: SupportCase.CAMEL_CASE,
|
type: SupportCase.CAMEL_CASE,
|
||||||
name: '小驼峰(驼峰)命名',
|
name: '小驼峰(驼峰)命名',
|
||||||
@ -302,25 +300,25 @@ export const qickPickSupportCases = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: SupportCase.KEBAB_CASE,
|
type: SupportCase.KEBAB_CASE,
|
||||||
name: '连字符(脊柱式)命名',
|
name: '中划线(连字符/脊柱式)命名',
|
||||||
shortName: '脊柱',
|
shortName: '脊柱',
|
||||||
keyword: [...keyword.kebab, ...keyword.lower],
|
keyword: [...keyword.kebab, ...keyword.lower],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: SupportCase.KEBAB_CAMEL_CASE,
|
type: SupportCase.KEBAB_CAMEL_CASE,
|
||||||
name: '连字符(脊柱式) + 小驼峰(驼峰)命名',
|
name: '中划线(连字符/脊柱式) + 小驼峰(驼峰)命名',
|
||||||
shortName: '脊柱驼峰',
|
shortName: '脊柱驼峰',
|
||||||
keyword: [...keyword.kebab, ...keyword.camel],
|
keyword: [...keyword.kebab, ...keyword.camel],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: SupportCase.KEBAB_PASCAL_CASE,
|
type: SupportCase.KEBAB_PASCAL_CASE,
|
||||||
name: '连字符(脊柱式) + 大驼峰(帕斯卡)命名',
|
name: '中划线(连字符/脊柱式) + 大驼峰(帕斯卡)命名',
|
||||||
shortName: '脊柱帕斯卡',
|
shortName: '脊柱帕斯卡',
|
||||||
keyword: [...keyword.kebab, ...keyword.pascal],
|
keyword: [...keyword.kebab, ...keyword.pascal],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: SupportCase.KEBAB_UPPER_CASE,
|
type: SupportCase.KEBAB_UPPER_CASE,
|
||||||
name: '连字符(脊柱式) + 全大写命名',
|
name: '中划线(连字符/脊柱式) + 全大写命名',
|
||||||
shortName: '脊柱大写',
|
shortName: '脊柱大写',
|
||||||
keyword: [...keyword.kebab, ...keyword.upper],
|
keyword: [...keyword.kebab, ...keyword.upper],
|
||||||
},
|
},
|
||||||
@ -361,3 +359,31 @@ export const qickPickSupportCases = [
|
|||||||
keyword: keyword.upper,
|
keyword: keyword.upper,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过快捷键循环转换的顺序
|
||||||
|
* @since 2024-04-08
|
||||||
|
*/
|
||||||
|
export const cyclicConvertCaseOrder = [
|
||||||
|
SupportCase.CAMEL_CASE,
|
||||||
|
SupportCase.PASCAL_CASE,
|
||||||
|
|
||||||
|
SupportCase.SNAKE_CASE,
|
||||||
|
SupportCase.KEBAB_CASE,
|
||||||
|
SupportCase.SPACE_CASE,
|
||||||
|
|
||||||
|
SupportCase.SNAKE_UPPER_CASE,
|
||||||
|
SupportCase.KEBAB_UPPER_CASE,
|
||||||
|
SupportCase.SPACE_UPPER_CASE,
|
||||||
|
|
||||||
|
SupportCase.SNAKE_PASCAL_CASE,
|
||||||
|
SupportCase.KEBAB_PASCAL_CASE,
|
||||||
|
SupportCase.SPACE_PASCAL_CASE,
|
||||||
|
|
||||||
|
SupportCase.SNAKE_CAMEL_CASE,
|
||||||
|
SupportCase.KEBAB_CAMEL_CASE,
|
||||||
|
SupportCase.SPACE_CAMEL_CASE,
|
||||||
|
|
||||||
|
SupportCase.LOWER_CASE,
|
||||||
|
SupportCase.UPPER_CASE,
|
||||||
|
];
|
||||||
|
Loading…
Reference in New Issue
Block a user