From 2a1cf5488d6eff0a018c1ec9e3d7325fbc3f3d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=8D=9A=E5=87=AF?= Date: Sat, 14 Dec 2024 22:12:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BF=AB=E6=8D=B7=E9=94=AE?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E5=88=87=E6=8D=A2=20Windows=20/=20Unix=20?= =?UTF-8?q?=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/path-convert/conversion.ts | 3 +- src/core/path-convert/cyclic-conversion.ts | 116 ++++++++++++++++++ .../types/SupportPathFormatType.ts | 19 ++- src/extension.ts | 15 ++- src/test/extension.test.ts | 9 +- src/test/test-case/path-convert-test-case.ts | 7 ++ src/test/test-case/types/PathTestCaseType.ts | 3 +- 7 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 src/core/path-convert/cyclic-conversion.ts diff --git a/src/core/path-convert/conversion.ts b/src/core/path-convert/conversion.ts index b5b6c79..4c479dc 100644 --- a/src/core/path-convert/conversion.ts +++ b/src/core/path-convert/conversion.ts @@ -1,3 +1,4 @@ +import { EOL } from "../../types/EOLType"; import { SupportPathFormat } from "./types/SupportPathFormatType"; /** / */ @@ -7,7 +8,7 @@ const 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 isSeperator = false; diff --git a/src/core/path-convert/cyclic-conversion.ts b/src/core/path-convert/cyclic-conversion.ts new file mode 100644 index 0000000..c5925aa --- /dev/null +++ b/src/core/path-convert/cyclic-conversion.ts @@ -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 + 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>('disableFormat') || []; + + const textList = userSelection.currentSelectionsText; + // vscode.window.showInformationMessage('lazyConvert' + textList.join('\n')); + const eol = userSelection.currentEol; + const conversionsTarget: Array = [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; + } +} \ No newline at end of file diff --git a/src/core/path-convert/types/SupportPathFormatType.ts b/src/core/path-convert/types/SupportPathFormatType.ts index 60297cf..6642234 100644 --- a/src/core/path-convert/types/SupportPathFormatType.ts +++ b/src/core/path-convert/types/SupportPathFormatType.ts @@ -20,4 +20,21 @@ export enum SupportPathFormat { * @since 2024-12-07 */ Unix, -}; \ No newline at end of file +}; + +/** + * @since 2024-12-14 + */ +export interface CyclicConvertPathOrderItem { + type: SupportPathFormat, + settingsKey: string, +} + +/** + * 通过快捷键循环转换的顺序 + * @since 2024-12-14 + */ +export const cyclicConvertPathOrder: Array = [ + { type: SupportPathFormat.Windows, settingsKey: 'windows' }, + { type: SupportPathFormat.Unix, settingsKey: 'unix' }, +]; diff --git a/src/extension.ts b/src/extension.ts index 957709c..8b47527 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -15,7 +15,8 @@ import handleEditorReplace from './handler/editor-submenu-handler'; import { handleQuickPick } from './handler/quick-pick-handler'; import { commands } from './core/variable-convert/types/SupportVariableCaseType'; 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 { 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'; - 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 let loopConvertCasePrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.previous', ({ arrowKey }) => { console.log('variable-conversion.cyclicConvertCase.previous', arrowKey); - CyclicConversion.previousOne(); + CyclicConversionVariable.previousOne(); }); context.subscriptions.push(loopConvertCasePrevDisposable); let loopConvertCaseNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertCase.next', ({ arrowKey }) => { console.log('variable-conversion.cyclicConvertCase.next', arrowKey); - CyclicConversion.nextOne(); + CyclicConversionVariable.nextOne(); }); context.subscriptions.push(loopConvertCaseNextDisposable); @@ -142,12 +145,12 @@ export function activate(context: vscode.ExtensionContext) { // 注册循环转换 command let loopConvertPathPrevDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.previous', ({ direction }) => { console.log('variable-conversion.cyclicConvertPath.previous', direction); - // TODO + CyclicConversionPath.previousOne(); }); context.subscriptions.push(loopConvertPathPrevDisposable); let loopConvertPathNextDisposable = vscode.commands.registerCommand('variable-conversion.cyclicConvertPath.next', ({ direction }) => { console.log('variable-conversion.cyclicConvertPath.next', direction); - // TODO + CyclicConversionPath.nextOne(); }); context.subscriptions.push(loopConvertPathNextDisposable); } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 1e2fc19..cdae582 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -57,7 +57,7 @@ suite('Extension Test: run variable convert test case', () => { 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.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, () => { 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 + '<-'); // 验证转换 - assert.strictEqual(testCase.output.Windows.unEscape, pathConversion(SupportPathFormat.Windows, input), 'Windows path format test failed.'); - assert.strictEqual(testCase.output.Unix.unEscape, pathConversion(SupportPathFormat.Unix, input), 'Unix path format test failed.'); + 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.'); + } } }); } diff --git a/src/test/test-case/path-convert-test-case.ts b/src/test/test-case/path-convert-test-case.ts index 3a96e20..0287382 100644 --- a/src/test/test-case/path-convert-test-case.ts +++ b/src/test/test-case/path-convert-test-case.ts @@ -1,5 +1,8 @@ import { PathTestCaseGroup } from "./types/PathTestCaseType"; +const LF = '\n'; +const CRLF = '\r\n'; + export const pathConvertTestGroups: Array = [ { group: 'Normal Path Format Convert', @@ -9,6 +12,7 @@ export const pathConvertTestGroups: Array = [ 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 @@ -28,6 +32,7 @@ export const pathConvertTestGroups: Array = [ { title: 'Unix 风格', input: '/home/user/file.txt', + eol: [LF, CRLF], output: { Windows: { unEscape: // \home\user\file.txt @@ -46,6 +51,7 @@ export const pathConvertTestGroups: Array = [ { title: 'Windows (Git Bash) 风格', input: '/c/Users/test/file.txt', + eol: [LF, CRLF], output: { Windows: { unEscape: // \c\Users\test/file.txt @@ -81,6 +87,7 @@ export const pathConvertTestGroups: Array = [ // title: '', // input: // // '', + // eol: [LF, CRLF], // output: { // Windows: { // unEscape: // diff --git a/src/test/test-case/types/PathTestCaseType.ts b/src/test/test-case/types/PathTestCaseType.ts index 1b39ed0..f3e15fd 100644 --- a/src/test/test-case/types/PathTestCaseType.ts +++ b/src/test/test-case/types/PathTestCaseType.ts @@ -1,4 +1,4 @@ -import exp from "constants"; +import { EOL } from "../../../types/EOLType"; export type PathTestCaseGroup = { group: string @@ -14,6 +14,7 @@ export type PathTestOutputResult = { export type PathTestCase = { title: string input: string | Array + eol: EOL | Array output: { Windows: PathTestOutputResult Unix: PathTestOutputResult