实现快捷键循环切换 Windows / Unix 风格
This commit is contained in:
parent
6fce88f88a
commit
2a1cf5488d
@ -1,3 +1,4 @@
|
|||||||
|
import { EOL } from "../../types/EOLType";
|
||||||
import { SupportPathFormat } from "./types/SupportPathFormatType";
|
import { SupportPathFormat } from "./types/SupportPathFormatType";
|
||||||
|
|
||||||
/** / */
|
/** / */
|
||||||
@ -7,7 +8,7 @@ const RIGHT_SLASH = '\\';
|
|||||||
/** \\ */
|
/** \\ */
|
||||||
const DOUBLE_RIGHT_SLASH = '\\\\';
|
const DOUBLE_RIGHT_SLASH = '\\\\';
|
||||||
|
|
||||||
export function pathConversion(targetPathType: SupportPathFormat, input: string): string {
|
export function pathConversion(targetPathType: SupportPathFormat, input: string, eol: EOL): string {
|
||||||
let resultPath;
|
let resultPath;
|
||||||
|
|
||||||
let isSeperator = false;
|
let isSeperator = false;
|
||||||
|
116
src/core/path-convert/cyclic-conversion.ts
Normal file
116
src/core/path-convert/cyclic-conversion.ts
Normal 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 disableFormatList = getUserConfigurations<Array<string>>('disableFormat') || [];
|
||||||
|
|
||||||
|
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 (disableFormatList.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;
|
||||||
|
}
|
||||||
|
}
|
@ -20,4 +20,21 @@ export enum SupportPathFormat {
|
|||||||
* @since 2024-12-07
|
* @since 2024-12-07
|
||||||
*/
|
*/
|
||||||
Unix,
|
Unix,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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' },
|
||||||
|
];
|
||||||
|
@ -15,7 +15,8 @@ import handleEditorReplace from './handler/editor-submenu-handler';
|
|||||||
import { handleQuickPick } from './handler/quick-pick-handler';
|
import { handleQuickPick } from './handler/quick-pick-handler';
|
||||||
import { commands } from './core/variable-convert/types/SupportVariableCaseType';
|
import { commands } from './core/variable-convert/types/SupportVariableCaseType';
|
||||||
import { createStatusBarItem, updateStatusBarItemVisable } from './handler/status-bar-handler';
|
import { createStatusBarItem, updateStatusBarItemVisable } from './handler/status-bar-handler';
|
||||||
import * as CyclicConversion from './core/variable-convert/cyclic-conversion';
|
import * as CyclicConversionVariable from './core/variable-convert/cyclic-conversion';
|
||||||
|
import * as CyclicConversionPath from './core/path-convert/cyclic-conversion';
|
||||||
import { EOL } from './types/EOLType';
|
import { EOL } from './types/EOLType';
|
||||||
import { getUserConfigurations } from './utils/user-configuration';
|
import { getUserConfigurations } from './utils/user-configuration';
|
||||||
|
|
||||||
@ -65,7 +66,9 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
// 循环转换:记录当前选中内容,并且进行转换
|
// 循环转换:记录当前选中内容,并且进行转换
|
||||||
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);
|
CyclicConversionVariable.onUserSelectionUpdated(selections, textList, eol);
|
||||||
|
|
||||||
|
CyclicConversionPath.onUserSelectionUpdated(selections, textList, eol);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建状态栏按钮
|
// 创建状态栏按钮
|
||||||
@ -120,12 +123,12 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
// 注册循环转换 command
|
// 注册循环转换 command
|
||||||
let loopConvertCasePrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => {
|
let loopConvertCasePrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => {
|
||||||
console.log('variable-conversion.cyclicConvertCase.previous', arrowKey);
|
console.log('variable-conversion.cyclicConvertCase.previous', arrowKey);
|
||||||
CyclicConversion.previousOne();
|
CyclicConversionVariable.previousOne();
|
||||||
});
|
});
|
||||||
context.subscriptions.push(loopConvertCasePrevDisposable);
|
context.subscriptions.push(loopConvertCasePrevDisposable);
|
||||||
let loopConvertCaseNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => {
|
let loopConvertCaseNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => {
|
||||||
console.log('variable-conversion.cyclicConvertCase.next', arrowKey);
|
console.log('variable-conversion.cyclicConvertCase.next', arrowKey);
|
||||||
CyclicConversion.nextOne();
|
CyclicConversionVariable.nextOne();
|
||||||
});
|
});
|
||||||
context.subscriptions.push(loopConvertCaseNextDisposable);
|
context.subscriptions.push(loopConvertCaseNextDisposable);
|
||||||
|
|
||||||
@ -142,12 +145,12 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
// 注册循环转换 command
|
// 注册循环转换 command
|
||||||
let loopConvertPathPrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.previous', ({ direction }) => {
|
let loopConvertPathPrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.previous', ({ direction }) => {
|
||||||
console.log('variable-conversion.cyclicConvertPath.previous', direction);
|
console.log('variable-conversion.cyclicConvertPath.previous', direction);
|
||||||
// TODO
|
CyclicConversionPath.previousOne();
|
||||||
});
|
});
|
||||||
context.subscriptions.push(loopConvertPathPrevDisposable);
|
context.subscriptions.push(loopConvertPathPrevDisposable);
|
||||||
let loopConvertPathNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.next', ({ direction }) => {
|
let loopConvertPathNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.next', ({ direction }) => {
|
||||||
console.log('variable-conversion.cyclicConvertPath.next', direction);
|
console.log('variable-conversion.cyclicConvertPath.next', direction);
|
||||||
// TODO
|
CyclicConversionPath.nextOne();
|
||||||
});
|
});
|
||||||
context.subscriptions.push(loopConvertPathNextDisposable);
|
context.subscriptions.push(loopConvertPathNextDisposable);
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ suite('Extension Test: run variable convert 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(SupportVariableCase.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(SupportVariableCase.PASCAL_CASE, input, eol), 'pascal case test failed.');
|
assert.strictEqual(testCase.output.pascalCase, caseConversion(SupportVariableCase.PASCAL_CASE, input, eol), 'pascal case test failed.');
|
||||||
|
|
||||||
@ -113,11 +113,14 @@ suite('Extension Test: run path convert test case', () => {
|
|||||||
// }
|
// }
|
||||||
test(testTitle + ' - ' + testCase.title, () => {
|
test(testTitle + ' - ' + testCase.title, () => {
|
||||||
const inputList = Array.isArray(testCase.input) ? testCase.input : [testCase.input];
|
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) {
|
for (const input of inputList) {
|
||||||
// console.log('input', '->' + input + '<-');
|
// console.log('input', '->' + input + '<-');
|
||||||
// 验证转换
|
// 验证转换
|
||||||
assert.strictEqual(testCase.output.Windows.unEscape, pathConversion(SupportPathFormat.Windows, input), 'Windows path format test failed.');
|
for (const eol of eolList) {
|
||||||
assert.strictEqual(testCase.output.Unix.unEscape, pathConversion(SupportPathFormat.Unix, input), 'Unix path format test failed.');
|
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.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { PathTestCaseGroup } from "./types/PathTestCaseType";
|
import { PathTestCaseGroup } from "./types/PathTestCaseType";
|
||||||
|
|
||||||
|
const LF = '\n';
|
||||||
|
const CRLF = '\r\n';
|
||||||
|
|
||||||
export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
||||||
{
|
{
|
||||||
group: 'Normal Path Format Convert',
|
group: 'Normal Path Format Convert',
|
||||||
@ -9,6 +12,7 @@ export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
|||||||
title: 'Windows 风格',
|
title: 'Windows 风格',
|
||||||
input: // E:\Project\variable-conversion-vscode-extension
|
input: // E:\Project\variable-conversion-vscode-extension
|
||||||
'E:\\Project\\variable-conversion-vscode-extension',
|
'E:\\Project\\variable-conversion-vscode-extension',
|
||||||
|
eol: [LF, CRLF],
|
||||||
output: {
|
output: {
|
||||||
Windows: {
|
Windows: {
|
||||||
unEscape: // E:\Project\variable-conversion-vscode-extension
|
unEscape: // E:\Project\variable-conversion-vscode-extension
|
||||||
@ -28,6 +32,7 @@ export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
|||||||
{
|
{
|
||||||
title: 'Unix 风格',
|
title: 'Unix 风格',
|
||||||
input: '/home/user/file.txt',
|
input: '/home/user/file.txt',
|
||||||
|
eol: [LF, CRLF],
|
||||||
output: {
|
output: {
|
||||||
Windows: {
|
Windows: {
|
||||||
unEscape: // \home\user\file.txt
|
unEscape: // \home\user\file.txt
|
||||||
@ -46,6 +51,7 @@ export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
|||||||
{
|
{
|
||||||
title: 'Windows (Git Bash) 风格',
|
title: 'Windows (Git Bash) 风格',
|
||||||
input: '/c/Users/test/file.txt',
|
input: '/c/Users/test/file.txt',
|
||||||
|
eol: [LF, CRLF],
|
||||||
output: {
|
output: {
|
||||||
Windows: {
|
Windows: {
|
||||||
unEscape: // \c\Users\test/file.txt
|
unEscape: // \c\Users\test/file.txt
|
||||||
@ -81,6 +87,7 @@ export const pathConvertTestGroups: Array<PathTestCaseGroup> = [
|
|||||||
// title: '',
|
// title: '',
|
||||||
// input: //
|
// input: //
|
||||||
// '',
|
// '',
|
||||||
|
// eol: [LF, CRLF],
|
||||||
// output: {
|
// output: {
|
||||||
// Windows: {
|
// Windows: {
|
||||||
// unEscape: //
|
// unEscape: //
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import exp from "constants";
|
import { EOL } from "../../../types/EOLType";
|
||||||
|
|
||||||
export type PathTestCaseGroup = {
|
export type PathTestCaseGroup = {
|
||||||
group: string
|
group: string
|
||||||
@ -14,6 +14,7 @@ export type PathTestOutputResult = {
|
|||||||
export type PathTestCase = {
|
export type PathTestCase = {
|
||||||
title: string
|
title: string
|
||||||
input: string | Array<string>
|
input: string | Array<string>
|
||||||
|
eol: EOL | Array<EOL>
|
||||||
output: {
|
output: {
|
||||||
Windows: PathTestOutputResult
|
Windows: PathTestOutputResult
|
||||||
Unix: PathTestOutputResult
|
Unix: PathTestOutputResult
|
||||||
|
Loading…
Reference in New Issue
Block a user